引言
Redis是一款基于内存的键值对数据库,提供了多种数据结构存储数据,存取数据的速度还非常快,除了这些优点它还提供了其他特色功能,比如:管道、lua脚本、发布订阅模型
本篇文章主要描述发布订阅模型,将围绕发布订阅深入浅出的描述发布订阅的使用和数据结构实现原理
发布订阅
发布订阅是一种消息通信模式
发送者(pub)发送消息到频道(channel),订阅者(sub)接收频道的消息
其中发送者、订阅者都是客户端,频道维护在服务端
Redis提供订阅频道、模式两种方式,模式可以理解为匹配正则的频道 (比如 new.it 匹配 new.*模式)
使用命令
subscribe channel...
订阅一个或多个频道
unsubscribe channel...
退订一个或多个频道
psubscribe pattern...
订阅一个或多个符合模式的频道 (比如 new.it 符合new.*模式)
publish channel message
将消息发送到指定频道
pubsub subcommand argument...
查看订阅与发布系统状态
punsubscribe pattern...
退订所有给定模式的频道
使用
#testchannel为频道 hello!caicai为消息 #客户端A发送消息 返回0 表示0个客户端接收 此时还没订阅频道 127.0.0.1:6379> publish testchannel hello!caicai (integer) 0 #客户端B订阅testchannel频道 127.0.0.1:6379> subscribe testchannel Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "testchannel" 3) (integer) 1 #客户端A发送消息 返回1 说明1个客户端接收到 127.0.0.1:6379> publish testchannel hello!caicai (integer) 1 #客户端B收到消息 1) "message" 2) "testchannel" 3) "hello!caicai" #客户端C使用模式进行订阅 订阅符合test*模式的频道(*为通配) testchannel符合test* 127.0.0.1:6379> psubscribe test* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "test*" 3) (integer) 1 #客户端A发送消息 返回2 说明2个客户端接收到 127.0.0.1:6379> publish testchannel hello!caicai2 (integer) 2 #客户端B显示 1) "message" 2) "testchannel" 3) "hello!caicai2" #客户端C显示 1) "pmessage" 2) "test*" 3) "testchannel" 4) "hello!caicai2"
原理
subscribe channel
订阅频道维护字典,K为频道,V为链表,节点为订阅频道的客户端;客户端订阅或退订频道则是在字典中添加/删除
psubscribe pattern
订阅模式维护链表,节点为模式名与客户端;客户端订阅或退订模式频道则是在链表上遍历添加/删除
publish
发送消息时,先找到字典中的K频道遍历链表发送消息,再去模式中的链表上遍历频道是否与节点上的模式名匹配,匹配则发送消息给对应客户端
pubsub
查看订阅信息则是通过字典和链表获取到信息
pubsub channels (pattern)
则是找到字典中的频道返回链表长度表示这个频道的订阅数量,如果携带了pattern则返回满足匹配的频道pubsub numsub channels
返回字典中频道对应的链表长度pubsub numpat pattern
模式数量,返回模式链表长度
通过发布订阅模型能够实现订阅、通知系统,哨兵模式中也使用发布订阅模式,哨兵订阅主节点,主节点收到某个哨兵命令后发布返回信息,各个哨兵收到消息后能够感知其他哨兵的存在
总结
本文围绕Redis的发布订阅模型,深入浅出描述了发布订阅模型的使用、发布订阅模型实现的数据结构以及使用发布订阅模型的场景
发布订阅是一种通信模式,哨兵通过发布订阅来与节点进行交流,发布订阅能够实现关注、订阅系统的实现
发布订阅的两种方式订阅频道、模式是通过维护频道字典和模式链表实现的,其中发送消息会先遍历字典和链表找出匹配频道的订阅客户端进行发送,其他pubsub相关查看订阅信息命令都是从频道字典和模式链表中获取信息
最后
- 参考资料
- 《Redis深度历险》
- 《Redis设计与实现》