Redis 的指令执行方式:Pipeline、事务与 Lua 脚本的对比

news2025/4/22 16:07:32

Pipeline

客户端将多条命令打包发送,服务器顺序执行并一次性返回所有结果。可以减少网络往返延迟(RTT)以提升吞吐量。

需要注意的是,Pipeline 中的命令按顺序执行,但中间可能被其他客户端的命令打断

典型场景:批量插入、查询或更新数据,也就是命令间没有什么依赖关系的情况。

比如下面这个例子,Pipeline 将 3 个 SET 打包发送,减少三次网络往返为一次。假设单次命令 RTT 为 1ms,3 次命令需 3ms;使用 Pipeline 仅需约 1ms。

SET key1 value1
SET key2 value2
SET key3 value3

事务

可以确保一组命令“原子”执行,确保一组命令执行过程中不被其他客户端打断如果事务中有命令失败,整个事务不会回滚,但后续命令不会执行

通常,它会结合 WATCH 来实现乐观锁

另外,Redis 中的原子性和 MySQL 中的原子性意义不同。MySQL 的原子性意味着,要么全部执行成功,要么就不执行,它会涉及回滚的操作。但 Redis 没有没有回滚的操作(为了性能,实现回滚需要维护事务日志等其他一些机制,会增加开销),它的原子性指,一组命令顺序执行,不会被其他命令打断。

还有,Redis 的事务并不会像 Pipeline 一样,将命令一起发送给 Redis,而是会一条一条发送。为什么?可以结合下面的过程,这样的话可以用来进行语法检查。

客户端发送 MULTI,开启事务。
客户端逐条发送命令(如 SET、INCR),每条命令立即传输到服务器。
服务器收到命令后,不执行,而是将其放入事务队列,并返回 QUEUED 响应。
客户端发送 EXEC,服务器原子性执行队列中的所有命令,并返回结果。
或者,客户端发送 DISCARD,清空队列,取消事务。

在实际使用中,比如在 Python 中的 redis-py 库,事务会以 Pipeline 的方式批量发送,来优化命令发送。

pipe = r.pipeline()  # 创建 Pipeline
pipe.multi()  # 开始事务
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.execute()  # 发送并执行事务

典型场景:需要保证数据一致性的操作,如转账、库存扣减。

WATCH accountA  -- 监控账户 A 的键,防止被其他客户端修改
MULTI
GET accountA -- 如果账户 A 的值发生改变,剩下的命令将不会执行
SET accountA $new_balanceA -- 更新账户 A 余额(减 100)
SET accountB $new_balanceB -- 更新账户 B 余额(加 100)
EXEC

Lua 脚本

Lua 脚本可以在一条命令中实现复杂逻辑,如条件判断、循环、错误控制。它和事务功能上有些相似,都是为了实现原子性。不过 Lua 脚本有两种选择,redis.call() 失败时脚本停止(前面已经执行完的命令不会受影响);redis.pcall() 捕获错误继续执行。

它比起事务有什么好处呢?

  • 比如事务中需要依赖于一个 GET 操作的结果,来决定后面的操作,事务无法实现,需要结合客户端的代码,加大了复杂性
  • 事务中的每条命令都会与 Redis 服务器进行网络交互,增加了客户端与服务器的交互

另外,为了避免每次都需要传输完整的 Lua 脚本给 Redis,Redis 还设立了一个缓冲区,来去存放 Lua 脚本的内容以及它的 SHA1 值(一种哈希算法,将 Lua 脚本内容映射为固定长度的唯一标识符)。之后只需传输对应的 SHA1 值即可执行对应的脚本。

总之,Lua 脚本会更灵活,事务能做的,Lua 都能做。所以能用 Lua 就用 Lua

典型场景:需要保证数据一致性的操作,如转账、库存扣减。和事务差不多。

local accountA = KEYS[1]    -- 账户 A 的键
local accountB = KEYS[2]    -- 账户 B 的键
local amount = tonumber(ARGV[1])  -- 转账金额(转换为数字)

-- 获取账户 A 余额(不存在则默认为 0)
local balanceA = redis.call('GET', accountA) or 0
balanceA = tonumber(balanceA)

-- 检查余额是否足够
if balanceA < amount then
    return 0  -- 余额不足,返回 0
end

-- 获取账户 B 余额(不存在则默认为 0)
local balanceB = redis.call('GET', accountB) or 0
balanceB = tonumber(balanceB)

