文章目录
一、主要解决的问题
(1) Lua 脚本
主要解决多个命令执行时的原子性问题,确保全部成功或全部失败。
使用 Lua 时,可以将多个命令打包到一个 Lua 脚本中,一次性执行,来实现原子性。
多个命令:往往是几个,几十个,几百个的量级
(2) Pipeline(管道)
主要解决执行大批量命令时,消耗过多网络资源的问题。
使用 Pipeline 时,可以将多个命令打包到一个 Pipeline 管道中,减少执行大量命令时每次都需要的网络开销,提高效率。
大量批命令:往往是几百,几千,几万的量级
二、相同点
Lua 和 Pipeline 也有一些相同点:
- 批量操作 :都支持将多个 Redis 命令组合在一起执行
- 性能优化 :两者都用于减少网络往返时间(RTT),提高 Redis 操作的性能
- 减少网络开销 :通过减少客户端与服务器之间的通信次数来提升效率
- 顺序执行 :多个命令是按顺序执行
三、区别
| 对比维度 | Lua 脚本(EVAL/EVALSHA) | Pipeline(管道) |
|---|---|---|
| 执行位置 | 在 Redis 服务端执行(Lua 引擎) | 客户端打包发送,服务端逐条执行 |
| 原子性 | ✅ 是,全部成功或失败 | ❌ 否,可能部分成功,部分失败 |
| 是否独占资源 | ✅ 是,Redis 会阻塞其他所有客户端请求,保证脚本内所有操作不可分割 | ❌ 否,命令按序执行,但执行过程中可能被其他命令"插队" |
| 阻塞风险 | 复杂脚本可能长时间阻塞 Redis 单线程 | 只是减少 RTT,不会额外阻塞 |
| 性能瓶颈 | 脚本过长会阻塞 Redis 线程,导致其他请求处于等待状态 | 性能极高,适合大量无依赖命令批量处理,其他请求可能穿插执行 |
| 错误处理 | redis.call() 出错会中断脚本;redis.pcall() 可捕获错误继续执行 | 某条命令失败不影响后续命令执行(无事务回滚) |
| 网络开销 | 脚本内容需传输一次(可用 SCRIPT LOAD + EVALSHA 缓存 SHA1 避免重复传输) | 多条命令合并为一次 TCP 请求,减少 RTT |
| 逻辑复杂性 | 是,支持复杂逻辑:条件判断、循环、局部变量等完整编程能力,可以调用 Lua 函数 | 否,只是简单的命令堆叠,仅支持命令批量发送,无逻辑控制能力 |
四、使用场景
使用时,主要取决于业务场景
(1) Lua 脚本
需要原子性(全部成功或失败)或逻辑判断时,使用 Lua 脚本。常见场景有:
- 分布式锁
- 库存扣减
- 订单创建
- 用户注册
- 限流(令牌桶/计数器)
- 转账(一个扣款 → 另一个加款)
(2) Pipeline
需要大批量执行命令,命令之间无依赖,减小网络开销,使用 Pipeline。常见场景有:
- 批量查询、更新、删除(如:10万条商品数据写入 Redis,商品数据之间无需原子操作)
- 初始化缓存
- 日志/埋点数据上报
五、注意事项
Lua 脚本
避免在 Lua 中进行大量计算,Redis 是单线程的- 脚本执行时间不宜过长(建议 < 100ms)
- 使用SCRIPT KILL可以终止长时间运行的脚本(除非脚本修改了数据)
Pipeline
合理设置批量大小,过大会增加内存使用和延迟- 注意 Redis 服务器的输出缓冲区限制
- 考虑使用
异步或非阻塞方式处理 Pipeline 结果