当前位置: 首页 > news >正文

说一下redis事务底层原理

Redis事务

1. 事务的基本流程

Redis 事务通过 MULTIEXECWATCH 等命令实现,底层原理可以分为以下几个步骤:

(1) MULTI 命令
  • 当客户端发送 MULTI 命令时,Redis 会将客户端标记为“事务模式”。
  • 在事务模式下,客户端发送的所有命令不会立即执行,而是被放入一个队列(命令队列)中。
(2) 命令入队
  • MULTIEXEC 之间,客户端发送的所有命令都会被追加到事务队列中。
  • 这些命令不会立即执行,而是等待 EXEC 命令的触发。
(3) EXEC 命令
  • 当客户端发送 EXEC 命令时,Redis 会依次执行事务队列中的所有命令。
  • 执行过程中,所有命令是原子的,不会被其他客户端的命令打断。
(4) WATCH 命令
  • WATCH 命令用于实现乐观锁。
  • 当客户端对一个或多个键执行 WATCH 后,如果在 EXEC 执行之前,这些键被其他客户端修改,则当前事务会失败(返回 nil

watch我们可以指定监听一个键和多个键,然后exec批量执行

WATCH key [key ...]

2. 事务的原子性

  • Redis 事务的原子性是通过单线程模型实现的。
  • Redis 是单线程的,所有命令都是顺序执行的。在 EXEC 执行时,事务队列中的命令会连续执行,不会被其他客户端的命令打断。

3. 事务的一致性

  • Redis 事务的一致性是通过 WATCH 机制实现的。
  • 如果 WATCH 的键在事务执行期间被修改,事务会失败,从而保证数据的一致性。

4. 事务的局限性

  • 不支持回滚:如果事务中的某个命令失败,其他命令仍然会执行,Redis 不会自动回滚。
  • 部分失败问题:事务中的命令可能会部分成功、部分失败。
  • 性能开销WATCH 机制会增加额外的性能开销。

Redis 7 对事务的优化

Redis 7 在事务机制上并没有完全改变底层实现,但引入了一些优化和改进:

1. 性能优化

  • Redis 7 对事务的执行流程进行了优化,减少了事务模式下的性能开销。
  • 通过改进命令队列的处理方式,提高了事务的执行效率。

2. Lua 脚本的增强

  • Redis 7 对 Lua 脚本的支持进行了增强,使得 Lua 脚本可以更好地与事务结合使用。
  • Lua 脚本在 Redis 7 中的执行效率更高,同时支持更多的 Redis 命令。

3. 更好的错误处理

  • Redis 7 改进了事务中的错误处理机制,使得事务失败时的错误信息更加清晰。
  • 如果事务中的某个命令失败,Redis 7 会返回更详细的错误信息,方便排查问题。

4. 功能增强

  • Redis 7 引入了更多的命令和功能,可以与事务结合使用。
  • 例如,Redis 7 支持更多的数据类型和操作,使得事务可以处理更复杂的场景。

Redis 事务的底层实现细节

1. 命令队列

  • 在事务模式下,Redis 会为每个客户端维护一个命令队列。
  • 所有在 MULTIEXEC 之间发送的命令都会被追加到队列中。

2. 事务执行

  • EXEC 命令被触发时,Redis 会依次执行命令队列中的所有命令。
  • 执行过程中,Redis 会保证命令的原子性,不会被其他客户端的命令打断。

3. WATCH 机制

  • WATCH 命令会监视一个或多个键。
  • 如果在 EXEC 执行之前,这些键被其他客户端修改,则当前事务会失败。
  • WATCH 的实现基于 Redis 的键空间通知机制。

总结

  • Redis 事务的底层原理 是基于 MULTI/EXEC/WATCH 机制,通过命令队列和乐观锁实现原子性和一致性。
  • Redis 7 在事务机制上进行了性能优化和功能增强,但底层实现并没有本质变化。
  • Redis 事务的局限性 包括不支持回滚、部分失败问题和性能开销。
  • 如果需要更强大的事务支持,可以结合 Lua 脚本或使用支持 ACID 事务的数据库。

Redis+Lua脚本实现手动回滚补偿

我们每一步执行失败,我们就依次撤销前面的操作

可惜这个并不是真正的acid,我们的mysql执行事务的时候宕机了,它的事务没有提交所以数据并不会进到mysql里面

而redis是人为控制的,所以我们执行lua脚本的时候宕机了,我们之前事务中执行的操作数据仍然进去了,这个是我们无法解决的

local key1 = KEYS[1]
local key2 = KEYS[2]
local key3 = KEYS[3]
local value = ARGV[1]

-- 记录原始值
local original_value1 = redis.call('GET', key1)
local original_value2 = redis.call('GET', key2)
local original_value3 = redis.call('GET', key3)

-- 第一步操作
redis.call('SET', key1, value)

-- 第二步操作
if redis.call('EXISTS', key2) == 0 then
    -- 手动回滚第一步操作
    redis.call('SET', key1, original_value1)
    return "Key2 does not exist"
end
redis.call('SET', key2, value)

-- 第三步操作
if redis.call('EXISTS', key3) == 0 then
    -- 手动回滚前两步操作
    redis.call('SET', key1, original_value1)
    redis.call('SET', key2, original_value2)
    return "Key3 does not exist"
end
redis.call('SET', key3, value)

return "Transaction successful"

相关文章:

  • 【Vue CLI脚手架开发】——3.组件交互props配置
  • ANI AGI ASI的区别
  • 现在创业的风口有哪些?
  • 蓝桥杯备考:动态规划线性dp之传球游戏
  • Windows命令行的注释方式, powershell的注释 和 cmd的注释 笔记250303
  • 初识FPGA
  • 【前端跨域】CORS:跨域资源共享的机制与实现
  • python力扣3:无重复字符的最长子串
  • 通往 AI 之路:Python 机器学习入门-线性代数
  • ThreadLocal解析
  • 面试150,数组 / 字符串
  • PixelShuffle与Sub-pixel卷积详解
  • error Mixed spaces and tabs no-mixed-spaces-and-tabs
  • EtherNet/IP转Modbus解析基于网关模块的罗克韦尔PLC与Modbus上位机协议转换通讯案例
  • build gcc
  • 61. Three.js案例-彩色旋转立方体创建与材质应用
  • GPU/CUDA 发展编年史:从 3D 渲染到 AI 大模型时代(上)
  • wgcloud-server端部署说明
  • RK3568平台(网络篇)RTL8111网卡
  • 基于SpringBoot的“扶贫助农系统”的设计与实现(源码+数据库+文档+PPT)
  • 建设方案包括哪些内容/怎么做关键词优化排名
  • dw网站log怎么做/拉新推广怎么做代理
  • 网站自适应布局/永久免费的培训学校管理软件
  • 网站建设营业执照/最近一周新闻大事件
  • 建一个个人网站多少钱/seo外包优化公司
  • 个人手机版网站建设/百度账号快速登录