Redis Pub/Sub消息发送效率不能只看PUBLISH单次耗时,因其快得几乎测不出,但实际吞吐受订阅者数量、网络状况及Redis版本影响:5.x同步遍历订阅者会阻塞主线程,6.0+改用异步分发避免阻塞。

Redis Pub/Sub 的消息发送效率不能只看 PUBLISH 命令的单次耗时——它快得几乎测不出(通常
用 redis-benchmark 测纯发布吞吐不反映真实场景
官方工具 redis-benchmark -r 10000 -n 100000 -q -P 50 PUBLISH test_channel "msg" 能跑出几十万 QPS,但这只是 TCP 层面的压测:它不建立真正的 SUB 连接,不模拟消息落地、不触发客户端回调。结果虚高,对线上调优无参考价值。
- 真实瓶颈不在
PUBLISH,而在订阅者数量增长后,Redis 单线程要逐个写入每个 SUB 连接的 socket 缓冲区 -
redis-benchmark使用 pipeline,而实际 Pub/Sub 是异步广播,无法 pipeline - 它完全忽略网络抖动、客户端处理阻塞、反序列化开销等关键因素
真实压测必须构造“发布 + 多订阅者 + 消费计时”闭环
核心是让每个订阅客户端记录从收到消息到完成处理的时间戳,并汇总统计。推荐用 Jedis 或 redis-py 实现:
- 启动 N 个独立进程/线程,每个运行一个
pubsub.subscribe(),并监听get_message(timeout=1) - 每个订阅者收到消息后立即记录
time.time(),执行空处理(或模拟业务逻辑),再记录结束时间 - 发布端用循环调用
r.publish(),每发 100 条 sleep 10ms 控制节奏,避免压垮 Redis 内存或连接数 - 重点观察指标:99% 消费延迟、平均堆积量(通过
PUBSUB NUMSUB test_channel定期采样)、客户端断连率
示例关键片段(python):
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
pubsub = r.pubsub()
pubsub.subscribe('test')
for msg in pubsub.listen():
if msg['type'] == 'message':
start = time.time()
# 模拟业务处理
time.sleep(0.002) # 2ms 处理
latency = (time.time() - start) * 1000
print(f"latency: {latency:.2f}ms")主从架构下测试必须明确订阅节点位置
Redis 主从同步支持 Pub/Sub,但消息**只由主节点接收并广播**,从节点只是被动转发;所有订阅者若连从节点,仍需经主节点中转。这意味着:
- 订阅从节点不会降低主节点负载,反而增加主从间网络压力
- 测试时若混用主/从连接,
PUBSUB NUMSUB返回值可能不一致(从节点不维护订阅元数据) - 真正提升扩展性的方式是分片:把不同频道路由到不同 Redis 实例,而非依赖主从
验证方法:分别在主、从节点执行 PUBSUB CHANNELS,只有主节点能列出全部活跃频道。
容易被忽略的三个硬限制
很多压测失败不是代码问题,而是撞上了 Redis 底层约束:
-
client-output-buffer-limit pubsub默认是32mb 8mb 60,单个 SUB 连接缓冲区超 32MB 或 60 秒未读,连接会被强制断开——高频小消息易触发 - Linux
net.core.somaxconn和tcp_max_syn_backlog限制并发连接数,1000+ 订阅者需调大 - 每个 SUB 连接独占一个 Redis client 结构体,内存占用约 10KB,万级订阅者直接吃掉百 MB 内存
这些参数不改,压测刚上量就断连或延迟飙升,但日志里往往只显示 “Connection reset”,不会提示 buffer limit 超限。

















