Redis 事务机制之ACID属性

事务属性

事务是对数据库进行读写的一系列操作。在事务执行时提供ACID属性保证: 包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

  • 原子性(Atomicity): 事务中多个操作要么全部成功,要么全部失败。
  • 一致性(Consistency): 数据库中的数据在事务执行前后是一致的。
  • 隔离性(Isolation): 一个事务的执行不被其他事务影响。
  • 持久性(Durability):数据库执行事务后,数据的修改被持久化保存。

Redis 中的事务如何工作:

  • Redis 事务允许在一个步骤中执行一组命令,Redis提供了事务相关的命令: MULTI 、 EXEC、 DISCARD、WATCH。
  • Redis 事务做了两个重要的保证:
    1)事务中的所有命令都被序列化并按顺序执行。另一个客户端发送的请求永远不会在执行Redis事务的过程中被服务。这保证了命令作为单个隔离操作执行。
    2)EXEC命令触发事务中所有命令的执行,因此,如果客户机在调用EXEC命令之前在事务的上下文中失去与服务器的连接,则不会执行任何操作,相反,如果调用EXEC命令,则执行所有操作。

原子性(Atomicity)

Redis事务机制是否能够保证原子性? 在事务期间,可能会遇到两种命令错误:

  • 命令可能无法排队,因此在调用EXEC之前可能会出现错误。例如,该命令可能在语法上是错误的(参数数量错误,命令名称错误,…),或者使用不存在的命令,或者可能存在一些关键条件,如内存不足条件(如果服务器使用maxmemory指令配置了内存限制)。
# 开启事务
192.168.88.11:6380> multi
OK# 语法错误,redis不支持该命令
192.168.88.11:6380> sett key hello 
(error) ERR unknown command `sett`, with args beginning with: `key`, `hello`, # 正确命令,Redis命令入队
192.168.88.11:6380> incr counter 
QUEUED# 执行事务,因之前命令有错,事务无法执行
192.168.88.11:6380> exec
(error) EXECABORT Transaction discarded because of previous errors.# 键counter为空
192.168.88.11:6380> get counter
(nil)
  • 在调用EXEC之后,命令可能会失败,例如我们对具有错误值的键执行了操作(例如对字符串值调用列表操作)。即命令和操作的数据类型不匹配。但Redis实例并没有检查出错误。这种属于运行时错误,Redis在执行这些事务操作时就会报错。
    需要注意的是, 即使命令失败,队列中的所有其他命令也会被处理——Redis 不会停止命令的处理。
    需要注意的是, 即使命令失败,队列中的所有其他命令也会被处理——Redis 不会停止命令的处理。
    需要注意的是, 即使命令失败,队列中的所有其他命令也会被处理——Redis 不会停止命令的处理。
# 键 k1 为字符串类型
192.168.88.11:6380> type k1
string# k1 当前值为 hello 
192.168.88.11:6380> get k1
"hello"# 开启事务
192.168.88.11:6380> multi 
OK# 对 k1 字符串类型调用列表操作: LPUSH,此时并不报错
192.168.88.11:6380> LPUSH k1 1
QUEUED# 继续执行append操作
192.168.88.11:6380> APPEND k1 world
QUEUED# 执行事务,第一个操作报错,第二个操作正常执行
192.168.88.11:6380> exec
1) (error) WRONGTYPE Operation against a key holding the wrong kind of value
2) (integer) 10# k1 的傎已修改
192.168.88.11:6380> get k1
"helloworld"

Redis 不支持事务回滚,因为支持回滚会对 Redis 的简单性和性能产生重大影响。虽然 Redis 提供了 DISCARD 命令,DISCARD可用于中止事务。丢弃命令队列。 此时,不会执行任何命令,连接状态恢复正常。起不到回滚的效果。

DISCARD可用于中止事务。丢弃命令队列。不是回滚命令。
DISCARD可用于中止事务。丢弃命令队列。不是回滚命令。
DISCARD可用于中止事务。丢弃命令队列。不是回滚命令。

