Pipeline 批量操作

一句话总结

Pipeline = 把 N 条 Redis 命令攒在一趟发过去,原来 N 次网络往返变成 1 次。跟拼车一个道理——十个人各打一辆车 vs 十个人打一辆大巴,路程一样,但车费(网络开销)省了 90%。


🌰 先搞懂问题在哪

想象你点外卖

 
没有 Pipeline:
 
  你:"老板,一份炒饭"
 
  老板:"好"  ← 把饭端出来
 
  你:"再加一份汤"
 
  老板:"好"  ← 又端汤出来
 
  你:"再加个蛋"
 
  老板:"好"  ← 又端蛋出来
 
  每加一个菜→等老板回应→再加→再等
 
  时间全花在"来回走"上,不是做饭上 ❌
 
Pipeline:
 
  你:"老板,炒饭+汤+蛋,一起上"
 
  老板一起做完,一次端出来 ✅
 

网络也是一样:每次发命令→等 Redis 回复→再发→再等。Pipeline 就是让 Redis 一次收一整串,你等一次就行。

快递员送货的比喻

 
你是快递员(客户端),仓库是 Redis。
 
没有 Pipeline:
 
  送一件货 → 回仓库拿下一件 → 再送 → 再回
 
  10 件货 = 10 趟
 
有 Pipeline:
 
  一次装上 10 件货 → 挨个送完 → 回仓库
 
  10 件货 = 1 趟
 
Pipeline 不减少"送货"本身的时间,
 
省的是"来回跑"的时间。
 

Pipeline 省了什么,没省什么

 
省了啥?
 
  └─ 客户端 ⇄ Redis 之间来回跑的时间(网络往返)
 
  └─ 每次命令的打包解包开销
 
没省啥?
 
  └─ Redis 执行命令本身的时间(该 1ms 还是 1ms)
 
  └─ 命令的复杂度(查询大 key 还是慢)
 
一句话:Pipeline 解决的是"距离"问题,不是"速度"问题。
 

核心思想:攒够了再发


sequenceDiagram

    participant C as 客户端

    participant R as Redis

    Note over C,R: 正常情况: 3 次 RTT

    C->>R: set a 1

    R-->>C: OK

    C->>R: set b 2

    R-->>C: OK

    C->>R: set c 3

    R-->>C: OK

    Note over C,R: Pipeline: 1 次 RTT

    C->>R: set a 1,set b 2,set c 3

    R-->>C: OK,OK,OK

Pipeline 的原理就这么简单:不等到回复就发下一条,最后一起收所有回复。


Pipeline 不是事务(最高频考点)

这是最喜欢挖坑的地方:

 
Pipeline 只是把命令攒在一起发。
 
到了 Redis 那边,还是逐条执行的。
 
比如你发了:SET a 1, SET b 2, GET c, DEL d
 
Redis 收到的顺序:
 
① SET a 1 ✓
 
② SET b 2 ✓
 
③ GET c → 返回 c 的值
 
④ DEL d ✓
 
如果第③条 c 不存在,Redis 只是返回 nil。
 
第④条照样执行,不会回滚。
 

Pipeline = 一车拉过去,挨个执行,互不影响。

事务 = 要么全做,要么全不做。

对比Pipeline事务(MULTI/EXEC)
原子性❌ 中间失败,后面的继续✅ 全部成功或全部放弃
网络优化✅ 减少往返❌ 不减少往返
回滚✅ DISCARD
场景批量操作、省网络需要原子性的场景

实际用多少条一批合适

 
少了没意义:
 
  攒 2~3 条 → 省不了啥网络开销,不如直接发
 
多了也会出事:
 
  一次性 Pipeline 100 万条 SET
 
  → 你的程序先要攒 100 万条命令在内存里
 
  → 网络一下子发一个大包
 
  → Redis 要处理完这 100 万条才能干别的
 
  → 你这 100 万条没处理完,其他请求全堵住了 ❌
 
经验值:500~1000 条一批比较稳妥。
 

Pipeline vs MSET/MGET

 
Redis 自带了一些"批量命令":
 
  MSET a 1 b 2 c 3    ← 一次设多个 key
 
  MGET a b c           ← 一次取多个 key
 
  DEL a b c            ← 一次删多个 key
 
