1.前言

  本节记录一下redis的一些功能上的实现,包括发布订阅、事务、Lua脚本、排序、二进制位数组、慢查询日志和监视器。

2.发布订阅

  上一章介绍sentinel的时候说到了sentinel会订阅主从服务器的hello频道,每个sentinel通过往这个频道中传递各自的状态,让其它sentinel发现自己并更新相关状态。

  Redis的发布与订阅功能是由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成。一个客户端订阅某个频道,一旦有消息推送到该频道,其就会知道相关消息。具体操作如下:

    SUBSCRIBE “xxx"    PUBLISH "xxx" "yyy" 订阅xxx频道的客户端就会接收到yyy消息。

  还可以使用匹配模式的方式订阅多个频道:

    PSUBSCRIBE ”new.[ie]t"   PUBLISH “new.it"  PUBLISH "new.et"

  实现原理:

    redisServer中有一个字段dict  *pubsub_channels保存了所有频道和订阅关系。键是频道,值是客户端构成的链表。

    有一个订阅者就会添加到这个字段中。

    退订频道时,从这里面删除。

  UNSUBSCRIBE

  模式的订阅与退订:

    redisServer中有一个字段list *pubsub_patterns保存了所有模式订阅关系.

    PSUBSCRIBE的时候就会添加到这里面。

    退订就是使用PUNSUBSCRIBE方法。

  发送消息:

    PUBLISH方法会将发送的消息,遍历pubsub_channels和pubsub_patterns找到对应的客户端发送给他们。

  查看订阅信息:

    PUBSUB命令是redis2.8新增加的命令之一,可以通过这个查看频道或者模式的相关信息。

    PUBSUB CHANNELS  或者PUBSUB CHANNELS “news.[is]*"

    PUBSUB NUMSUB查看输入的频道的订阅者数量

    PUBSUB NUMPAT 查看当前订阅模式有多少个

3.事务

  redis通过MULTI、EXEC和WATCH等命令来实现事务功能。提供了一种将多个命令请求打包,然后一次性、按顺序执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令执行完毕。

  例如: MULTI

     SET "name" "xxx"

     GET “name"

     SET "author" "xx"

     EXEC

  事务的实现:

    MULTI意味着开始,客户端切换到事务状态,修改flags。

    EXEC、DISCARD、WATCH、MULTI四个命令会立刻执行。其他命令进入事务队列,返回QUEUED回复。事务队列在multiState mstate事务状态中。

    接收到EXEC命令的时候,服务器会遍历事务队列,执行所有的结果并返回。

  WATCH:

    watch命令是一个乐观锁,可以在执行EXEC命令之前监视任何数量的数据库键。并在执行EXEC命令时,检查被监视的键是否被修改,如果是就会拒绝执行事务。

      WATCH "name"

      MULTI

      SET "name" "peter"

      EXEC

    redisDb中有一个dict *watched_keys,键是具体的键,值是监视这个键的客户端链表。执行命令前先判断这个键有没有被监视,被监视了修改所有客户端的标志成REDIS_DIRTY_CAS。意味着事务安全性被破坏。EXEC时候会检查这个标志,就能判断是否可以提交。

  事务的ACID性质:

    原子性,redis的事务要不全部执行要不都不执行。

    一致性,redis入队时会检查命令是否正确,执行过程中错误的命令不会对数据库进行修改,停机状态没持久化就没了,有持久化能够恢复。

    隔离性,redis没有并发,所以有隔离性

    耐久性,redis没有提供额外的持久化,都是通过redis的持久化模式决定的。加个SAVE可以有,但是效率太低。

4. Lua脚本

  略。

5.排序

  SORT可以对列表键,集合键或者有序集合键的值进行排序,即list,set,zset。

  实现原理:

    创建了一个与排序元素数量相同的数组,结构是redisSortObject,每个都对应一个元素。将元素进行排序,从小到大。最后遍历数组,返回排序后的元素。

    默认只能进行数字类型比较大小,字符串用字符串的比较方式要命令添加ALPHA选项。

  SORT可以配合ASC选项和DESC选项来实现。影响的就是结果的排序倒序还是顺序,SORT name ASC

  BY选项的实现:

    by选项可以实现某些字符串键或者hash键的某些域作为元素的权重进行排序。

    比如:SADD fruits "apple" "banana" "cherry"

       字典里面有MSET apple-price 8 banana-price 5.5 cherry-price 7

      对fruits按照价格排序 SORT fruits by *-price

      就会返回 banana cherry apple

    By选项默认保存的是数字值,如果权重保存的是字符串,要同时使用ALPHA选项

      mset apple-id  "xxx" banana-id "yyy" cherry-id "zzz"

      SORT fruits by *-id ALPHA

  LIMIT选项:

    返回指定范围的元素 SORT name LIMIT skip size

    比如SORT fruits ALPHA 0 4

  GET选项:

    前面的都是返回排序的键的结果,如果我们想要返回关联的内容就要使用GET,比如对student进行排序,返回学生的全名。

    SADD students jack peter tom

    MSET peter-name "Peter White" jack-name "Jack Snow" tom-name "Tom Smith"

    SORT students ALPHA GET *-name

    就可以拿到学生排序后的相关学生姓名了。

  STORE选项:

    SORT只返回排序结果,通过STORE选项可以保存排序结果,以便下次使用。

    SORT students ALPHA STORE sorted_students

    下次取sorted_students键即可。

  多个选项的执行顺序:

    SORT <key> ALPHA DESC BY <by-pattern> LIMIT <offset> <count> GET <get-pattern> STORE <store_key>

    执行顺序是:排序,限制长度,获取外部键,保存排序结果,向客户端返回结果。

    除了GET选项,改变顺序不会影响执行顺序。

