pipeline将n次tcp往返压缩为1次,核心是客户端攒包合收:命令先缓存、exec时一次性write发送、服务端串行执行后一次性read返回全部结果,消除“等网”空转。

Pipeline 把 N 次 TCP 往返压成 1 次,核心就在这儿。它不改变单条命令执行时间,只消灭“等网”的空转。
每次普通命令都强制走完整 TCP 往返
调 client.Get(ctx, "k") 或 client.Set(ctx, "k", "v", 0) 时,go-redis 底层会:发包 → 等 socket read 返回 → 解析响应 → 才返回结果。哪怕 Redis 服务端 10μs 就执行完,你也要硬等一次 RTT(局域网几毫秒,跨城可能十几毫秒)。
100 条命令 = 100 次 send + 100 次 recv,中间全是网络空等。
- RTT 不是由 Redis 决定的,而是由物理距离、链路质量、TCP 栈行为决定
- 即使
redis-cli -h 127.0.0.1,loopback 也有 ~0.05ms RTT,1000 次就是 50ms 白等 - go-redis/v9 默认用二进制协议,但每次调用仍触发独立的
write()和read()系统调用,上下文切换开销真实存在
Pipeline 实际干了三件事
它不是魔法,是客户端主动把协议层“攒包”+“合收”:
- 调
client.Pipeline()后所有命令(如pip.Set()、pip.HGetAll())只构造命令结构体,不发包 - 所有命令序列被序列化进一个 buffer,最终由
pip.Exec(ctx)一次性write()出去 - 服务端串行执行完,把全部响应拼成一个大 buffer,客户端一次
read()拿全,再按顺序拆给每个*redis.Cmd实例
整个过程:1 次 write + 1 次 read = 1 次 RTT,无论里面塞了 50 条还是 300 条命令。
别误以为 Pipeline 是并行或服务端优化
Redis 服务端仍是单线程顺序执行,Pipeline 不提升单命令速度,也不绕过命令排队逻辑。它只解决客户端“发得太碎”这个问题。
- 服务端
instantaneous_ops_per_sec指标会虚高——因为 1 秒内收到 1 个大包,但实际处理了 200 条命令 - 真正瓶颈若在服务端(比如 pipeline 里混了
KEYS *或SLOWLOG GET),整条 pipeline 会卡住,耗时暴涨 - 错误不会在
pip.Set()那一刻报,而是在pip.Exec(ctx)时统一返回连接级错误(如redis.Nil或connection refused),单条命令失败需查cmd.Err()
实测差异往往比理论更刺眼
在跨可用区部署下(如 client 在北京,Redis 在广州),单次 RTT ≈ 12ms:
- 100 次
client.Set():≈ 1200ms(纯等网) - 100 次塞进
pip.Exec():≈ 12ms + 服务端总执行时间(通常 - 吞吐直接从 ≈ 83 QPS 拉到 ≈ 6000+ QPS
注意:这个收益完全依赖你真调了 Exec(),且 pipeline 里没藏慢命令或语义冲突操作——否则省下的 RTT 全被阻塞吃掉。











