第四部分 独立功能的实现
Redis设计与实现简读笔记链接
第一章_数据结构与对象
第二章_单机数据库的实现
第三章__多机数据库的实现
第四章_独立功能的实现
发布订阅
两种类型的订阅
- 订阅频道
- 订阅模式
SUBSCRIBE "news.it" //订阅频道
SUBSCRIBE "news.[ie]t" //订阅模式
PUBLISH "news.it" "hello" //发布消息
频道订阅的数据结构
#使用字典保存所有频道的订阅信息
struct redisServer{
//保存所有频道的订阅信息
dict *pubsub_channels;
}
模式订阅的数据结构
#使用链表保存所有模式的订阅信息
struct redisServer{
//保存所有模式的订阅信息
list *pubsub_patterns;
}
struct pubsubPattern{
//订阅模式的客户
redisClient *client;
//被订阅的模式
robj *pattern;
}pubsubPattern;
频道和模式的订阅和退订过程
无非就是在数据结构上进行增加,删除节点
发送消息
- 将消息发送给频道订阅者
- 在频道字典表中找出对应的频道
- 遍历链表,将消息发送给所有的订阅者
- 将消息发送给模式订阅者
- 遍历模式订阅链表
- 如果频道和模式匹配,则将消息发送给订阅该模式的客户端
几个常用的命令
-
PUBSUB CHANNELS [pattern]
-
用于返回服务器当前被订阅的频道
若给定pattern参数, 则还需从被订阅频道列表中过滤 与pattern匹配 的频道
-
-
PUBSUB NUMSUB [channel_1,channel_2....]
- 返回给定频道的订阅者数量
-
PUBSUB NUMPAT
- 返回服务器当前被订阅模式的数量
回顾
- 服务器状态在pubsub_channels字典保存了所有频道的订阅信息: SUBSCRIBE命令负责将客户端和被订阅的频道关联到字典中,而UNSUBSCRIBE命令则负责解除客户端和被退订频道的关联
- 服务器状态在pubsub_patterns链表保存了所有频道的订阅信息: PSUBSCRIBE命令负责将客户端和被订阅的模式关联到这个链表中,而PUNSUBSCRIBE命令则负责解除客户端和被退订模式的关联
- PUBLISH命令通过访问pubsub_channels字典来向频道的所有订阅者发送消息,而通过pubsub_patterns链表来向所有匹配频道模式的订阅者发送消息
- PUBSUB命令的几个常用命令都是通过读取频道的字典和模式的链表信息来实现的.
事务
事务的实现
事务从开始到结束所经历的几个阶段
- 事务开始
- 事务入队
- 事务执行
事务开始
MULTI
def MULTI();
#打开事务标志
client.flags |= REDIS_MULTI
#返回OK回复
事务入队
表示事务状态的数据结构
typedef struct redisClient{
//事务状态
multiState mstate ;
}
typedef struct multiState{
//事务队列,FIFO顺序
multiCmd *commands;
// 已入队命令计数
int count
}multiState;
typedef struct multiCmd{ //记录命令相关信息
//命令参数
robj **argv
//参数数量
int argc;
//命令指针
struct redisCommand *cmd
}multiCmd;
结构图
事务执行
EXEC
执行事务的伪代码
def execute_transaction():
# 创建空白的回复队列
reply_queue = []
# 取出事务队列里的所有命令、参数和参数数量
for cmd, argv, argc in client.transaction_queue:
# 执行命令,并取得命令的返回值
reply = execute_redis_command(cmd, argv, argc)
# 将返回值追加到回复队列末尾
reply_queue.append(reply)
# 清除客户端的事务状态
clear_transaction_state(client)
# 清空事务队列
clear_transaction_queue(client)
# 将事务的执行结果返回给客户端
send_reply_to_client(client, reply_queue)
watch命令的实现
WATCH命令是一个乐观锁
, 它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话 , 服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复
案例
WATCH命令的数据结构
typedef struct redisDB{
//正在被WATCH命令监视的键
dict *watched_keys; //键为被监视的数据库键, 值为监视该键的客户端链表
}
WATCH机制的触发
当数据库执行修改命令之后,都会调用 touchWatchKey函数对 watches_keys字典进行检查, 检查是否有客户端正在监视刚刚被命令修改过的数据库键, 如果有的话,那么touchWatchKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS
标志打开, 表示该客户端的事务安全性被破坏了.
判断事务是否安全
当服务端收到一个客户端发来的EXEC命令时,服务器会根据这个客户端是否打开了REDIS_DIRTY_CAS标志来决定是否执行事务
回顾
- 事务提供了一种将多个命令打包,然后一次性,有序地执行的机制
- 多个命令会被入队到事务队列中,然后按先进先出的顺序执行
- 事务在执行过程中不会被中断,当事务队列的所有命令都被执行完毕之后,事务才会结束
- 带有WATCH命令的事务会将客户端和被监视的键在数据库的watched_keys字典中进行关联,当键被修改时,程序会将所有监视被修改键的客户端的REDIS_DIRTY_CAS标志打开