redis 发布订阅 源码分析

本文深入探讨Redis的发布订阅功能,分析了`sub`、`psub`和`publish`的相关源码实现。在Redis客户端中,`sub`命令以哈希表存储订阅的channels,`psub`使用链表存储模式订阅。`publish`命令通过字典结构快速找到订阅频道的客户端列表,以O(1)时间复杂度进行消息推送。
摘要由CSDN通过智能技术生成

pubsub

目录

以后都在 github 更新,请戳 redis 发布订阅

相关位置文件

  • redis/src/pubsub.c
  • redis/src/util.c

sub

在 redis 客户端中, 如果你输入如下命令

127.0.0.1:6379> SUBSCRIBE c100
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "c100"
3) (integer) 1

sub

pubsub_channels 是以 哈希表 的结构存储的, 在 pubsub_channels 中, key 值是一个 sds 结构, sds 中存储的是 c100

对于 server 对象, key 的内容相同, 但是 value 是一个列表, 列表中的每个元素为对应的 client 实例

对于 client 对象, value 中存储的是一个空指针

在每一个 client 对象中, 所有这个 client 订阅的 channels 都会存储在名为 client.pubsub_channels 的字典中, key 是 channel 的名称, value 是一个空指针

对于 server对象来说, 所有不同的 redis 客户端的所有的 channels 都存储在 server.pubsub_channels

如果我们启动另一个客户端, 并且订阅相同的 channel

127.0.0.1:6379> SUBSCRIBE c100
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "c100"
3) (integer) 1

sub2

如果我们取消一个客户端的订阅, 那么客户端实例中的 pubsub_channels 结构中对应的 channel 会被删除, 并且 server.pubsub_channels.value 这个列表也会把对应的 client 移除

整个操作的时间复杂度为 server.pubsub_channels.value 这个列表的长度, 列表搜索的时间复杂度为 O(N)

psub

如果我们在 redis-cli 中输入如下命令

127.0.0.1:6379> PSUBSCRIBE h*llo
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "h*llo"
3) (integer) 1

psub

并且在另一个 client 中进行订阅

127.0.0.1:6379> PSUBSCRIBE h*llo
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "h*llo"
3) (integer) 1

psub2
server.pubsub_patterns 是一个链表结构, 其中的每一个元素是一个复合结构, 这个结构包含了在指向 pattern 的指针和指向 client 的指针

client.pubsub_patterns 也是一个链表, 其中的每一个元素都是该 client 实例订阅的 pattern

publish

目录 redis/src/util.c 中的函数 stringmatchlen 被用来作为 pattern 匹配的基本函数

当你输入 PUBLISH 命令时

下面这个函数会被调用

int pubsubPublishMessage(robj *channel, robj *message) {
    int receivers = 0;
    dictEntry *de;
    listNode *ln;
    listIter li;

    /* 发送给所有监听对应 channel 的客户端 */
    de = dictFind(server.pubsub_channels,channel);
    if (de) {
        list *list = dictGetVal(de);
        listNode *ln;
        listIter li;

        listRewind(list,&li);
        while ((ln = listNext(&li)) != NULL) {
            client *c = ln->value;
            addReplyPubsubMessage(c,channel,message);
            receivers++;
        }
    }
    /* 发送给所有 pattern 匹配上的客户端 */
    if (listLength(server.pubsub_patterns)) {
        listRewind(server.pubsub_patterns,&li);
        channel = getDecodedObject(channel);
        while ((ln = listNext(&li)) != NULL) {
            pubsubPattern *pat = ln->value;

            if (stringmatchlen((char*)pat->pattern->ptr,
                                sdslen(pat->pattern->ptr),
                                (char*)channel->ptr,
                                sdslen(channel->ptr),0))
            {
                addReplyPubsubPatMessage(pat->client,
                    pat->pattern,channel,message);
                receivers++;
            }
        }
        decrRefCount(channel);
    }
    return receivers;
}

server.pubsub_channels 是一个字典结构, 其中存储 key 值是对应的 channel, value 值是的 client 实例列表, 这个 value 值可以以 O(1) 的时间搜索到, 之后我们遍历这个列表进行推送即可

server.pubsub_patterns 中是一个链表, 每个元素存储了对应的复合结构, 其中有 client 信息和对应的 pattern, 需要遍历这个链表, 对每一个 pattern 都调用 stringmatchlen 进行匹配看是否能匹配的上, 如果能就给对应的客户端进行推送

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值