欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > Redis中的Lua脚本是否是原子性操作?详解

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

2024/12/1 9:08:29 来源:https://blog.csdn.net/weixin_43287459/article/details/142886079  浏览:    关键词:Redis中的Lua脚本是否是原子性操作?详解

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数据库中,相反如果发生异常,则不会有任何命令结果被应用。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com