Redis 订阅发布模式(pub/sub)浅析
Redis 支持简单的 pub/sub 功能,之所以说其简单,是因为消息是发送即遗忘的(fire and forgot),不会进行持久化,一旦宕机,消息丢失。
客户端可以使用两种方式订阅消息:
- 频道(channel)
- 模式(pattern)
频道是最简单和核心的方式,模式是基于频道的模式匹配。例如:现有频道 "it.news" 和 "it.post" ,客户端可以直接订阅 "it.new",或者可以订阅模式 "it.*" 从而在频道 "it.news" 和 "it.post"有消息时得到通知。
深入 Redis 源代码(branch: 6.0)来探究 Redis pub/sub 功能的实现。
在 redisServer 和 client 中包含了 pubsub_channels 和 pubsub_patterns,如下(server.h):
struct redisServer {
dict *pubsub_channels;
list *pubsub_patterns;
dict *pubsub_patterns_dict;
// ...
}
typedef struct client {
dict *pubsub_channels;
list *pubsub_patterns;
// ...
} client;
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
typedef struct dictht {
dictEntry **table;
// ...
} dictht;
typedef struct dict {
dictType *type;
dictht ht[2];
// ...
} dict;
typedef struct list {
listNode *head;
listNode *tail;
unsigned long len;
// ...
} list;
typedef struct pubsubPattern{
client *client;
robj *pattern;
} pubsubPattern;
pubsub_channels 是字典类型(见 dict.c),内部实现是哈希表(hash table),键为 channel,值为订阅该频道的客户端列表 clients。
pubsub_patterns 是一个列表类型(见 adlist.h),内部实现是双向链表,元素为 pubsubPattern,pubsubPattern 包含 glob匹配模式(通配符匹配模式,广泛运用于 Linux 中的 ls、find、mv 等等命令,git 中的 .gitignore 文件中) pattern 和订阅了该匹配模式客户端 client。