-- 执行转账
redis.call('SET', accountA, balanceA - amount)  -- 扣减账户 A
redis.call('SET', accountB, balanceB + amount)  -- 增加账户 B

return 1  -- 转账成功,返回 1


-- Redis 调用方式:
EVAL "local accountA = KEYS[1] local accountB = KEYS[2] local amount = tonumber(ARGV[1]) local balanceA = redis.call('GET', accountA) or 0 balanceA = tonumber(balanceA) if balanceA < amount then return 0 end local balanceB = redis.call('GET', accountB) or 0 balanceB = tonumber(balanceB) redis.call('SET', accountA, balanceA - amount) redis.call('SET', accountB, balanceB + amount) return 1" 2 accountA accountB 30

参考

  1. Redis 事务 vs Lua,区别以及如何选择
  2. 【Redis】- 事务和Lua脚本
  3. Redis 管道、事务、Lua 脚本对比

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速搭建 Cpolar 内网穿透(Mac 系统)

1、Cpolar快速入门教程&#xff08;官方&#xff09; 链接地址&#xff1a;Cpolar 快速入门 2、官方教程详解 本地安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"这个是从 git 上拉取的&#x…

动态监控进程

1.介绍: top和ps命令很相似,它们都是用来显示正在执行的进程,top和ps最大的不同之处,在于top在执行中可以更新正在执行的进程. 2.基本语法&#xff1a; top [选项] 选项说明 ⭐️僵死进程&#xff1a;内存没有释放,但是进程已经停止工作了,需要及时清理 交互操作说明 应用案…

HADOOP 3.4.1安装和搭建(尚硅谷版~)

目录 1.配置模版虚拟机 2.克隆虚拟机 3.在hadoop102安装JDK 4.完全分布式运行模式 1.配置模版虚拟机 1.安装模板虚拟机&#xff0c;IP地址192.168.10.100、主机名称hadoop100、内存2G、硬盘20G&#xff08;有需求的可以配置4G内存&#xff0c;50G硬盘&#xff09; 2.hado…

第 4 篇:平稳性 - 时间序列分析的基石

第 4 篇&#xff1a;平稳性 - 时间序列分析的基石 在上一篇中&#xff0c;我们学习了如何将时间序列分解为趋势、季节性和残差。我们看到&#xff0c;很多真实世界的时间序列&#xff08;比如 CO2 浓度&#xff09;都包含明显的趋势&#xff08;长期向上或向下&#xff09;和/…

DeepSeek赋能Nuclei:打造网络安全检测的“超级助手”

引言 各位少侠&#xff0c;周末快乐&#xff0c;幸会幸会&#xff01; 今天唠一个超酷的技术组合——用AI大模型给Nuclei开挂&#xff0c;提升漏洞检测能力&#xff01; 想象一下&#xff0c;当出现新漏洞时&#xff0c;少侠们经常需要根据Nuclei模板&#xff0c;手动扒漏洞文章…

从0到1彻底掌握Trae:手把手带你实战开发AI Chatbot,提升开发效率的必备指南!

我正在参加Trae「超级体验官」创意实践征文&#xff0c; 本文所使用的 Trae 免费下载链接&#xff1a; www.trae.ai/?utm_source… 前言 大家好&#xff0c;我是小Q&#xff0c;字节跳动近期推出了一款 AI IDE—— Trae&#xff0c;由国人团队开发&#xff0c;并且限时免费体…

opencv图片颜色识别,颜色的替换

图片颜色识别 1. RGB颜色空间2. 颜色加法2.1使用numpy对图像进行加法2.2使用opencv加法&#xff08;cv2.add&#xff09; 3 颜色加权加法&#xff08;cv2.addWeighted()&#xff09;4. HSV颜色空间5. 制作掩膜4. 与运算&#xff08;cv2.bitwise_and&#xff09;5.颜色的替换7 R…

B实验-12

需要注意版本、页面源代码 两个文件一个目录&#xff1a;phpinfo robots phpmyadmin 实验12 靶机1 一个key在phpmyadmin&#xff0c;一个key在回收站 用两个扫描目录的工具扫&#xff0c;nmap给python版 情况1&#xff1a;弱口令 root root root 123456 …

【网工第6版】第5章 网络互联②

目录 ■ IPV6 ▲ IPV6报文格式 ◎ IPV6扩展报头&#xff08;RFC2460&#xff09; ◎ IPv6相关协议 ▲ IPV6地址分类 ◎ IPv6地址基础 ◎ IPv6地址举例 ◎ IPv6地址分类 ◎ 特殊地址对比IPv4 vs IPv6 ▲ 过渡技术 本章重要程度&#xff1a;☆☆☆☆☆ ■ IPV6 与IPv4…

