如何在Redis发布订阅架构中设计幂等消费逻辑防止重复处理

胖伟小哥_3525

胖伟小哥_3525

2026-09-23

691人浏览

原创

redis pub/sub本身不防重复,是广播模型必然结果;必须由业务层用set nx ex+全局唯一msg_id做前置幂等校验,且校验失败直接跳过,不可重试或ack。

如何在redis发布订阅架构中设计幂等消费逻辑防止重复处理

Redis Pub/Sub 本身不防重复,多实例、重连、网络抖动都会导致同一条消息被多次收到——这不是缺陷,是广播模型的必然结果。防重复必须由业务层兜底,核心就一条:用 SET 原子指令 + 全局唯一 msg_id 做前置校验。

为什么 SUBSCRIBE 和 PSUBSCRIBE 都无法解决重复消费

有人误以为换用 PSUBSCRIBE(模式订阅)就能避开重复,其实它只改变“哪些频道的消息能进当前连接”,不改变“每条匹配消息进几次”。比如你启动 3 个进程都 PSUBSCRIBE order.*,而发布端发了 PUBLISH order.created "...",这 3 个进程各自都会收到一份副本。

更关键的是:SUBSCRIBEPSUBSCRIBE 都没有消费确认机制,Redis 不记录谁收到了、谁处理失败了、谁卡在中间。所以无论你怎么切订阅方式,重复问题照旧。

必须由发布方生成并透传 msg_id

消费者不能自己拼 msg_id(比如用时间戳+随机数),因为不同进程可能在同一毫秒生成相同字符串;也不能依赖 Redis 自增 ID(INCR),因为 Pub/Sub 没有事务上下文,ID 和消息不是原子绑定的。

  • 推荐用 uuid4() 或 Snowflake ID,在发布时就塞进 payload,例如:{"msg_id": "a1b2c3...", "data": {...}}
  • 如果用 Spring Data Redis,convertAndSend() 发送前先序列化好带 msg_id 的对象
  • 前端或上游服务调用发布接口时,也应统一生成并透传该 ID,避免下游再补

消费者端用 SET NX EX 做原子幂等校验

校验动作必须在真正执行业务逻辑之前完成,且失败时直接返回,不要重试、不要 ACK——因为 Pub/Sub 根本不支持 ACK。

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载

正确写法是单条命令完成“不存在才写”+“自动过期”,例如:

if not redis_client.set(f"seen:{msg_id}", "1", nx=True, ex=3600):
    return  # 已处理过,跳过

注意以下三点:

  • 别拆成 SETNX + EXPIRE:两步非原子,高并发下可能写入成功但过期失败,key 永久残留
  • TTL 时间要合理:太短(如 60 秒)可能业务还没跑完 key 就过期;太长(如 7 天)会占内存,建议按业务最长处理耗时 × 2~3 倍设置
  • key 命名带上业务域前缀,比如 order:seen:{msg_id},避免跨业务冲突

Redis 故障时幂等会失效,这点必须接受

如果 Redis 实例宕机或网络分区,SET 操作失败,消费者会认为“没存过”,继续执行业务逻辑——此时重复就真发生了。这不是设计漏洞,而是权衡:为强一致性引入 ZooKeeper 或数据库去重,会拖慢整个 Pub/Sub 流程,违背其轻量广播的定位。

生产环境真正要做的,是把这种失效当成已知边界来设计:比如订单场景,Redis 去重失败后,后续仍走数据库唯一索引兜底;日志类场景,可容忍少量重复,不做额外防护。别指望一个方案吃掉所有风险。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4009

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

3515

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

6232

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

583

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

696

6

mysql和redis怎么保证双写一致性
mysql和redis怎么保证双写一致性

确保 mysql 和 redis 双写一致性的技术包括:1、事务性更新:同时更新 mysql 和 redis,保证一致性;2、主从复制:mysql 主服务器更改同步到 redis 从服务器;3、基于事件的更新:mysql 记录更改并发送到 redis等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

5642

6

redis缓存一般存些什么数据
redis缓存一般存些什么数据

redis缓存中存储的数据类型包括:字符串、哈希、列表、集合、有序集合、位图、地理空间数据和hyperloglog。这些数据类型适用于存储各种数据,从简单信息到复杂对象和地理位置。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1120

6

redis的8种数据类型有哪些
redis的8种数据类型有哪些

redis 提供 8 种数据类型:字符串(文本、数字、二进制)、哈希(键值对)、列表(有序集合)、集合(无序唯一元素)、有序集合(按分数排序)、地理空间(地理位置)、hyperloglog(估计大数据基数)和位图(位序列存储)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

916

6

redis主要作用有哪些
redis主要作用有哪些

redis 的主要作用包括:1. 缓存数据,提高访问速度;2. 充当消息队列,实现消息传递;3. 存储各种数据类型,如字符串、散列和集合;4. 管理会话信息,确保可靠性和可用性;5. 限制请求速率,防止服务器超载等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

5118

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习