# 设置foo的值为1
192.168.88.11:6380> SET foo 1
OK# 开启事务
192.168.88.11:6380> MULTI
OK# 自增操作
192.168.88.11:6380> INCR foo
QUEUED# 执行DISCARD 命令,放弃事务
192.168.88.11:6380> DISCARD
OK# 再次读取foo值,值没有被修改
192.168.88.11:6380> GET foo
"1"
  • 如果在执行事务 EXEC 命令时,Redis实例或机器意外故障。导致事务执行失败。
    1)如果没有开启AOF,操作日志不会被记录,数据丢弃。
    2)如果有开启AOF,AOF 日志是仅追加日志,断电时也不会出现损坏问题。即使由于某种原因(磁盘已满或其他原因)日志以半写命令结束,redis-check-aof 工具也能够轻松修复它。

如果 AOF 被截断,该怎么办?
当 aof-load-truncated 启用时,AOF 中的最后一个命令可能会被截断。Redis 的最新主要版本无论如何都能够加载 AOF,只是丢弃文件中最后一个格式不正确的命令。在这种情况下,会有下面日志:此时事务操作不会再被执行,从而保证原子性。

2213:M 22 Feb 2024 14:40:08.204 # !!! Warning: short read while loading the AOF file !!!
2213:M 22 Feb 2024 14:40:08.204 # !!! Truncating the AOF at offset 237 !!!
2213:M 22 Feb 2024 14:40:08.204 # AOF loaded anyway because aof-load-truncated is enabled
2213:M 22 Feb 2024 14:40:08.204 * DB loaded from append only file: 0.000 seconds

当 aof-load-truncated 未启用时,Redis无法启动,会有下面的日志:

2302:M 22 Feb 2024 14:56:13.638 # Unexpected end of file reading the append only file. You can: 1) Make a backup of your AOF file, then use ./redis-check-aof --fix <filename>. 2) Alternatively you can set the 'aof-load-truncated' configuration option to yes and restart the server.

需要使用 redis-check-aof 工具修复AOF 日志文件,把未完成的事务操作从 AOF 文件中删除。通过AOF 恢复实例后,事务操作不会再被执行,保证了原子性。

执行以下步骤进行恢复:

root@ubuntu-x64_01:/data/redis/data# cp appendonly.aof appendonly.aof.bak 

制作 AOF 文件的备份副本。

使用Redis附带的redis-check-aof 工具修复原始文件:

root@ubuntu-x64_01:/data/redis/data# redis-check-aof --fix appendonly.aof
0x              f5: Expected to read 6 bytes, got 0 bytes
AOF analyzed: size=245, ok_up_to=166, diff=79
This will shrink the AOF from 245 bytes, with 79 bytes, to 166 bytes
Continue? [y/N]: y
Successfully truncated AOF

所以Redis对事务原子性属性不同场景下会不同。具体如下:
1)如果命令语法错误、在命令入队就报错,事务将无法执行,保证了原子性。
2)如果命令本身正确,命令入队成功。但实际执行时报错。无法保证原子性。
3)如果EXEC命令执行时实例故障。此时有开启AOF,可以保证原子性。

综合上面场景:
当命令入队时没报错,实际执行时报错,运行时错误。不能保证原子性!!!
当命令入队时没报错,实际执行时报错,运行时错误。不能保证原子性!!!
当命令入队时没报错,实际执行时报错,运行时错误。不能保证原子性!!!

在这里插入图片描述

一致性(Consistency)

事务的一致性要看具体场景,事务在执行时可能会有错误命令、参数数量错误、实例故障等因素影响。

1) 调用EXEC之前出现错误
即命令入队时报错,例如,该命令可能在语法上是错误的(参数数量错误,命令名称错误,…),或者使用不存在的命令。这种情况下,事务本身不会被执行,可以保证一致性。

在这里插入图片描述
2)调用EXEC之后出现错误
在调用EXEC之后,命令可能会失败,例如,由于我们对具有错误值的键执行了操作(例如对字符串值调用列表操作),在这种情况下,有错误的命令不会执行,正确的命令成功执行。不影响数据的一致性。