单页面应用的特点,什么是路由,VueRouter的下载,安装和使用,路由的封装抽离,声明式导航的介绍和使用

文章目录 一.什么是单页面应用?二.什么是路由?生活中的路由和Vue中的路由 三.VueRouter(重点)0.引出1.介绍2.下载与使用(5个基本步骤2个核心步骤)2.1 五个基本步骤2.2 两个核心步骤 四.路由的封装抽离五.声明式导航1.导航链接特点一:能跳转特点二:能高亮 2.两个高亮类名2.1.区…

STM32---外部中断EXTI

目录 一、中断向量表 二、EXTI工作原理图 三、NVIC模块 四、GPIO设置为EXTI的结构 五、C语言示例代码 在STM32中&#xff0c;中断是一个非常重要的结构&#xff0c;他能让我们在执行主函数的时候&#xff0c;由硬件检测一些外部或内部产生的中断信号&#xff0c;跳转到中断…

Itext进行PDF的编辑开发

这周写了一周的需求&#xff0c;是制作一个PDF生成功能&#xff0c;其中用到了Itext来制作PDF的视觉效果。其中一些功能不是很懂&#xff0c;仅作记录&#xff0c;若要学习请仔细甄别正确与否。 开始之前&#xff0c;我还是想说&#xff0c;这傻福需求怎么想出来的&#xff0c…

Hibernate的组件映射

在实际的开发中,使用的是非常多的&#xff0c;还有几种比较特殊的关系映射: 组件映射继承映射 先看一下组件映射: 组件映射中, 组件也是一个类, 但是这个类它不独立称为一个实体, 也就是说, 数据库中没有一个表格单独的和它对应, 具体情况呢, 看演示&#xff1a;

C++ 操作符重载Operator

C可以重载大多数操作符&#xff0c;如算术运算符号&#xff0c;-号。 位操作符<<,>> 下标符号[]等都可以重载。 重载的意思&#xff0c;是让这些符号&#xff0c;按你定义的行为来执行代码&#xff0c;但是这种自定义&#xff0c;是有限制的&#xff0c;必须有一…

Docker 镜像、容器和 Docker Compose的区别

前言&#xff1a;Docker 的镜像、容器和 Docker Compose 是容器化技术的核心组件&#xff0c;以下是对它们的详细解析及使用场景说明。 ​​1、Docker 镜像&#xff08;Image&#xff09;​​ ​​定义​​&#xff1a; 镜像是只读模板&#xff0c;包含运行应用程序所需的代码、…

Linux深度探索:进程管理与系统架构

1.冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是由⼀个个的硬件组件组成。 输入设备&#xff1a;键盘&#xff0c;鼠标…

一段式端到端自动驾驶:VAD:Vectorized Scene Representation for Efficient Autonomous Driving

论文地址&#xff1a;https://github.com/hustvl/VAD 代码地址&#xff1a;https://arxiv.org/pdf/2303.12077 1. 摘要 自动驾驶需要对周围环境进行全面理解&#xff0c;以实现可靠的轨迹规划。以往的方法依赖于密集的栅格化场景表示&#xff08;如&#xff1a;占据图、语义…

4月21日星期一今日早报简报微语报早读

4月21日星期一&#xff0c;农历三月廿四&#xff0c;早报#微语早读。 1、女子伸腿阻止列车关门等待同行人员&#xff0c;被深圳铁路警方行政拘留&#xff1b; 2、北理工再通报&#xff1a;开除宫某党籍&#xff0c;免去行政职务&#xff0c;解除聘用关系&#xff1b; 3、澳门…

Kubeflow 快速入门实战(二) - Pipelines / Katib / KServer

承接前文博客 Kubeflow 快速入门实战(一) Kubeflow 快速入门实战(一) - 简介 / Notebooks-CSDN博客文章浏览阅读441次&#xff0c;点赞19次&#xff0c;收藏6次。本文主要介绍了 Kubeflow 的主要功能和能力&#xff0c;适用场景&#xff0c;基本用法。以及Notebook&#xff0c…

【JavaEE初阶】多线程重点知识以及常考的面试题-多线程进阶(一)

本篇博客给大家带来的是多线程中常见的所策略和CAS知识点. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; 要开心要快…