Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • ⛸️ Redis Implementation
    • Part 1 - 数据结构与对象

      • Chapter 2 - 简单动态字符串
      • Chapter 3 - 链表
      • Chapter 4 - 字典
      • Chapter 5 - 跳跃表
      • Chapter 6 - 整数集合
      • Chapter 7 - 压缩列表
      • Chapter 8 - 对象
    • Part 2 - 单机数据库的实现

      • Chapter 9 - 数据库
      • Chapter 10 - RDB 持久化
      • Chapter 11 - AOF 持久化
      • Chapter 12 - 事件
      • Chapter 13 - 客户端
      • Chapter 14 - 服务器
    • Part 3 - 多机数据库的实现

      • Chapter 15 - 复制
      • Chapter 16 - Sentinel
      • Chapter 17 - 集群
    • Part 4 - 独立功能的实现

      • Chapter 18 - 发布与订阅
      • Chapter 19 - 事务
      • Chapter 21 - 排序
      • Chapter 22 - 二进制位数组
      • Chapter 23 - 慢查询日志

Chapter 18 - 发布与订阅

Created by : Mr Dk.

2020 / 06 / 09 20:53

Nanjing, Jiangsu, China


Redis 客户端可以订阅一个或多个频道,称为频道的订阅者,每当其它客户端向被订阅的频道发送消息时,频道的 所有订阅者 都会收到这条消息。另外,客户端还可以订阅一个 频道模式,当其它客户端向某个频道发布消息时,如果频道与频道模式匹配,那么除了频道订阅者以外,频道模式的订阅者也能接收到消息。

Subscription

Redis 服务器将所有订阅关系维护在服务器状态的 pubsub_channels 字典中:

struct redisServer {
    // ...
    dict *pubsub_channels;
    // ...
};

字典的 key 是被订阅的频道名;字典的 value 是一个链表,记录了订阅该频道的所有客户端。当客户端发出订阅请求时,服务器首先查找对应的频道名是否存在,如果存在,那么直接将客户端加入链表;如果不存在,则会新建一个键,并将客户端放到链表的第一个位置。

解除订阅的过程恰恰相反。服务器通过遍历订阅字典,把客户端从频道 key 对应的链表中删除。如果客户端被移除后,频道 key 对应的链表为空,那么这个 key 也将会从字典中删除。

Pattern Subscription

服务器将所有模式的订阅信息维护在服务器状态中:

struct redisServer {
    // ...
    list *pubsub_patterns;
    // ...
};

这个属性是一个链表,其中的每个结点都记录了一个被订阅的 pattern 和对应的客户端:

typedef struct pubsubPattern {
    redisClient *client;
    robj *pattern;
}

当客户端请求订阅模式时,将构造一个新的 pubsubPattern 结构,并添加到链表尾部;退订时,只需要将该结构从链表中移除。


Publishing Message

当 Redis 客户端执行 PUBLISH <channel> <message> 后,服务器将执行如下动作:

  1. 将 message 发给 channel 的所有订阅者
  2. 将消息发送给所有与 channel 匹配的 pattern 对应的订阅者

第一步,服务器从 pubsub_channels 字典中取得该频道对应的客户端链表,遍历链表依次将消息发送给订阅者客户端;第二步,服务器遍历 pubsub_patterns 链表,如果 pattern 匹配,也将消息推送给对应的客户端。


Subscription Information

客户端可以通过命令查看服务器中的所有订阅关系。

PUBSUB CHANNELS

该命令返回服务器当前被订阅的频道。遍历服务器的频道字典即可。如果命令还指定了 pattern,则只返回匹配的频道。

PUBSUB NUMSUB

返回频道的订阅者数量。服务器通过 pubsub_channels 字典,找到频道对应的订阅者链表,然后返回订阅者链表的长度。

PUBSUB NUMPAT

返回服务器当前订阅模式的数量。服务器直接返回 pubsub_patterns 链表的长度。

Edit this page on GitHub
Next
Chapter 19 - 事务