redis用作消息队列性能下降的根本原因是误用pubsub模式,因其无存储、无顺序保障、无重试机制且客户端断连即丢消息;lpush+brpop存在连接数膨胀、无消费者组、无ack等问题;stream虽支持消费者组和ack,但仍缺ttl、延迟消息和死信队列,仅适合作为轻量级过渡方案。

Redis 用作消息队列时性能下降,根本原因不是“用了 Redis”,而是误用了 PUBSUB 模式——它不存消息、不保顺序、不支持重试,客户端断连即丢消息。这不是调优能解决的问题,是模型错配。
为什么 PUBSUB 一压测就掉链子
它本质是广播通道,不是队列:所有订阅者实时收到副本,没有存储层,也不记录消费状态。
- 发布者发完即忘,
PUBLISH返回成功 ≠ 消息被任何消费者拿到 - 消费者离线期间发布的消息彻底丢失,
SUBSCRIBE重连后无法回溯 - 无 ack 机制,无法确认处理成功,更谈不上重试或死信
- 高并发下,频繁的 socket 通知和内存拷贝会推高 CPU,而 Redis 单线程模型对此毫无招架之力
LPUSH + BRPOP 也扛不住大流量
用 List 模拟队列看似可行,但实际在中等规模业务中很快暴露瓶颈:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
-
BRPOP是阻塞命令,每个消费者独占一个连接,连接数随消费者数量线性增长,容易打满maxclients - 没有内置的 consumer group,多个 worker 消费同个 List 时需自行实现竞争逻辑(如
WATCH+MULTI),极易出错且性能差 - List 底层是双向链表,
LLEN是 O(N),监控队列长度本身就会拖慢主线程 - 消息一旦被
BRPOP取出就从 List 删除,没失败重入机制;若消费者崩溃,消息直接丢失
真正能撑住的 Redis 队列方案只有 Stream
Redis 5.0 引入的 Stream 是唯一接近专业 MQ 能力的原生结构,但它仍缺关键能力:
- 支持消费者组(
XGROUP)、消息 ID 自增、ACK 确认(XACK)、未确认消息重读(XCLAIM) - 但不支持消息 TTL、无延迟消息、无死信队列(DLQ),也不能按 tag 或 header 路由
-
XADD和XREADGROUP均为 O(1),性能尚可,但当单个 Stream 积压超百万条时,XINFO STREAM查询元信息会明显变慢 - 持久化依赖 RDB/AOF,若配置为
appendfsync no,宕机仍可能丢最后几秒消息
该换 MQ 的明确信号
出现以下任意一条,就该立刻评估迁移到 Kafka/RocketMQ/Pulsar:
- 业务要求消息 100% 不丢(比如支付结果通知)
- 需要消息重试 + 死信 + 限流 + 延迟投递(比如订单超时关单)
- 消费者处理耗时波动大,当前靠加机器硬扛,但运维成本已高于引入新中间件
- 开始自己写脚本轮询
INFO replication或MEMORY USAGE来防雪崩——说明你已在给 Redis 打补丁,而不是用它做事
Redis Stream 可作为轻量级场景的过渡选择,但别把它当主力。真正的消息可靠性,不在数据结构里,而在设计契约中:谁发、谁收、谁兜底、丢了一定要告警——这些,Redis 从没承诺过。