6.二进制位数组

  redis提供了SETBIT、GETBIT、BITCOUNT、BITOP四个命令用于处理二进制位数组。

    SETBIT bit 0 1 # 0000 0001

    SETBIT bit 3 1 # 0000 0101

    GETBIT bit 3  得到的就是1

    BITCOUNT bit 得到的就是2

    BITOP可以进行与、或、异或运算,按位取反

    BITOP AND and-result x y z

    BITOP OR or-result x y z

    BITOP XOR xor-result x y z

    BITOP NOT not-value value

  redis用sds结构保存位数组。len表示保存了几个1字节长的位数组。

  GETBIT命令的实现:

    GETBIT <bitarray> <offset>

    计算下标 offset / 8 确定在哪个位数组上,取出这个1字节长的byte

    计算offset mod 8 + 1,计算偏移量,确定这个byte的第几个二进制位

    返回这个值

  SETBIT命令的实现:

    SETBIT <bitarray> <offset> <value>

    计算len offset / 8 + 1 ,确定需要多少个字节

    检查bitarray当前的len,不够扩容到计算出的长度,扩容部分全部填0

    byte = offset / 8 确定byte

    bit = offset mod 8 + 1 确定二进制位

    设置byte的bit位的值

    返回oldValue

  注意对于单个byte是使用逆序的方式保存内容的。

  BITCOUNT命令的实现:

    1.最直接的方法,遍历二进制位计数。假设数组长度为100MB,遍历要执行100 * 1024 * 1024 * 8,10来亿次计算,这个就可怕了。

    2.查表法:创建一个表记录每个值的1的个数,比如8位字节的查表,8位字节可以组成0~255范围,制作一张表0的时候对应的1的个数就是0,1的时候对应的个数就是1

        0000 0000      0

        0000 0001      1

        0000 0010    1

        ……

      这样就可以不需要检测各个位,直接获得相关的1的个数了。表越大,计算次数就越少。但是这个方法有两个问题,一是用空间换时间,表越大耗费的空间越多。二是CPU缓存命中降低,CPU缓存能保存的表比例越低,查表无法命中,缓存的换入换出频繁,影响实际效率。

    3.二进制统计算法:variable-precision SWAR算法

    计算汉明距离:

      i = (i & 0x55555555) + ((i >> 1) & 0x55555555);

      i = (i & 0x33333333) + ((i >> 1) & 0x33333333);

      i = (i & 0x0F0F0F0F) + ((i >> 1) & 0x0F0F0F0F);

      i = (i * (0x01010101) >> 24);

    第一步按两个二进制位进行一组,每组的十进制就是该组的汉明重量

    第二步按四个二进制位进行分组,每组的十进制就是该组的汉明重量

    第三步按八个二进制位进行分组,每组的十进制就是该组的汉明重量

    最后计算bitarray的汉明重量,并记录在二进制位的最高八位,右移24位得到汉明距离

    这个方法每次可以计算32个二进制位的汉明重量,比遍历快32倍,比键长8位的查表法快4倍。

    4.二进制统计算法:redis实现

      BITCOUNT命令使用了查表法和variable-precisionSWAR两种算法。

      查表法使用8位的表,记录0000 0000到1111 1111的汉明重量

      SWAR算法,每次循环载入128个二进制位,调用4次32位的SWAR算法计算这128个位的汉明重量。

    BITCOUNT会根据未处理的二进制位数量来决定使用哪种算法:

      未处理大于等于128位,使用SWAR算法。

      小于128位,使用查表法。

    100MB只需要执行625万次循环,比遍历8亿次快太多。

  BITOP命令的实现:

    创建一个空白数组位,然后对做操作的数组按字节进行与或操作,保存在这个空白数组中,最后返回。

