Redis中的Lua脚本是否是原子性操作?详解

news/2024/10/18 2:08:01/

1. Redis中的Lua脚本是原子性操作吗?

        在回答这个问题之前,我们首先要明确,Lua脚本中所指的原子性与我们通常意义上的原子性不一样

        我们通常所说的原子性是数据库中事务四大特性ACID(即原子性、一致性、隔离性、持久性)中的原子性,它是指一个事务中的所有操作要么全部成功执行,要么不执行。不执行的情况是指如果在事务执行的过程中,发生了异常或者死锁等,会将之前对数据库所做的全部操作撤销,将数据库的状态回滚到事务执行前的状态(具体原理可以了解一下MVCC)。而Lua脚本的原子性是指Redis在执行lua脚本的过程中将其视为一个不可分割的整体,在执行过程中不会被其他命令或请求打断,会严格按照脚本的流程顺序执行完毕。

1.1. Lua脚本的原子性与回滚

        我们都知道Redis是不支持事务回滚的,因为Redis的设计初衷就是简单、高效,常用作缓存,而要实现事务的回滚需要额外的机制和数据结果来保证(参考MySQL中的MVCC和数据项中的回滚指针及事务id),因此Redis不支持回滚Lua脚本是不仅支持原子性也支持回滚,即Lua脚本在执行过程中如果发生了异常,对于异常发生前已经执行的指令,会进行撤销,以此来实现回滚的效果。

        例如,假设有一个Lua脚本:

redis.call("SET", "key1", "value1")
local result = redis.call("INCR", "key2")
if result > 10 thenerror("Value too large!")  -- 触发异常
end
redis.call("SET", "key3", "value3")

如果 INCR key2返回的结果大于10,脚本会抛出异常,在这种情况下:

  • SET key1 "value1" 已经执行,但因为脚本中途抛出了异常,Redis 并不会将该操作实际应用到数据库中
  • 同样地,SET key3 "value3" 也不会被执行,因为脚本在之前就已经中止了。
  • 整个 Lua 脚本要么全部成功,要么在异常时所有的操作都不会生效

1.2. 为什么Lua脚本发生异常时,已修改的部分不会生效?

        当Lua脚本在执行过程中发生异常时,Redis会中止脚本的运行,并且确保已经执行的命令不会对Redis服务器中的数据产生任何影响,这是因为:Redis在Lua脚本执行期间会”预执行“所有命令。当Lua脚本调用Redis.call()来执行Redis命令时,这些命令实际上并没有立即作用到Redis数据库中,只有当整个脚本成功执行完毕后,Redis才会将这些命令应用到Redis数据库中。 如果脚本中途抛出异常,Redis 会抛弃脚本执行过程中产生的所有操作,而不会将任何结果写入数据库。因此Lua脚本能够支持回滚操纵。

1.3. Lua脚本原子性实现的技术原理

Redis通过以下机制来确保Lua脚本的原子性:

  • 单线程执行:由于Redis的网络I/O和键值对的读写操作是单线程的,Redis执行Lua脚本时,会把Lua脚本作为一个整体并把它当作一个任务加入到一个队列中,然后单线程按照队列的顺序依次执行这些任务,确保了Lua脚本从头到尾作为一个整体独立进行执行。
  • 延迟应用:Redis在执行Lua脚本时,所有的命令实际上并不会立即作用到数据库(区别于MySQL),而是”预执行“所有命令,将结果放入内部缓存中。当脚本全部成功执行完毕后,Redis会一次性将脚本中所有的命令结果应用到Redis数据库中,相反如果发生异常,则不会有任何命令结果被应用。

http://www.ppmy.cn/news/1538526.html

相关文章

Linux高阶——0928—Github数据上传markdown语言

1、Github三要素 仓库、提交、分支 提交 绿色:新加 红色:删除 主分支master或main 项目的存储单位——仓库 实际代码的存储单位——分支 分支的协同开发 2、本地数据上传到云端的过程 3、markdown

【SQL】三角形判断

目录 语法 需求 示例 分析 代码 语法 SELECT name, IF(salary > 5000, High, Low) AS salary_level FROM employees; SELECT 关键字用于指定要从表中选取哪些列。name 是employees表中的一个列名,代表员工的名字。IF(salary > 5000, High, Low) 是一个函…

Linux——传输层协议

目录 一再谈端口号 1端口号范围划分 2两个问题 3理解进程与端口号的关系 二UDP协议 1格式 2特点 3进一步理解 3.1关于UDP报头 3.2关于报文 4基于UDP的应用层协议 三TCP协议 1格式 2TCP基本通信 2.1关于可靠性 2.2TCP通信模式 3超时重传 4连接管理 4.1建立…

Apache DolphinScheduler社区9月进展记录

各位热爱 Apache DolphinScheduler 的小伙伴们,社区 9 月月报更新啦!这里将记录 Apache DolphinScheduler 社区每月的重要更新,欢迎关注! 月度 Merge Star 感谢以下小伙伴上个月为 Apache DolphinScheduler 做的精彩贡献&#x…

Redis配置篇 - 指定Redis配置的三种方式,以及Redis配置文件介绍

文章目录 1 指定Redis配置的三种方式1.1 通过命令行参数来指定Redis配置1.2 通过配置文件来指定Redis配置1.3 在服务器运行时更​​改 Redis 配置 2 关于Redis配置文件 1 指定Redis配置的三种方式 1.1 通过命令行参数来指定Redis配置 在redis启动时,可以直接通过命…

针对考研的C语言学习(循环队列-链表版本以及2019循环队列大题)

题目 【注】此版本严格按照数字版循环队列的写法,rear所代表的永远是空数据 图解 1.初始化部分和插入部分 2出队 3.分部代码解析 初始化 void init_cir_link_que(CirLinkQue& q) {q.rear q.front (LinkList)malloc(sizeof(LNode));q.front->next NULL…

FLINK SQLTable API 简介及运行环境

FLINK SQL&Table API 简介 Flink本身是批流统一的处理框架,所以Flink SQL和Table API是批流统一的上层处理API。目前,这两套API仍处于活跃的开发阶段,功能尚未完全完善。 Flink SQL Flink SQL:可以直接在代码中写SQL&#…

第五章:软件工程(5.3软件设计--5.4软件实现)

5.3 软件设计 5.3.1 结构化设计 结构化设计(StructuredDesign,SD)是一种面向数据流的方法,其目的 在于确定软件结构。它以SRS和SA阶段所产生的DFD和数据字典等文档为基础 是一个自顶向下、逐层分解、逐步求精和模块化的过程。 从管理角度讲分为&#…