redis---第四部分 独立功能的实现

1 发布与订阅

2 事务

3 Lua脚本

4 排序

5 二进制数组

6 慢查询日志

7 监视器


1 发布与订阅

发布与订阅

 Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成

## 频道的订阅与退订

Redis将所有频道的订阅关系都保存在服务器状态的pubsub_channels字典里面,资格字典的键是某个被订阅的频道,而键的值则是一个链表,链表里面记录了所有订阅这个频道的客户端

## 模式的订阅与退订

1 频道的订阅与退订

 

 

订阅频道

退订频道

2 模式的订阅与退订

订阅模式

退订模式

3 发送消息

将消息发送给频道订阅者

将消息发送给模式订阅者

4 查看订阅信息

PUBSUB CHANNELS

PUBSUB NUMSUB

PUBSUB NUMPAT

 

订阅模式和频道到底有什么区别

 

2 事务

Redis通过MULTI、EXEC、WATCH等命令来实现事务功能。

一个事务从开始到结束通常会经历以下三个阶段:

1. 事务开始
2. 命令入队
3. 事务执行

1 事务的实现

1事务开始

MULTI

2 命令入队

3 事务队列

4 执行事务

EXEC

2 WATCH命令的实现

## WATCH命令的实现

WATCH命令是一个乐观锁,它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复

当服务器接收到一个客户端发来的EXEC命令时,服务器会根据这个客户端是否打开了`REDIS_DIRTY_CAS`标识来决定是否执行事务。

1 使用WATCH命令监视数据库键

2 监视机制的触发

3 判断事务是否安全

4 一个完整的WATCH事务执行过程

3 事务的ACID性质

原子性

一致性

隔离性

耐久性

3 Lua脚本

1 创建并修改Lua环境

   创建Lua环境

   载入函数库

   创建redis 全局表格

   使用Redis自制的随机函数来替换Lua原有的随机函数

   创建排序辅助函数

   创建redis.pcall 函数的错误报告辅助函数

   保护Lua的全局环境

   将Lua环境保存到服务器状态的lua属性里面

2 Lua环境协作组件

 伪客户端

   lua_scripts字典

3 EVAL命令的实现

定义脚本数据

将脚本保存到lua_scripts字典

执行脚本函数

4 EVALSHA命令的实现

5 脚本管理命令的实现

  SCRIPT FLUSH

  SCRIPT EXISTS

  SCRIPT LOAD

  SCRIPT KILL

6 脚本复制

  复制EVAL命令、SCRIPT FLUSH命令和SCRIPT LOAD命令

       EVAL    SCRIPT FLUSH     SCRIPT LOAD

  复制EVALSHA命令

 

4 排序

1 SORT<key> 命令的实现

2 ALPHA选项的实现

3 ASC选项和DESC选项的实现

4 BY选项的实现

5 带有ALPHA选项的BY选项的实现

6 LIMIT选项的实现

7 GET选项的实现

8 STORE选项的实现

9 多个选项的执行顺序

# 排序

Redis的`SORT`命令可以对列表键、集合键或者有序集合键的值进行排序

`SORT`命令的最简单执行形式为:`SORT <key>`

```c
// 用于保存被排序值及其权重的结构
typedef struct _redisSortObject {

    // 被排序键的值
    robj *obj;

    // 权重
    union {

        // 排序数字值时使用
        double score;

        // 排序字符串时使用
        robj *cmpobj;

    } u;

} redisSortObject;
```

 

5 二进制数组

1 位数组的表示

2 GETBIT命令的实现

3 SETBIT命令的实现

4 BITCOUNT命令的实现

  二进制位统计算法 遍历算法

  二进制位统计算法 查表算法

  二进制位统计算法 variable-precision SWAR算法

  二进制位统计算法 Redis算法

5 BITOP 命令的实现

# 二进制位数组

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

## 位数组的表示

Redis使用字符串对象来表示位数组,因为字符串对象使用的SDS数据结构是二进制安全的,所以程序可以直接使用SDS结构来保存位数组,并使用SDS结构的操作函数来处理位数组。

## BITCOUNT命令的实现

### 二进制位统计算法(1):遍历算法

遍历算法虽然实现起来简单,但效率非常低,因为这个算法在每次循环中只能检查一个二进制位的值是否为1,所以检查操作执行的次数将与位数组包含的二进制位的数量成正比

### 二进制位统计算法(2):查表算法

查表法是一种比遍历算法更好的统计方法,但受限于查表法带来的内存压力,以及缓存不命中可能带来的影响,我们只能考虑创建键长为8位或者键长为16位的表,而这两种表带来的效率提升,对于处理非常长的位数组来说任然远远不够。

### 二进制位统计算法(3):variable-precision SWAR算法

### 二进制位统计算法(4):Redis的实现

`BITCOUNT`命令的实现用到了查表和`variable precision SWAR`两种算法:

如果未处理的二进制位的数量小于128位,那么程序使用查表算法来计算二进制位的汉明重量

6 慢查询日志

慢查询日志

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

1 慢查询记录的保存

 

2 慢查询日志的阅览和删除

3 添加新日志

7 监视器

 

1成为监视器

2 向监视器发送命令信息