当前位置: 首页 > news >正文

Redis 发布订阅:社区的 “通知栏与分类订阅” 系统

目录

一、核心概念:社区的 “通知栏、订阅者与分类”

二、频道订阅:居民 “登记关注通知栏”(SUBSCRIBE/UNSUBSCRIBE)

1. 数据结构对应:社区的 “通知栏 - 订阅者名单”

2. 订阅操作(SUBSCRIBE):登记关注

3. 退订操作(UNSUBSCRIBE):注销关注

三、模式订阅:居民 “按类别订阅所有相关通知栏”(PSUBSCRIBE/PUNSUBSCRIBE)

1. 数据结构对应:社区的 “分类订阅记录”

2. 模式订阅(PSUBSCRIBE):按类别登记

3. 模式退订(PUNSUBSCRIBE):取消分类订阅

四、发布消息:往通知栏贴消息,自动推送给订阅者(PUBLISH)

1. 推送给 “该频道的订阅者”(精准推送)

2. 推送给 “匹配模式的订阅者”(模糊推送)

五、衔接之前的 Redis 结构知识

六、模式订阅的优势:减少重复操作

七、总结:发布订阅的 “社区通知逻辑”


如果把 Redis 的客户端比作 “社区居民”,那发布订阅(Pub/Sub)功能就是社区的 “通知栏 + 分类订阅系统”—— 居民可以 “订阅特定通知栏(频道)” 或 “按类别订阅通知(模式)”,发布者往通知栏贴消息(发布)后,所有订阅的居民都会收到消息。这种机制不用居民主动查消息,实现 “消息主动推送”,就像社区通知自动送到订阅者手里。

一、核心概念:社区的 “通知栏、订阅者与分类”

先理清发布订阅的 3 个核心角色,对应社区场景:

  • 频道(Channel):社区的 “专属通知栏”,比如 “快递 - 北门”“物业 - 缴费”“邻里 - 二手闲置”—— 每个通知栏只发对应类别的消息。

  • 订阅者(Subscriber):关注通知栏的居民,比如老张订阅 “快递 - 北门”,每次有快递通知都会收到。

  • 模式(Pattern):“通知类别模糊匹配”,比如老李订阅 “快递 -*”(* 是通配符),不管是 “快递 - 北门”“快递 - 南门”,只要带 “快递 -” 的通知栏发消息,老李都能收到。

二、频道订阅:居民 “登记关注通知栏”(SUBSCRIBE/UNSUBSCRIBE)

居民要关注某个通知栏,需要 “登记信息”;不想关注了,就 “注销登记”。

Redis 用 pubsub_channels字典  管理这种 “通知栏 - 订阅者” 关系:

1. 数据结构对应:社区的 “通知栏 - 订阅者名单”

Redis 服务器状态里的pubsub_channels是个字典,键是 “频道名(通知栏名)”,值是 “订阅该频道的客户端链表(关注通知栏的居民名单)”:

struct redisServer {dict *pubsub_channels; // 键:频道名,值:订阅者客户端链表
};
  • 比如 “快递 - 北门” 频道的键对应一个链表,里面存着订阅该频道的 3 个客户端(老张、老王、小李)。

2. 订阅操作(SUBSCRIBE):登记关注

居民老张执行SUBSCRIBE 快递-北门,相当于 “在‘快递 - 北门’通知栏的订阅名单上登记自己”,Redis 的操作分两种情况:

  • 通知栏已存在(已有其他人订阅):直接把老张的客户端(redisClient)加到 “快递 - 北门” 对应的链表末尾。
  • 通知栏不存在(没人订阅过):先在pubsub_channels字典里新建 “快递 - 北门” 键,值设为空链表,再把老张的客户端加进去(成为第一个订阅者)。

3. 退订操作(UNSUBSCRIBE):注销关注

老张不想关注 “快递 - 北门” 了,执行UNSUBSCRIBE 快递-北门,Redis 的操作:

  • pubsub_channels字典找到 “快递 - 北门” 对应的链表,删除老张的客户端。
  • 如果删除后链表空了(没人关注这个通知栏了),就把 “快递 - 北门” 这个键从字典里删掉 —— 就像社区撤掉没人关注的通知栏。

三、模式订阅:居民 “按类别订阅所有相关通知栏”(PSUBSCRIBE/PUNSUBSCRIBE)

