Redis Pipeline(管道):原理与最佳实践
前言
Redis Pipeline(管道)是 Redis 中一种网络通信优化技术,它的核心思想是:
一次性发送多条命令,Redis 依次执行,然后再一次性返回所有结果。
这样可以显著减少客户端与 Redis 之间的网络往返(RTT,Round Trip Time)开销。
一、为什么会有 Pipeline
先看普通 Redis 请求。假设执行 4 条命令:
SET name tom
GET name
INCR counter
GET counter
正常情况下:
Client Redis
SET name tom ------->
执行
<------- OK
GET name ------->
执行
<------- tom
INCR counter ------->
执行
<------- 1
GET counter ------->
执行
<------- 1
需要 4 次请求、4 次响应、4 次 RTT。如果 RTT 是 0.5ms,那么总耗时 ≈ 4 × 0.5ms = 2ms。
假设有 10000 个命令,就是 10000 次 RTT。即使 Redis 本身执行只需几毫秒,网络时间 » Redis 执行时间,性能浪费严重。
二、Pipeline 的工作方式
Pipeline 出现后,客户端把命令一起发送:
Client ------------------------>
Redis
SET name tom
GET name
INCR counter
GET counter
Redis 收到后按顺序执行(SET → GET → INCR → GET),执行完再统一返回:
<------------------------
OK
tom
1
1
整个过程只有 1 次发送、1 次接收、1 次 RTT。
可以这样理解:
- 普通模式:问一句、答一句,像聊天。
- Pipeline:一次问 100 句,Redis 全部回答,像发邮件。
三、Pipeline 的本质
很多人误解:Pipeline 能让 Redis 并行执行命令。实际上不是——Redis 仍然是单线程执行命令:
SET a 1
SET b 2
SET c 3
Redis 内部仍然依次执行 SET a → SET b → SET c,没有并行。
Pipeline 优化的是网络往返时间(Network RTT),而不是命令执行时间。
四、Pipeline 执行流程
以 5 条命令为例:
- 编码:客户端把所有命令编码(
*3、$3、SET…)形成一个大 Buffer。 - 发送:一次
write()(send(socket))发送给 Redis。 - 接收:Redis 从 socket buffer 收到 cmd1~cmd5。
- 解析执行:Redis 逐个解析并执行:
解析 cmd1 → 执行
解析 cmd2 → 执行
解析 cmd3 → 执行
...
- 缓冲结果:结果写入返回缓冲区(result1~result5)。
- 统一返回:一次返回给客户端,客户端再按顺序读取结果。
五、Pipeline 为什么快
举例:每次网络 RTT 为 0.2ms,Redis 执行一条命令 0.01ms,执行 10000 次 GET:
- 普通模式:
10000 × (0.2 + 0.01) ≈ 2100 ms - Pipeline:
1 × RTT + 10000 × 0.01 ≈ 100 ms
性能提升 20 倍以上,甚至 50 倍、100 倍都很常见。
六、Pipeline 与 MGET 的区别
GET key1
GET key2
GET key3
为什么不用 MGET?
- MGET:服务器命令优化,一次命令完成多个读取。
- Pipeline:客户端网络优化,一次发送多个命令。
例如下面这些命令类型不同,MGET 做不到,但 Pipeline 可以:
GET user:1
HGET user:2 name
ZSCORE rank 100
七、Pipeline 与事务(Transaction)的区别
Pipeline 只是一起发送,例如:
SET a 1
INCR a
GET a
Redis 依次执行 SET、INCR、GET,中间可能被别的客户端插入命令。
而事务:
MULTI
SET a 1
INCR a
GET a
EXEC
Redis 保证 EXEC 后整个命令队列连续执行,不会被其他客户端打断。
| 特性 | Pipeline | Transaction |
|---|---|---|
| 减少 RTT | ✅ | ❌ |
| 原子性 | ❌ | ✅ |
| 提升吞吐量 | ✅ | 一般 |
| 防止插队 | ❌ | ✅ |
八、Pipeline 是否保证顺序
保证。例如:
SET a 1
INCR a
GET a
Pipeline 发送后,Redis 执行顺序一定是 SET → INCR → GET,返回结果 result1、result2、result3 也严格对应。
九、Pipeline 的缺点
1. 响应占用内存
假设 100 万条 GET,Redis 要缓存 100 万个结果才能统一返回,可能导致内存暴涨。所以通常按 100、500、1000、5000 一批,不要 100 万一批。
2. 无法实时拿结果
GET a
如果结果出来后才能决定:
SET b xxx
这种依赖关系不能 Pipeline,因为结果还没回来。
3. 某条命令失败不会回滚
SET a 1
INCR a
LPUSH a x
第三条报 WRONGTYPE 错误,但前两条已经执行成功,不会回滚。
十、Pipeline 最佳实践
批量写适合 Pipeline:
SET user:1 ...
SET user:2 ...
SET user:3 ...
批量删适合 Pipeline:
DEL key1
DEL key2
DEL key3
批量缓存预热非常适合:
SET product:1 ...
SET product:2 ...
SET product:3 ...
批量查询也适合:
GET key1
GET key2
GET key3
十一、总结
Pipeline 是 Redis 提供的一种网络优化机制。客户端可以一次性向 Redis 发送多条命令,而不必等待每条命令的返回结果,Redis 按顺序执行这些命令后再批量返回结果。Pipeline 不会让 Redis 并行执行命令,也不保证原子性,它优化的是客户端与 Redis 之间的网络往返时间(RTT),因此在批量读写场景下可以显著提升吞吐量。实际生产中通常按几百到几千条命令分批使用 Pipeline,以避免响应结果过大导致内存压力。
一句话记忆:
Pipeline = Redis单线程不变
+ 批量发送命令
+ 减少RTT
+ 提高吞吐量