这些命令比 Pipeline 还省——Pipeline 好歹发了 N 条命令,
 
MSET/MGET 是一条命令搞定。
 
能用 MSET/MGET 的场景,先用它。
 
那什么时候用 Pipeline?
 
  Pipeline 赢在"灵活":
 
    MSET 只能设,MGET 只能取。
 
    Pipeline 可以:先删、再读、再写、再删,各种混着来。
 
像一个购物清单:MSET 是"买 3 瓶水"(单一操作多次)。
 
Pipeline 是"买水、退衣服、问价格、买面包"(杂七杂八一起搞)。
 

一句话讲清

 
延伸提问:"Redis Pipeline 是什么?"
 
你:
 
"Pipeline 就是批量发命令,减少网络往返。
 
正常一条命令一次网络往返,Pipeline 把 N 条攒一起,
 
一次发过去,一次收所有回复。
 
比如你内网延迟 1ms,发 1000 条命令:
 
  不用 Pipeline → 1ms × 1000 = 1 秒花在路上
 
  用 Pipeline → 分两批,每批 500 条 → 2ms
 
注意 Pipeline 不是事务。
 
它只是省了网络时间,原子性不保证。
 
中间某条失败,后面的照样执行。
 
要原子性得用 Lua 脚本或事务。"
 

记忆口诀

Pipeline = 攒一批发一趟,省的是来回跑的时间,不是干活的时间。

Pipeline 不是事务——命令到了 Redis 还是逐条执行,中间失败不回滚。

500~1000 条一批,少了省不了多少,多了撑爆内存堵住 Redis。

MSET/MGET 比 Pipeline 还省——同样批量,命令数量也更少。但 Pipeline 更灵活,什么操作都能混着来。

速记卡(面试闪卡)

Q1:一句话讲清「Pipeline 批量操作」到底是什么?

A:Pipeline 是把 N 条 Redis 命令攒一车发过去:N 次网络往返变 1 次,省的是跑腿时间不是干活时间。

Q2:它到底省了什么、没省什么 —— 怎么理解?

A:像快递员送货:没 Pipeline 是一件件跑仓库(10 件=10 趟),有 Pipeline 是一次装车挨个送(10 件=1 趟),省的是来回跑的路费(网络 RTT)。但 Redis 执行每条命令本身的耗时一点没少——它解决的是”距离”问题,不是”速度”问题。命令复杂或大 key 该慢还是慢。

Q3:Pipeline 不是事务 —— 怎么理解?

A:Pipeline 像一车货拉过去挨个卸,谁坏谁坏、互不影响;事务(Transaction,MULTI/EXEC)像”要么全做要么全不做”的打包契约。中间某条失败(比如 GET 一个不存在的 key 返回 nil),后面的照样执行、不回滚。要原子性得用 Lua 脚本或真正的事务。

Q4:一批攒多少条合适 —— 怎么理解?

A:太少没意义(攒 2-3 条不如直接发),太多会爆——程序得先在内存里攒 100 万条命令,网络一下甩个大包,Redis 处理完这 100 万条前别的请求全堵死。经验值 500~1000 条一批最稳,兼顾省网络又不撑爆内存。

Q5:和 MSET/MGET 怎么选 —— 怎么理解?

A:MSET/MGET 是”一条命令买三瓶水”(单一操作批量),比 Pipeline(发三条命令)还省。能用 MSET/MGET 先用它。但 Pipeline 赢在”灵活”:MSET 只能设、MGET 只能取,Pipeline 能”删了再读再写再删”各种混着来——像购物清单里买水、退衣服、问价一起办。

Q6:核心速记主线有哪些?

  • Pipeline 攒一批发一趟,省网络往返不省执行

  • 不是事务,中间失败不回滚

  • 500~1000 条一批,少了没用多了堵

  • MSET/MGET 更省,但 Pipeline 更灵活

口诀

A:Pipeline 攒一车,省的是跑腿不干活

不是事务不回滚,中间失败照样过

五百一千一批稳,太多撑爆内存破

MSET MGET 更省,灵活还数 Pipeline 多

相关链接