如果居民老李想关注 “所有快递相关的通知栏”(不管北门、南门),不用逐个登记,只需 “按类别订阅”。Redis 用 pubsub_patterns链表管理这种 “模式 - 订阅者” 关系:

1. 数据结构对应:社区的 “分类订阅记录”

Redis 服务器状态里的pubsub_patterns是个链表,每个节点是pubsubPattern结构,记录 “订阅者(居民)” 和 “订阅的模式(类别)”:

struct redisServer {list *pubsub_patterns; // 存储所有模式订阅关系的链表
};typedef struct pubsubPattern {redisClient *client; // 订阅模式的客户端(老李)robj *pattern;       // 订阅的模式("快递-*")
} pubsubPattern;
  • 比如老李订阅 “快递 -”,链表会新增一个节点:client指向老李的客户端,pattern是 “快递 -” 的字符串对象(底层用 SDS 存储,衔接之前的 SDS 知识)。

2. 模式订阅(PSUBSCRIBE):按类别登记

老李执行PSUBSCRIBE 快递-*,Redis 的操作:

  1. 新建一个pubsubPattern结构,client设为老李的客户端,pattern设为 “快递 -*”(SDS 字符串)。
  2. 把这个结构加到pubsub_patterns链表的末尾 —— 相当于社区记录 “老李要收所有快递相关的通知”。

3. 模式退订(PUNSUBSCRIBE):取消分类订阅

老李不想关注快递类通知了,执行PUNSUBSCRIBE 快递-*,Redis 的操作:

  • 遍历pubsub_patterns链表,找到 “client是老李、pattern是‘快递 -*’” 的节点,删除该节点 —— 相当于社区删掉老李的分类订阅记录。

四、发布消息:往通知栏贴消息,自动推送给订阅者(PUBLISH)

社区管理员(发布者客户端)往 “快递 - 北门” 通知栏贴一条消息 “15:00 有京东快递”,所有相关订阅者都会收到。Redis 执行PUBLISH 快递-北门 "15:00有京东快递"时,分两步推送:

1. 推送给 “该频道的订阅者”(精准推送)

  • Redis 从pubsub_channels字典找到 “快递 - 北门” 对应的链表(里面有老张、老王、小李),把消息逐个发给这三个客户端 —— 就像管理员把通知念给关注 “快递 - 北门” 的居民听。

2. 推送给 “匹配模式的订阅者”(模糊推送)

  • Redis 遍历pubsub_patterns链表,检查每个模式是否匹配 “快递 - 北门”:
    • 老李订阅的 “快递 -*”,*匹配任意字符,所以 “快递 - 北门” 符合模式。
  • 把消息发给老李的客户端 —— 就像管理员把快递通知也发给 “关注所有快递类” 的老李。

五、衔接之前的 Redis 结构知识

发布订阅功能完全复用了之前学的核心结构,体现 Redis 的 “结构复用” 设计:

  1. SDS:频道名、模式名(如 “快递 - 北门”“快递 -*”)都是字符串,底层用 SDS 存储 —— 利用 SDS 的动态扩展、二进制安全特性,支持长名称或特殊字符。
  2. redisClient:订阅者本质是客户端,用redisClient结构体记录(如fdname等属性)—— 和之前讲的 “客户端管理” 逻辑一致。
  3. dict 与 listpubsub_channels用字典(dict)实现 “频道 - 订阅者” 的快速查找(O (1) 定位频道);pubsub_patterns用链表(list)实现 “模式 - 订阅者” 的遍历 —— 复用了字典的快速查找和链表的灵活遍历特性。

六、模式订阅的优势:减少重复操作

如果没有模式订阅,老李要关注 “快递 - 北门”“快递 - 南门”“快递 - 东门” 3 个频道,需要执行 3 次SUBSCRIBE,还要维护 3 个订阅关系;有了模式订阅,只需 1 次PSUBSCRIBE 快递-*,后续新增 “快递 - 东门” 频道,老李不用再操作,自动收到该频道的消息 —— 极大减少重复操作,适合 “批量订阅同类频道” 的场景。

七、总结:发布订阅的 “社区通知逻辑”