在这里插入图片描述

  1. 执行事务 EXEC 命令实例故障
    如果在执行事务 EXEC 命令时,Redis实例或机器意外故障。导致事务执行失败。要根据是否持久化分场景分析:
    3.1)如果没有持久化(即没开启RDB和AOF),无持久化无数据。数据是一致的。
    3.2)如果有RDB持久化,事务执行时RDB快照不会执行。数据是一致的。
    3.3)如果有AOF持久化,事务可能没被记录或记录不完整(使用Redis附带的redis-check-aof 工具修复原始文件),数据是一致的。

综合上面场景:
当命令语法错误、命令执行错误 或 Redis发生意外故障场景下。Redis事务机制对一致性属性有保证的。
在这里插入图片描述

隔离性(Isolation)

事务是在EXEC命令后才能真正执行,EXEC命令之前,命令会先进入队列。 分两种场景来分析:

1)调用EXEC之前

事务在 EXEC 命令前执行,命令操作是暂存在命令队列,并没有真正执行,此时。隔离性使用 WATCH 机制来实现保证 。

WATCH用于为 Redis 事务提供检查和设置 (CAS) 行为。

监视键是为了检测针对它们的更改。如果在执行EXEC命令之前至少修改了一个被监视的键,那么整个事务将终止,EXEC将返回一个Null应答来通知事务失败。

比如,我们要对键 foo 加 10 操作:

只有当我们有一个客户端在给定时间内执行操作时,这才会可靠地工作。如果多个客户端同时尝试增加键,就会出现竞争条件。例如,客户端A和B将读取旧值,例如:1。两个客户端都将该值增加到11,并最终设置为键的值。所以最后的值是11而不是21。
在这里插入图片描述

此时,我们需要使用WATCH命令来确保检测旧值没有其它客户端修改过,如果修改了,存在竞争条件,在调用WATCH和调用EXEC之间的时间内,另一个客户端修改了val的结果,则事务将失败。否则事务就能正常执行。

我们只需要重复这个操作,希望这次不会出现新的竞争。这种形式的锁定称为乐观锁定。在许多用例中,多个客户端将访问不同的键,因此不太可能发生冲突,通常不需要重复操作。

# 客户端1 
192.168.88.11:6380> CLIENT ID
(integer) 13192.168.88.11:6380> set key "java"
OK192.168.88.11:6380> watch key 
OK
192.168.88.11:6380> multi
OK192.168.88.11:6380> append key go
QUEUED
192.168.88.11:6380> exec
(nil)192.168.88.11:6380> get key 
"javapython"# -----------------------------------------------# 客户端 2 
192.168.88.11:6380> CLIENT ID
(integer) 14# 此步骤在 客户1 开启事务后 执行 
192.168.88.11:6380> append key python
(integer) 10192.168.88.11:6380> get key 
"javapython"

在这里插入图片描述

2)调用EXEC之后

因为Redis主线程是单线程执行命令,EXEC命令执行后,Redis会先执行命令队列中的所有命令执行完。再处理其它客户请求操作命令。所以这种情况不会影响事务的隔离性。

在这里插入图片描述

综上场景,使用WATCH命令在事务执行前,检测它们的更改。如果在执行EXEC命令之前至少修改了一个被监视的键,那么整个事务将终止,EXEC将返回一个Null应答来通知事务失败,避免事务的隔离性被破坏。如果在EXEC命令之后执行,Redis会保证先把命令队列中的所有命令执行完。不会破坏事务的隔离性。

在这里插入图片描述

持久性(Durability)

事务的持久性取决于Redis持久化配置,如果Redis没有配置RDB和AOF持久化,无持久化无数据。无持久性保证。那么事务属性肯定得不到保证。如果配置了持久性,根据不同的场景分析如下:

1)如果有RDB持久化,事务执行后,RDB快照还未执行就故障。无持久性保证。
2)如果有AOF持久化,取决于三种配置(no、everysec、alway)都存在数据丢失的情况,无持久性保证。

综上,不管是哪种模式,持久性都无法保证。 Redis本身是内存数据库,持久性并不是必须的属性。

在这里插入图片描述

小结

1)Redis事务ACID属性可以保证一致性和隔离性。但是无法保证原子性、持久性(由于Redis本身是内存数据库),持久性并不是必须的属性。一般关注ACI属性。
2)Redis的原子性在使用时较复杂,请参考官方文档操作命令,要确保命令运行正确,否则原子性无法得到保证。
3)在使用事务时,可以结合 pileline 一次发出多个命令而无需等待每个命令的响应来提高性能、或使用LUA脚本。
4)事务还需要考虑其它的,比如redis中的操作是redis脚本,它是事务性的。Redis 事务做的所有事情,你也可以用脚本来做,而且通常脚本会更简单、更快。

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

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

