redis-benchmark的pub/sub压测无效,因其仅建单发布+单订阅连接、不模拟真实并发,80w+ ops/s无参考价值;必须用多线程python脚本,每线程独立redis连接与pubsub对象,严格控制频道隔离、daemon=true、纳秒级打点,并排查docker网络模式及client-output-buffer-limit溢出问题。

用多线程 Python 脚本实测,别信 redis-benchmark -t pubsub
redis-benchmark 的 PUB/SUB 模式只建单个发布 + 单个订阅连接,循环压测,完全不模拟真实业务的并发连接压力。它跑出的 80w+ ops/s 数值对线上毫无参考价值,甚至会误导你认为“延迟没问题”。
真实高并发场景下必须用多线程/多进程脚本,每个线程持有一个独立 redis.Redis() 实例和 pubsub 对象:
- 发布端:启动 N 个线程,每线程用独立连接调用
publish(),频道名建议带后缀(如news:0~news:29),避免单 channel 广播锁竞争 - 订阅端:同样启动 N 个线程,每线程
subscribe()不同频道(或同一频道但隔离连接),调用listen()前务必设daemon=True - 时间戳打点:在
publish()前记录time.time_ns(),在on_message回调里立刻读取当前纳秒时间,差值即端到端延迟 - 禁用耗时操作:
listen()循环里只做计数和打点,任何 DB 写入、HTTP 请求都会积压消息,导致缓冲区溢出断连
Docker 环境下延迟飙升?先查网络模式和连接地址
很多团队一上 Docker 就发现延迟从 0.5ms 跳到 6–12ms,根源不是 Redis 配置,而是默认 --network bridge 引入的虚拟网络栈开销:veth → docker0 → iptables → NAT,每跳加 0.5–2ms。
验证方法很简单:容器内用 curl -v http://host.docker.internal:6379 或 telnet host.docker.internal 6379 测通断,再对比改用 --network host 后的延迟变化。
注意两个易错点:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 改
host网络后,redis-cli必须连127.0.0.1:6379,不能用localhost(否则可能走 Unix socket 失败) - 避免让 Python 客户端通过
127.0.0.1:6379连宿主机 Redis——这会触发 Docker port mapping,额外引入 DNAT 和 conntrack,延迟更不可控 - 若必须用 bridge,可临时禁用 conntrack:
sysctl -w net.netfilter.nf_conntrack_enable=0,再重启 dockerd(需评估对其他容器影响)
延迟毛刺或断连?检查 client-output-buffer-limit 是否触顶
线上一旦启动 30+ 个 Python 订阅线程,Redis 很快开始断连、丢消息,根本原因是每个 pubsub 实例独占输出缓冲区,而默认配置 client-output-buffer-limit pubsub 32mb 8mb 60 在高并发下极易被撑爆。
现象包括:
- Redis 日志出现
Client id=xxx disconnected, output buffer too big -
redis-cli pubsub numsub your_channel返回的订阅数波动剧烈 - 消息积压明显,
on_message回调延迟突增且不规律
解决办法:
- 调大限制:在 redis.conf 中改为
client-output-buffer-limit pubsub 256mb 64mb 60(根据内存余量调整) - 更稳妥的是按业务域拆分连接池:订单通知、库存变更等各自用专属
ConnectionPool,避免一个模块的 PUBLISH 污染另一个模块的 pubsub 缓冲区 - Java 用户用 Lettuce 时,为不同
StatefulRedisPubSubConnection配置独立ClientResources,防止共享 event loop 导致 READONLY 报错
为什么 p90 延迟稳定在 100–200μs,但你测出来全是 5–10ms?
因为你在测的不是 Pub/Sub 本身的处理延迟,而是 TCP 往返路径 + 客户端调度 + 操作系统中断延迟的叠加结果。Redis 内部 PUBLISH 到广播给所有在线客户端的纯内存操作确实能压到 sub-millisecond,但真实端到端包含:
- 发布端应用层序列化 + 网络发包时间
- 中间网络设备(尤其 Docker bridge)的转发延迟
- 订阅端 TCP 接收、内核协议栈处理、Python GIL 调度、回调函数入队时间
所以实测目标应是:在可控网络(如 host 网络)、轻量消息体(