Redis 的发布订阅就像社区的智能通知系统:

  • 频道订阅是 “精准关注单个通知栏”,用字典快速定位订阅者;
  • 模式订阅是 “模糊关注一类通知栏”,用链表遍历匹配订阅者;
  • 发布消息是 “贴通知 + 自动推送”,先精准推给频道订阅者,再模糊推给模式订阅者。

这种设计不用订阅者主动轮询消息,实现 “消息实时推送”,同时复用 Redis 的核心数据结构(SDS、dict、list、redisClient),保证效率和灵活性 —— 就像社区通知系统既精准又智能,满足不同居民的订阅需求。


文章转载自:

http://nvtc9HP9.wtLyr.cn
http://6zoeopjz.wtLyr.cn
http://hSsvf4TF.wtLyr.cn
http://fAgBR0a8.wtLyr.cn
http://XnSqipBC.wtLyr.cn
http://LIpknLsq.wtLyr.cn
http://frySWSvz.wtLyr.cn
http://BGnhYxLM.wtLyr.cn
http://JAPajk82.wtLyr.cn
http://3viU12xs.wtLyr.cn
http://3dimbZOb.wtLyr.cn
http://ho4U2PKR.wtLyr.cn
http://GEPMcbte.wtLyr.cn
http://GfNyCYpn.wtLyr.cn
http://VtcHwTaG.wtLyr.cn
http://9b0q9kYr.wtLyr.cn
http://0Su8waqx.wtLyr.cn
http://qc5Eaj4u.wtLyr.cn
http://bi5uTlLi.wtLyr.cn
http://Cofi34yQ.wtLyr.cn
http://DyKC7z6F.wtLyr.cn
http://oMHvsgMg.wtLyr.cn
http://qvz2mEiM.wtLyr.cn
http://5DWgYlIg.wtLyr.cn
http://gFqMNM6k.wtLyr.cn
http://VBX5yUzE.wtLyr.cn
http://UK9guHIs.wtLyr.cn
http://s98cPKSL.wtLyr.cn
http://L77EqYiO.wtLyr.cn
http://AUQxQR0J.wtLyr.cn
http://www.dtcms.com/a/368773.html

相关文章:

  • WordPress性能优化全攻略:从插件实战到系统级优化
  • [新启航]激光频率梳 3D 轮廓测量 - 蓝光机械 3D 扫描的工作原理及优缺点
  • 3DEXPERIENCE平台五大实用技巧指南
  • 彻底搞懂深度学习-模型压缩(减枝、量化、知识蒸馏)
  • 概率论第二讲——一维随机变量及其分布
  • ChartGPT深度体验:AI图表生成工具如何高效实现数据可视化与图表美化?
  • 【AndroidStudio】官网下载免安装版,AndroidStudio压缩版的配置和使用
  • Android Activity的启动流程
  • 将 Android 设备的所有系统日志(包括内核日志、系统服务日志等)完整拷贝到 Windows 本地
  • NGUI--三大基础控件
  • 服务器IP暴露被攻击了怎么办?
  • Transformer实战——使用 run_glue.py 微调模型
  • SQLalachemy 错误 - Lost connection to MySQL server during query
  • 门控MLP(Qwen3MLP)与稀疏混合专家(Qwen3MoeSparseMoeBlock)模块解析
  • React Hooks useContext
  • 【Linux】Linux 的 cp -a 命令的作用
  • 基于FPGA实现CRC校验码算法(以MODBUS中校验码要求为例)verilog代码+仿真验证
  • LeetCode刷题-top100( 矩阵置零)
  • 算法模板(Java版)_DFS与BFS
  • 一分钟了解Modbus 转 IEC61850 网关
  • Webpack 有哪些特性?构建速度?如何优化?
  • 2025精选5款AI视频转文字工具,高效转录秒变文字!
  • 【最新版】发烧级完美解码播放器PureCodec v2025.08.29 中文免费版_电脑播放器影音解码包
  • 阿里云国际代理:阿里云的云数据库是什么?
  • 盲盒抽卡机小程序功能版块设计的合理性评估维度
  • Memory write error at 0x100000. MMU page translation fault
  • 纯血鸿蒙开发入门:2.展示hello world
  • 【1】策略模式 + 模板方法模式的联合应用
  • 突发奇想,还未实践,在Vben5的Antd模式下,将表单从「JS 配置化」改写成「模板可视化」形式(豆包版)
  • Flash Attention:突破大模型推理内存瓶颈的革命性算法