相关文章

YOLOv5改进 | Conv篇 | 利用YOLOv9的GELAN模块替换C3结构(附轻量化版本 + 高效涨点版本 + 结构图)

一、本文介绍 本文给大家带来的改进机制是利用2024/02/21号最新发布的YOLOv9其中提出的GELAN模块来改进YOLOv5中的C3,GELAN融合了CSPNet和ELAN机制同时其中利用到了RepConv在获取更多有效特征的同时在推理时专用单分支结构从而不影响推理速度,同时本文的内容提供了两种版本一…

8.qt5使用opencv的库函数打开图片

1.配置opencv动态库的环境变量 2.在创建的qt工程中加入如下opencv代码&#xff0c;具体代码如下&#xff1a; 使用opencv库函数显示图片

ACL权限、特殊位与隐藏属性的奥秘

1.2 操作步骤 # 1. 添加测试目录&#xff0c;用户&#xff0c;组&#xff0c;并将用户添加到组 ------------------- [rootlocalhost ~]# mkdir /project[rootlocalhost ~]# useradd zs[rootlocalhost ~]# useradd ls[rootlocalhost ~]# groupadd tgroup[rootlocalhost ~]# g…

亿道丨三防平板丨加固平板丨为零售业提供四大优势

随着全球经济的快速发展&#xff0c;作为传统行业的零售业也迎来了绝佳的发展机遇&#xff0c;在互联网智能化的大环境下&#xff0c;越来越多的零售企业选择三防平板电脑作为工作中的电子设备。作为一种耐用的移动选项&#xff0c;三防平板带来的不仅仅是坚固的外壳。坚固耐用…

4 buuctf解题

[CISCN 2019 初赛]Love Math1 打开题目 题目源码 <?php error_reporting(0); //听说你很喜欢数学&#xff0c;不知道你是否爱它胜过爱flag if(!isset($_GET[c])){show_source(__FILE__); }else{//例子 c20-1$content $_GET[c];if (strlen($content) > 80) {die("…

在项目中应用设计模式的实践指南

目录 ✨✨ 祝屏幕前的您天天开心&#xff0c;每天都有好运相伴。我们一起加油&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 引言 一. 单例模式&#xff08;Singleton Pattern&#xff09; 1、实现单例模式的方式 1…

回归预测 | Matlab实现PSO-BiLSTM-Attention粒子群算法优化双向长短期记忆神经网络融合注意力机制多变量回归预测

回归预测 | Matlab实现PSO-BiLSTM-Attention粒子群算法优化双向长短期记忆神经网络融合注意力机制多变量回归预测 目录 回归预测 | Matlab实现PSO-BiLSTM-Attention粒子群算法优化双向长短期记忆神经网络融合注意力机制多变量回归预测预测效果基本描述程序设计参考资料 预测效果…

使用 yarn 的时候,遇到 Error [ERR_REQUIRE_ESM]: require() of ES Module 怎么解决?

晚上回到家&#xff0c;我打开自己的项目&#xff0c;执行&#xff1a; cd HexoPress git pull --rebase yarn install yarn dev拉取在公司 push 的代码&#xff0c;然后更新依赖&#xff0c;最后开始今晚的开发时候&#xff0c;意外发生了&#xff0c;竟然报错了&#xff0c;…

easyui 手风琴Accordion 面板的高度设置

今天接到一个新的小需求&#xff0c;如下图&#xff0c;当预算表单只有一个时&#xff0c;要求不显示预算表单这块的内容。 考虑到页面创建时用到了表单的回调和点击方法&#xff0c;所以不能单纯的移除&#xff0c;移除右侧表格的创建会报错&#xff0c;所以只能隐藏。 隐藏…

Flutter 数据持久化存储之Hive

