综述
redis的消息是靠发布订阅实现的。
但这个消息和消息中间件不太一样,比消息中间件简易得多。没有队列,生产者消费者再启动的时候,会把消息注册到频道这个数据结构中,消息发送后,根据这个数据结构找到订阅该消息的订阅者,直接就给订阅者发送过去。
事就是这么个事,下面看细节。
频道的订阅与退订
当客户端执行subcribe命令订阅某个或某些频道的时候,这个客户端与被订阅频道之间就建立起了一种订阅关系。
redis将这个关系保存在服务器状态这个数据结构中。
struct redisServer {
// ...
// 保存所有频道的订阅关系,是一个字典
// key 为 频道名
// value 为 链表 链表里记录所有订阅这个频道的客户端
dict *pubsub_channels;
// ...
}
订阅频道
subscribe <channel>
退订频道
unsbscribe <channel>
订阅与退订都是对 pubsub_channels 这个字典和链表的增删操作。
模式的订阅与退订
什么是模式。简单理解就是带正则表达式的频道,比如
news.* --> news.it、news.sport 都可以订阅到
news.[ie]t --> news.it、news.et 都可以订阅到
模式的订阅与退订也在redisServer中
struct redisServer {
// ...
// 保存所有模式的订阅关系,是一个链表
// 链表的每一项为pubsubPattern结构体
list *pubsub_patterns;
// ...
}
typedef struct pubsubPattern {
// 订阅模式的客户端
redisClient *client;
// 被订阅的模式
robj *pattern;
} pubsubPattern;
订阅模式
psubscribe <pattern>
退订模式
punsbscribe <pattern>
订阅与退订都是对 pubsub_patterns 这个链表的增删操作。
发送消息
当redis客户端执行
publis <channel> <message>
publis "news.it" "hello"
将消息发送给频道的所有订阅者。用channel这个key到pubsub_channels这个字典中查询所有订阅的list,遍历list发送message。
如果有一个或多个模式pattern与频道相匹配,那么将消息发送给pattern模式的订阅者。遍历pubsub_patterns这个链表,匹配规则,发送message。