7.慢查询日志

  慢查询日志用于记录执行时间超过给定时长的命令请求,用户可以通过这个功能产生的日志来监视和优化查询速度。

    slowlog-log-slower-than 超过多少微妙保存记录

    slowlog-max-len    最多保存多少条慢查询日志,新的会让旧的被删除

  可以通过CONFIG SET命令设置这两个参数,如CONFIG SET slowlog-max-len 5

  SLOWLOG GET获取保存的慢查询日志:第一个是日志唯一标识,第二个是执行时的unix时间戳,第三个是执行耗时微妙,最后是命令及参数

  SLOWLOG RESET重置慢查询日志

8.监视器

  执行MONITOR命令,客户端就会变成一个监视器。实时打印出服务器当前处理的命令请求的相关信息。

Redis笔记(4)独立功能的实现的更多相关文章

  1. Redis(四):独立功能的实现

    发布与订阅 Redis 的发布与订阅功能有PUBLISH命令,SUBSCRIBE命令,PSUBSCRIBE命令,PUBSUB命令等组成. 客户端可以通过SUBSCRIBE命令订阅一个或多个频道,当其它 ...

  2. Redis 笔记 01:入门篇

    Redis 笔记 01:入门篇 ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ...

  3. Redis笔记(3)多数据库实现

    1.前言 本章介绍redis的三种多服务实现方式,尽可能简单明了总结一下. 2.复制 复制也可以称为主从模式.假设有两个redis服务,一个在127.0.0.1:6379,一个在127.0.0.1:1 ...

  4. Redis笔记搬迁

      Redis原理 从不同的角度来详细介绍redis 存储方式 数据结构 Redis的过期策略 数据淘汰策略 高可用 主从复制 分布式缓存 哨兵 缓存异常 缓存穿透 缓存雪崩 缓存与数据库数据一致性 ...

  5. redis笔记之一

    NoSQL简介 全称是Not Only SQL,泛指菲关系型数据库,它是通过键值对存储数据并且将数据存储在内存中.而像mysql,sql server这些通过关系表存数据的就叫关系型数据库 为什么需要 ...

  6. Redis Geo: Redis新增位置查询功能

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/144.html 移动互联网增进了人与人之间的联系,其中基于位置信息的服务( ...

  7. 通过Keepalived实现Redis Failover自动故障切换功能

    通过Keepalived实现Redis Failover自动故障切换功能[实践分享] 参考资料: http://patrick-tang.blogspot.com/2012/06/redis-keep ...

  8. 利用redis分布式锁的功能来实现定时器的分布式

    文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...

  9. 转:Redis Geo: Redis新增位置查询功能

    原文来自于:http://www.infoq.com/cn/news/2015/07/redis-geo 移动互联网增进了人与人之间的联系,其中基于位置信息的服务(Location Based Ser ...

随机推荐

  1. C#创建、设置和安装Windows服务

    文章大部分内容转自:http://www.cnblogs.com/greatandforever/archive/2008/10/14/1310504.html:和:http://www.cnblog ...

  2. js,javascript,打印对象,object

    function writeObj(obj){ var description = ""; for(var i in obj){ var property=obj[i]; desc ...

  3. 常见笔记本进入bios方法

    联想 y510p ->F2 ThinkPad E431 -> Fn + F1

  4. 空指针、NULL指针、零指针

    1. 空指针.NULL指针.零指针 1.1 什么是空指针常量 0.0L.'\0'.3 - 3.0 * 17 (它们都是“integer constant expression”)以及 (void*)0 ...

  5. 批处理FINDSTR正则表达式用法实例分析

    1.findstr . 2.txt 或 Findstr "." 2.txt 从文件2.txt中查找任意字符,不包括空字符或空行 2.findstr .* 2.txt 或 finds ...

  6. 合理提升WEB前端性能

    前端的优化包括四个部分:HTML结构优化.CSS样式优化.JS行为优化.服务器的优化.合理的前端优化不仅能够提升网站加载速度,而且能够更好的提升用户体验和团队开发效率.所以前端性能优化的重要性是不言而 ...

  7. 阿里云 oss实时日志查询

    实时日志查询 更新时间:2019-01-29 10:31:49 编辑 · 本页目录 开启实时日志查询 查询实时日志 参考文档 用户在访问 OSS 的过程中,会产生大量的访问日志.实时日志查询功能将 O ...

  8. CentOS 6 安装Redmine

    Redmine是一个灵活的项目管理web应用,采用Ruby on Rails框架开发.Redmine是典型的web 2.0网站,项目管理系统的后起之秀.Redmine支持多项目,灵活的角色权限管理,灵 ...

  9. 【python3+request】python3+requests接口自动化测试框架实例详解教程

    转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...

  10. java基础-day10

    第10天 IO 今日内容介绍 u IO流概述及FileWriter类使用 u FileReader类使用 u 缓冲流介绍和使用 u IO流相关案例 第1章   IO流概述及FileWriter类使用 ...