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://www.hqwc.cn/news/486505.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql-多表查询-内连接

一、简介 MySQL中的内连接&#xff08;INNER JOIN&#xff09;是一种多表查询的方式&#xff0c;它返回两个表中满足连接条件的记录。这意味着&#xff0c;只有当一个记录在两个表中都存在时&#xff0c;它才会出现在结果集中。 二、内连接查询语法 &#xff08;1&#xff0…

如何使用ChatGPT创建一份优质简历

目录 第一步&#xff1a;明确目标和重点 第二步&#xff1a;与ChatGPT建立对话 第三步&#xff1a;整理生成的内容 第四步&#xff1a;注重行文风格 第五步&#xff1a;强调成就和量化结果 第六步&#xff1a;个性化和定制 第七步&#xff1a;反复修改和完善 总结 在现…

69.x的平方根

目录 一、题目 二、暴力求解 三、二分查找&#xff08;改进&#xff09; 一、题目 https://leetcode.cn/problems/sqrtx/description/ 二、暴力求解 1.溢出问题 2.x为1 class Solution { public:int mySqrt(int x) {if(x 1)return 1;long long i0;for(i;i<x/2;i){if(…

分类预测 | Matlab实现KPCA-ISSA-LSSVM基于核主成分分析和改进的麻雀搜索算法优化最小二乘支持向量机故障诊断分类预测

分类预测 | Matlab实现KPCA-ISSA-LSSVM基于核主成分分析和改进的麻雀搜索算法优化最小二乘支持向量机故障诊断分类预测 目录 分类预测 | Matlab实现KPCA-ISSA-LSSVM基于核主成分分析和改进的麻雀搜索算法优化最小二乘支持向量机故障诊断分类预测分类效果基本描述程序设计参考资…

华为OD机试真题-来自异国的客人-2023年OD统一考试(C卷)--Python3--开源

题目&#xff1a; 考察内容&#xff1a; 10进制转为任何进制 代码&#xff1a; """ 题目分析&#xff1a;输入&#xff1a; k --物品价值&#xff1b;n 幸运数字&#xff1b;m 进制 输出&#xff1a; 幸运数字的个数 异常&#xff1b;0 eg; 10 2 4思路&…

HTML5技术实现的小钢琴

HTML5技术实现的小钢琴 用HTML5实现的小钢琴&#xff0c;按下钢琴键上的相应字母用或用鼠标点击钢琴键发声&#xff0c;源码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"v…

原型设计工具Axure RP

Axure RP是一款专业的快速原型设计工具。Axure&#xff08;发音&#xff1a;Ack-sure&#xff09;&#xff0c;代表美国Axure公司&#xff1b;RP则是Rapid Prototyping&#xff08;快速原型&#xff09;的缩写。 下载链接&#xff1a;https://www.axure.com/ 下载 可以免费试用…

钧达股份:光伏跨界新贵只身赴港股,光伏“秩序重塑”?

2月21日&#xff0c;钧达股份终是在“千呼万唤”之中披露最新业绩快报。 快报显示&#xff0c;钧达股份预计2023年经调整后营业收入183.97亿元&#xff0c;同比增长58.65%&#xff0c;归母净利润8.32亿元&#xff0c;同比增长16.00%。 其中&#xff0c;由于Q4完整计提了9.5GW…

Microsoft的PromptBench可以做啥?

目录 PromptBench简介 PromptBench的快速模型性能评估 PromptBench数据集介绍 PromptBench模型介绍 PromptBench模型加载遇到的问题 第一次在M1 Mac上加载模型 vicuna和llama系列模型 PromptBench各个模型加载情况总结 PromptBench的Prompt快速工程 chain of thought…

命令执行 [WUSTCTF2020]朴实无华1

做题&#xff1a; 打开题目 我们用dirsearch扫描一下看看 扫描到有robots.txt&#xff0c;访问一下看看 提示我们 /fAke_f1agggg.php 那就访问一下&#xff0c;不是真的flag bp抓包一下 得到提示&#xff0c; /fl4g.php&#xff0c;访问一下看看 按alt&#xff0c;点击修复文…

品优购项目

一、品优购项目规划 1.1 网站制作流程 1.2 品优购项目整体介绍 项目名称&#xff1a;品优购 项目描述&#xff1a;品优购是一个电商网站&#xff0c;我们要完成PC端首页、列表页、注册页面的制作 1.3 品优购项目的学习目的 1.电商类网站比较综合&#xff0c;里面需要大量的…

红队评估四靶场

文章目录 环境搭建1.设置所需网卡2.更改win7设置3.DC设置4.web设置开启docker服务5.kali网段`渗透启动`1.确认对方靶机的IP地址2.端口探测3.web探测`2001端口``2002端口`Tomcat/8.5.19漏洞复现`2003端口`4.docker逃逸5.ssh密钥爆破`域渗透启动`1.提权2.隧道搭建各项配置文件内容…