pipeline需显式调用exec()才发送,否则命令静默丢失;每条命令结果需通过对应cmd的result()/val()获取并检查cmd.err();集群下须按slot路由到指定节点执行。

直接用 rdb.Pipeline(),但不调 Exec() 就等于没发
Pipeline 不是自动触发的魔法,它只是把命令攒在内存里等你拍板。你链了一堆 Set()、Get()、ZAdd(),如果最后没调 pip.Exec(ctx),Redis 根本收不到任何请求——程序也不会报错,数据就静默丢失了。
-
Exec()返回的是整批命令的聚合错误(比如网络断开),不是单条命令成败的判据 - 每个命令返回的
*redis.Cmd(如*redis.StringCmd)才是结果载体,得调它的.Result()或.Val()才能取值 - 别在
Exec()后就以为万事大吉;必须逐个检查cmd.Err(),因为部分命令可能语法错、key 不存在或类型不匹配,而 Pipeline 仍会继续执行后续命令
批量写用户、预热缓存、更新排行榜,这些场景才值得上 Pipeline
单次发 10 条以上独立命令,且彼此无依赖(比如不用 A 命令的返回值决定 B 命令的参数),就是 Pipeline 的甜点区。
- 缓存预热:微服务启动时塞几万条
user:1001、config:prod,用单条Set()会卡住启动流程,用 Pipeline 可压到 1–2 次 RTT - 排行榜批量写入:
ZAdd(ctx, "leaderboard", redis.Z{Member: "uid1", Score: 95})循环几十次,全塞进一个 Pipeline - 避免滥用:读 3 条数据、写 2 个字段这种量级,Pipeline 带来的收益远小于代码复杂度;不如老老实实用
MGET/MSET
集群环境下不能直接 Pipeline(),得先找节点再操作
Redis Cluster 不允许跨 slot 打包命令。你往 Pipeline 里塞 {user:123}:profile 和 {order:456}:meta,哪怕只差一个字符,也可能落在不同 slot,节点直接拒收。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 必须先算 slot:
clusterClient.KeySlot("{user:123}:profile") - 再查节点:
node := clusterClient.NodeForKey(slot)或遍历clusterClient.Nodes() - 最后在该
*redis.Client上调node.Pipeline()—— 此时它退化为单机行为 - 更省事的替代:优先用原生命令,比如批量读用
MGET、批量写用MSET,它们内部已做 slot 分发,比手撸 Pipeline 更稳
超时、错误、大 key —— 这三个坑最容易被忽略
很多人只关注“怎么发”,不关心“发崩了怎么办”。Pipeline 的失败模式和单条命令完全不同。
-
ctx超时对整批生效:设context.WithTimeout(ctx, 100ms),哪怕第 1 条命令卡住,后面所有都直接中断,不会重试 - 错误不是“全成功”或“全失败”:可能前 5 条 ok,第 6 条
ERR wrong number of arguments,第 7–10 条仍照常执行并返回结果;必须遍历每个cmd.Err() - 大 key 风险:单个 value >10KB,打包后请求体膨胀,可能触发 Redis 的
proto-max-bulk-len限制,或让客户端内存陡增;此时应拆批,比如每 50 条一组
真正难的不是写对 Pipeline(),而是想清楚哪条命令不该进 Pipeline、哪个错误该重试、超时时间该卡在哪一毫秒。这些判断没法靠文档抄,得看监控、压测、线上日志里反复校准。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










