Pipeline能将N次RTT压至1次,因命令批量发送、服务端串行执行后一次性返回;但必须显式调Exec()才生效,且命令间不能有读写依赖,否则逻辑错误。

能减,但必须显式调用 Exec(),且不能混用依赖型命令——否则 RTT 没少,逻辑还错。
为什么 Pipeline 能压掉 99% 的 RTT
每次 client.Set() 或 client.Get() 都走一次 TCP 往返(RTT),100 条命令 = 100 次网络延迟。Pipeline 把它们攒成一个包发过去,Redis 串行执行完再一次性回结果,RTT 从 N 次压到 1 次。实测 1000 次 SET,吞吐翻 5 倍不稀奇。
但这只是网络层优化:服务端仍是单线程顺序执行,不并行;单条命令耗时没变,只是省了“等网”的时间。
go-redis/v9 中 Pipeline 的三步铁律
错一步,命令就不发、不执行、不报错——静默失效。
- 调
client.Pipeline()获取 pip 对象,别碰TxPipeline()(那是事务,更慢还易 OOM) - 所有命令链式调在 pip 上,比如
pip.Set(ctx, "k1", "v1", 0),返回的是*redis.StatusCmd等具体 cmd 实例 - 最后必须显式调
pip.Exec(ctx)—— 这才是真正发包的时刻;不调它,前面全白写
示例:
pip := client.Pipeline()
cmd1 := pip.Set(ctx, "user:1001", "alice", 0)
cmd2 := pip.Incr(ctx, "counter")
_, err := pip.Exec(ctx) // ← 关键!
if err != nil {
// 注意:err 是整个 pipeline 的执行错误(如连接断),不是单条命令错
}
val, _ := cmd1.Result() // 单条结果要从 cmd 实例里取
count, _ := cmd2.Result()
哪些命令组合能用 Pipeline,哪些会翻车
Pipeline 只保执行顺序,不保语义安全。适合批量、无依赖、key 不重叠的操作。
- 安全组合:
Set+HSet+LPush(不同 key、不同结构) - 危险组合:
Get("x")后立刻Set("x", result+1)(你拿不到Get结果去算,pipeline 内无法读写联动) - 完全禁用:
WATCH、EVAL、KEYS *(阻塞命令会让整条 pipeline 卡住)
有依赖逻辑?退回普通调用,或改用 TxPipelined() + Lua 脚本。
单次 Pipeline 控制多少条命令才合理
不是越多越好。过长 pipeline 会撑大响应体积、拖慢失败重试、还可能触发 Redis 的 client-output-buffer-limit(默认 256MB)导致连接被踢。
- 建议单次控制在 100–500 条之间
- 若平均响应体大(比如批量
HGETALL),往 100 条靠;若都是小SET,可上 500 - 监控
net_input_bytes和客户端耗时,比看instantaneous_ops_per_sec更准
真正卡住时,先查 pipeline 里有没有 SLOWLOG GET 或 SCAN 这类慢命令——它们本身就会把整条链拖死。











