Redis Pipeline 与 Lua:减少网络往返和保证原子性是两回事
假设下单时需要在 Redis 里做三件事:读取库存、判断是否足够、扣减库存。 第一次写这段逻辑,很容易想到 Pipeline:把几条命令一次发给 Redis,既然它们挨在一起执行,是不是就不会被其他请求插进来了? 答案是否定的。 Pipeline 解决的是网络往返太多,Lua 脚本解决的才是多步逻辑不能被其他命令打断。两者都能让客户端“一次请求完成多件事”,但它们处理的是完全不同的问题。 理解这一区别之后,Redis 里很多看似相近的概念都会顺起来:为什么批量写缓存适合 Pipeline,为什么扣库存适合 Lua,为什么事务和 Pipeline 经常同时出现在客户端 API 里,以及“Lua 是原子的”到底原子到什么程度。 先用一张表分清四种工具 工具 主要解决什么 多条命令会不会被其他客户端插入 能否根据中间结果继续判断 Pipeline 减少 RTT,提高吞吐 不保证 不适合 MULTI/EXEC 原子执行一组已经确定的命令 不会 很弱,命令只是先排队 WATCH + MULTI/EXEC 乐观锁与条件更新 提交后不会,冲突时提交失败 可以,但通常需要重试 Lua 脚本 在服务端完成读、计算、写 不会 可以 还有一个经常被忽略的选择:如果 Redis 已经有单条命令能完成需求,优先用单条命令。例如计数用 INCRBY,不存在才写入用 SET ... NX。单命令通常比自己拼事务或 Lua 更简单,也天然具有原子性。 Pipeline 为什么快:它省掉的是 RTT 客户端执行一条 Redis 命令,大致要经历下面这段路: 客户端发送命令 -> 网络传到 Redis -> Redis 执行命令 -> 结果通过网络返回 -> 客户端收到结果 如果依次执行 100 条命令,客户端通常要等待 100 次网络往返。即使命令本身只执行几十微秒,网络等待也可能占掉大部分时间。 ...