欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Redis发布与订阅操作

程序员文章站 2022-05-21 21:26:08
...

引言

Redis支持频道订阅和模式订阅;

  • 频道订阅:订阅的频道和发布消息的频道相同时,客户端可以接收到消息,如一个客户端订阅频道news.it,则只有频道news.it的消息才可以发送给该客户端;
  • 模式订阅:一个模式可以匹配一个或多个频道,当发布消息的频道与订阅的频道模式匹配时,客户端可以接收到消息,如一个客户端订阅模式news.[ie]t,则它可以接收发布到频道news.itnews.et的消息;

1. 数据结构

1.1 频道字典

  • 用于频道订阅;
  • 多个客户端可以订阅相同的频道,在服务器的redisServer结构里有一个pubsub_channels属性,是一个字典,维护了所有被订阅的频道;
  • 字典的键是被订阅的频道,字典的值则是一个链表,链表里记录了所有订阅这个频道的客户端;
struct redisServer{
    // ...
    
    // 保存所有频道的订阅关系
    dict *pubsub_channels;
    
    // ...
};

Redis发布与订阅操作

2. 模式链表

  • 用于模式订阅;
  • 一个模式可以匹配一个或多个频道;每个客户端订阅的模式可能各不相同,所以将客户端和订阅的模式构建成一个pubsubPattern结构,然后将多个订阅构成一张链表,存放在redisServerpubsub_patterns属性里;
struct redisServer{
    // ...
    
    // 保存所有模式订阅关系
    list *pubsub_patterns;
    
    // ...
};

typedef struct pubsub_pattern{
    // 订阅模式的客户端
    redisClient *client;
    
    // 被订阅的模式
    robj *pattern;
}pubsub_pattern;

Redis发布与订阅操作

2. 发布订阅命令

2.1 订阅频道命令 subscribe

# 订阅频道 "news.sport" 和 "news.movie"
SUBSCRIBE "news.sport" "news.movie"

每当客户端执行SUBSCRIBE命令订阅某个或某些频道时,服务器都会将客户端与被订阅的频道在pubsub_channels字典中进行关联:

  • 如果频道已经有其他订阅者(字典中已经存在键为当前频道的订阅者链表),那么服务端直接将客户端添加到订阅者链表的末尾;
  • 如果频道还未有任何订阅者(字典中没有存在键为当前频道的订阅者链表),服务器首先在pubsub_channels字典中为频道创建一个键,并将这个键的值设置为空链表,然后再将客户端添加到链表,成为链表的第一个元素;

2.2 退订频道 unscubscribe

# 退订频道 "news.sport" 和 "news.movie"
UNSUBSCRIBE "news.sport" "news.movie"

当一个客户端退订某个频道或者某些频道时,服务器将从pubsub_channels字典中解除客户端与频道之间的关联:

  • 程序会根据根据退订的频道名字,在pubsub_channels字典中找到频道对应的订阅者链表,然后从订阅者链表中删除退订客户端的信息;
  • 如果删除退订客户端之后,频道的订阅者链表变成了空链表,那么说明这个频道已经没有任何订阅者了,程序将从pubsub_channels字典中删除频道对应的键;

2.3 订阅模式 psubscribe

# 订阅所有以 "news."开头的频道
PSUBSCRIBE "news.*"

订阅模式是服务器端的pubsub_patterns链表中添加节点;

每到客户端执行PSUBSCRIBE命令订阅某个或某些模式时,服务器会对每个被订阅的模式执行以下两个操作:

  • 新建一个pubsubPattern结构,将结构的pattern属性设置为被订阅的模式,client属性设置为订阅该模式的客户端;
  • pubsubPattern结构添加到pubsub_patterns链表的末尾;

2.4 退订模式 punsubscribe

# 退订模式 "news.*"
PUNSUBSCRIBE "news.*"

当一个客户端退订某个或某些模式的时候,服务器将在pubsub_patterns链表中查找并删除那些pattern属性为被退订模式,并且client属性为执行退订命令的客户端的pubsubPattern结构

2.5 发送消息 publish

PUBLISH <channel> <message>

# 向频道 "news.it"发送 "hello"消息
PUBLISH "news.it" "hello"

当一个客户端执行PUBLISH命令将消息message发送给频道channel时,服务器需要执行以下两个操作:

  • 查询pubsub_channels字典,将消息发送给channel频道的所有订阅者;
  • 遍历pubsub_patterns链表,如果某个订阅模式pattern与频道channel相匹配,那么将消息发送给pattern模式的订阅者;

注意:

  • 发送消息只有一个命令PUBLISH
  • PUBLISH可以同时将消息发送给频道订阅者模式订阅者

参考文献

  • 《Redis设计与实现》黄建宏 著,机械工业出版社.
相关标签: Redis redis