Flutter 数据持久化存储之Hive 前言正文一、配置项目二、UI① 增加UI② 显示和删除UI 三、使用Hive① 初始化Hive② TypeAdapter自定义对象③ 注册TypeAdapter③ CURD 四、源码 前言 在Flutter中&#xff0c;有多种方式可以进行数据持久化存储。以下是一些常见的方式&#xff1…

Java核心-核心类与API(2)

话接上回&#xff0c;继续核心类与API的学习&#xff0c;这次介绍StringBuffer/StringBuilder/StringJoiner类。StringBuffer和StringBuilder是我们学习的重点&#xff0c;建议对比学习&#xff0c;做好区分。 一、StringBuffer类 1、概述 1&#xff09;问题 由于 String 类…

CLion 2023:专注于C和C++编程的智能IDE mac/win版

JetBrains CLion 2023是一款专为C和C开发者设计的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它集成了许多先进的功能&#xff0c;旨在提高开发效率和生产力。 CLion 2023软件获取 CLion 2023的智能代码编辑器提供了丰富的代码补全和提示功能&#xff0c;使您能够更…

❤ hexo主题+Gitee搭建个人博客

Hexo的基本使用 1. ​认识 官网 官网地址&#xff1a;https://hexo.io/zh-cn/ 介绍 Hexo是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown&#xff08;或其他渲染引擎&#xff09;解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。即把用…

在 Jupyter Notebook 中查看所使用的 Python 版本和 Python 解释器路径

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 我们在做 Python 开发时&#xff0c;有时在我们的服务器上可能安装了多个 Python 版本。 使用 conda info --envs 可以列出所有的 conda 环境。当在 Linux 服务器上使用 which python 命令时&#xff0…

问题慢慢解决-通过android emulator调试android kernel-内核条件断点遇到的问题和临时解决方案

起因 在摸索到这个方案之后&#xff0c;mac m1调试aarch64 android kernel最终方案&#xff0c;就准备调试内核了&#xff0c;预备下断点的地方是 b binder_poll b ep_ptable_queue_proc b remove_wait_queue但是由于是android系统&#xff0c;上面三个函数会被频繁的触发&am…

基于Redis限流(固定窗口、滑动窗口、漏桶、令牌桶)(肝货!!!)

近期redis复习的比较多&#xff0c;在限流这方面发现好像之前理解的限流算法有问题&#xff0c;索性花了一天“带薪摸鱼”时间肝了一天&#xff0c;有问题可以评论区探讨。 废话不多说&#xff0c;正片开始 目录 Maven固定窗口滑动窗口算法漏桶算法令牌桶算法 Maven 有些不用的…

85、字符串操作的优化

上一节介绍了在模型的推理优化过程中,动态内存申请会带来额外的性能损失。 Python 语言在性能上之所以没有c++高效,有一部分原因就在于Python语言将内存的动态管理过程给封装起来了,我们作为 Python 语言的使用者是看不到这个过程的。 这一点有点类似于 c++ 标准库中的一些…

海格里斯HEGERLS四向穿梭车系统如何避免同区域多车作业产生的冲突障碍?

随着高新科技的不断迅速发展&#xff0c;仓储行业也在经历着前所未有的变革。其中&#xff0c;全自动四向穿梭车立体库无疑成为了近年来引人注目的创新&#xff0c;这种新型的仓储系统&#xff0c;以其高效率、自动化智能、灵活多样的特点&#xff0c;正在颠覆我们对传统仓储的…

网页数据的存储--存储为文本文件(TXT、JSON、CSV)

用解析器解析出数据后&#xff0c;接下来就是存储数据了。数据的存储有多种多样&#xff0c;其中最简单的一种是将数据直接保存为文本文件&#xff0c;如TXT、JSON、CSV等。这里就介绍将数据直接保存为文本文件。 目录 一、Python存储数据的方法 1、 文件读取 2、 文件写入…

2023年全球软件开发大会:前沿技术揭秘与未来趋势展望

2023年全球软件开发大会&#xff08;QCon上海站2023&#xff09;在科技圈掀起了新一轮的浪潮。 作为软件开发领域的顶级盛会&#xff0c;本次大会聚焦了当下最热门的技术话题&#xff0c;吸引了全球各地的开发者、架构师、技术领袖齐聚一堂&#xff0c;共同探讨软件开发的未来…