当前位置:首页 > 文章列表 > 数据库 > Redis > Redis Pub/Sub 订阅者断线后为什么收不到历史消息

Redis Pub/Sub 订阅者断线后为什么收不到历史消息

来源:17golang原创 2026-09-10 16:45:59 0浏览 收藏

Redis 的 Pub/Sub 订阅者断线后收不到之前错过的历史消息,不是客户端漏写了拉取逻辑,而是这套机制从设计之初就没有历史回放的语义。Redis 官方把 Pub/Sub 定义为 at-most-once(最多一次)投递模式:消息发布的瞬间,只有当下已经连通服务端、并且提前订阅了对应频道的客户端才能收到这条消息。如果客户端中途断线、消息处理失败,哪怕之后立刻重连重新发起订阅,之前错过的消息也不会自动补发。业务如果需要支持消息补偿读取、实现至少一次消费的可靠性,应该把事件写入 Redis Streams 或者独立的业务持久化存储,Pub/Sub 只用来做轻量的实时通知就好。

官方地址:https://redis.io/

要点速览
  • Pub/Sub 是广播通道,不保存消息,也没有订阅者游标;断线期间发布的消息会永久错过。
  • 允许短暂丢失的缓存失效、在线状态和界面刷新可以继续用 Pub/Sub,但重连后要主动读取持久状态。
  • 订单、审计、任务和必须补偿的领域事件,应选择 Redis Streams 或业务数据库,再按消息 ID 恢复。

Redis Pub/Sub 为什么不会补发断线消息

PUBLISH 的工作是把一条消息推给当前匹配频道的订阅者;SUBSCRIBE 建立的是实时监听关系,不是一个可以翻页的消息列表。消息经过广播后不会自动写入某个频道历史,也不存在“订阅者上次读到哪里”的位置。

因此,发布者在 10:00 发送消息,订阅者在 10:01 才重连,即使频道名称、客户端身份和业务内容都一样,10:00 的消息也不会因为重新执行 SUBSCRIBE 而出现。Redis 文档把这种行为称为 at-most-once;断开网络、消费者进程崩溃或回调处理失败时,消息都没有第二次投递机会。

Redis Pub/Sub 广播边界:发布者通过 PUBLISH 消息连接在线订阅者,断线订阅者在边界外,持久状态单独保存
图1:Pub/Sub 只把发布时的消息推给广播边界内的在线订阅者,断线客户端不自动获得历史记录。

先区分实时广播和可恢复数据

排查“重连后少消息”时,先不要急着调大客户端缓冲区。要问的是:这条消息本身是不是业务事实?如果只是“让页面刷新一下”的提示,丢一条通常可以接受;如果它代表支付状态、库存变更或审计记录,就不能把唯一事实放在 Pub/Sub 上。

场景Pub/Sub 是否合适重连后的处理
缓存失效通知适合,允许偶发漏通知重连时按版本或 TTL 主动刷新缓存
在线状态、输入中提示适合,状态很快过期重新上报当前状态,不追历史事件
订单、扣款、审计不应作为唯一通道从数据库或 Streams 按记录/消息 ID 补偿

另外,Pub/Sub 与 Redis 数据库编号没有关系:在一个逻辑数据库上发布,不会让另一个数据库产生独立的频道历史。需要环境隔离时,应把 prod:staging: 这类环境前缀放进频道名。

允许丢失的通知,重连时怎样补当前状态

实时通知可以继续使用 Pub/Sub,但把“可恢复的当前状态”放在普通 Redis key 或业务数据库里。发布者先写入状态,再广播一个轻量通知;订阅者收到通知后读取状态。重连时不追问“我错过了几条消息”,而是直接读取最新状态,避免把广播通道误当成事件日志。

#!/usr/bin/env bash
# 先保存可恢复的当前版本,再发送只负责提醒的实时通知。
redis-cli HSET order:42 status paid version 18
# PUBLISH 返回当前收到消息的订阅者数量,不是历史消息数量。
redis-cli PUBLISH order:changed '{"order_id":42,"version":18}'

# 订阅者重连后主动读取当前状态,而不是等待 Pub/Sub 补发旧消息。
redis-cli HGETALL order:42

这个模式的关键是幂等:通知可以重复、丢失或乱序到达,但持久状态有版本号,消费者读取后能判断是否需要更新。若业务要求知道每个事件,而不是只关心最终状态,就升级为 Streams。

必须恢复的事件改用 Redis Streams

Redis Streams 会保留消息和消息 ID,可以让消费者在重连后从上次位置继续读取,并结合消费组处理确认与待处理消息。它和 Pub/Sub 解决的是两种不同问题:前者偏向可追踪事件流,后者偏向低延迟广播。

Redis Streams 恢复关系:业务事件同时进入持久化记录和 Redis Stream,消息 ID、消费组连接重连消费者,Pub/Sub 负责实时通知
图2:需要恢复的事件应落到持久化记录或 Redis Stream,Pub/Sub 只负责把实时变化快速通知在线消费者。
#!/usr/bin/env bash
# 把订单事件写入 Stream;* 让 Redis 生成可恢复的消息 ID。
redis-cli XADD order-events '*' order_id 42 status paid

# 消费组从未投递位置读取,重连后仍有消息身份可以继续处理。
redis-cli XREADGROUP GROUP billing-worker consumer-a COUNT 10 STREAMS order-events '>'
# 处理成功后确认这条消息,避免把“读到”误当成“业务完成”。
redis-cli XACK order-events billing-worker 1710000000000-0

生产环境还要明确确认时机、重复消费和待处理消息回收策略。不要因为 Pub/Sub 和 Streams 都在 Redis 里,就把两者混用成“先发布、之后一定能补回”的假可靠链路。

常见问题

订阅者重连后重新 SUBSCRIBE,为什么还是没有旧消息?

SUBSCRIBE 只建立新的实时订阅关系,不读取频道历史。旧消息没有被 Pub/Sub 保存,重连只能收到之后发布的消息。

PUBLISH 的返回值是不是消息积压数量?

不是。它表示本次发布时匹配到并收到推送的订阅者数量,不能说明有多少客户端离线,也不能说明消息是否已被业务处理。

缓存失效通知漏掉后一定会造成脏数据吗?

不一定。若缓存有 TTL、版本校验或重连后的主动刷新,漏掉一次通知可以被修复;没有这些补偿机制时,缓存失效事件就不该只依赖 Pub/Sub。

什么时候应该直接换 Redis Streams?

当消息必须保留、需要重放、需要消费确认、需要按消费者进度恢复,或业务能接受至少一次处理并自行幂等时,应优先考虑 Streams。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go map lookup 读取不存在键为什么返回元素零值Go map lookup 读取不存在键为什么返回元素零值
上一篇
Go map lookup 读取不存在键为什么返回元素零值
Go encoding/csv FieldsPerRecord 设置为负数后如何自行校验列数
下一篇
Go encoding/csv FieldsPerRecord 设置为负数后如何自行校验列数
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    63次使用
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    224次使用
  • C-Eval中文评测基准:大语言模型多学科能力评估指南
    C-Eval
    深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
    148次使用
  • AI Prompt Library:免费AI提示词库,助力ChatGPT高效创作与营销
    AI Prompt Library
    探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
    81次使用
  • Generrated:DALL·E 2/3 AI绘画提示词灵感库与图像对比平台
    Generrated
    Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
    58次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码