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) 13

192.168.88.11:6380> set key "java"
OK
 
192.168.88.11:6380> watch key 
OK
192.168.88.11:6380> multi
OK

192.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) 10

192.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 事务做的所有事情,你也可以用脚本来做,而且通常脚本会更简单、更快。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

改进yolov5实现目标检测与语意分割项目

简介 基于ultralytics/yolov5多任务模型。同时实现yolo目标检测与语意分割以增加少量计算和显存为代价&#xff0c;同时完成目标检测和语义分割(1024512输入约增加350MB&#xff0c;同尺寸增加一个bisenet需要约1.3GB&#xff0c;两个单任务模型独立输入还有额外的延时)。模型…

【elementUi-table表格】 滚动条 新增监听事件; 滚动条滑动到指定位置;

1、给滚动条增加监听 this.dom this.$refs.tableRef.bodyWrapperthis.dom.scrollTop 0let _that thisthis.dom.addEventListener(scroll, () > {//获取元素的滚动距离let scrollTop _that.dom.scrollTop//获取元素可视区域的高度let clientHeight this.dom.clientHeigh…

Sass预处理器教程

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 一、sass是什么 Sass官方文档 www.sasscss.com/guide Sass中文网 www.sass.hk sass是一种css预处理语言&#xff0c;由Ruby语言开发&#x…

【算法与数据结构】回溯算法、贪心算法、动态规划、图论(笔记三)

文章目录 七、回溯算法八、贪心算法九、动态规划9.1 背包问题9.2 01背包9.3 完全背包9.4 多重背包 十、图论10.1 深度优先搜索10.2 广度优先搜索10.3 并查集 最近博主学习了算法与数据结构的一些视频&#xff0c;在这个文章做一些笔记和心得&#xff0c;本篇文章就写了一些基础…

4.8 Verilog过程连续赋值

关键词&#xff1a;解除分配&#xff0c;强制&#xff0c;释放 过程连续赋值是过程赋值的一种。赋值语句能够替换其他所有wire 或 reg 的赋值&#xff0c;改写wire 或 reg 类型变量的当前值。 与过程赋值不同的是&#xff0c;过程连续赋值表达式能被连续的驱动到wire 或 reg …

苹果发布iPhone 16:革命性创新重新定义智能手机体验

&#xff08;苹果总部&#xff0c;加利福尼亚州&#xff0c;2024年2月23日&#xff09;——今天&#xff0c;全球领先的科技公司苹果公司再次震撼世界&#xff0c;宣布推出iPhone 16&#xff0c;这款革命性的智能手机重新定义了人们对于手机的期望和体验。 iPhone 16的发布代表…

基于R语言地理加权回归、主成份分析、判别分析等空间异质性数据分析

在自然和社会科学领域有大量与地理或空间有关的数据&#xff0c;这一类数据一般具有严重的空间异质性&#xff0c;而通常的统计学方法并不能处理空间异质性&#xff0c;因而对此类型的数据无能为力。以地理加权回归为基础的一系列方法&#xff1a;经典地理加权回归&#xff0c;…

DM数据库学习之路(十八)DMHS数据实时同步软件部署及迁移测试

​​​​​ DMDRS介绍 产品介绍 达梦数据实时同步软件&#xff08;以下简称 DMDRS&#xff09;是支持异构环境的高性能、高可靠、高可扩展数据库实时同步复制系统。该产品采用基于日志的结构化数据复制技术&#xff0c;不依赖主机上源数据库的触发器或者规则&#xff0c;对主…

【SpringCloudAlibaba系列--nacos配置中心】

Nacos做注册中心以及使用docker部署nacos集群的博客在这&#xff1a; 容器化部署Nacos&#xff1a;从环境准备到启动 容器化nacos部署并实现服务发现(gradle) 使用docker部署nacos分布式集群 下面介绍如何使用nacos做配置中心 首先要进行nacos-config的引入&#xff0c;引入…

【前端素材】推荐优质后台管理系统Modernize平台模板(附源码)

一、需求分析 后台管理系统是一种用于管理和控制网站、应用程序或系统后台操作的软件工具&#xff0c;通常由授权用户&#xff08;如管理员、编辑人员等&#xff09;使用。它提供了一种用户友好的方式来管理网站或应用程序的内容、用户、数据等方面的操作&#xff0c;并且通常…

kafka为什么性能这么高?

Kafka系统架构 Kafka是一个分布式流处理平台&#xff0c;具有高性能和可伸缩性的特点。它使用了一些关键的设计原则和技术&#xff0c;以实现其高性能。 上图是Kafka的架构图&#xff0c;Producer生产消息&#xff0c;以Partition的维度&#xff0c;按照一定的路由策略&#x…

康威生命游戏

康威生命游戏 康威生命游戏(Conway’s Game of Life)是康威发明的细胞自动机。 生命游戏有几个简单的规则&#xff1a; 细胞有两种状态&#xff0c;存活或死亡&#xff0c;每个细胞以自身为中心与周围的八格细胞互动。 对于存活的细胞&#xff1a; 当周围的细胞过少(<2)或…

【vue】如何打开别人编译后的vue项目

文件结构如下&#xff0c;编译后的文件放在dist中。 dist的文件结构大约如下&#xff0c;文件名称随项目 1.新建app.js文件 const express require(express);const app express();const port 8080;app.use(express.static(dist));app.listen(port, () > console.log); …

密评技术要求实施详解:每一步都关键

密评简介 密评定义&#xff1a;全称商用密码应用安全性评估, 是对采用商用密码技术、产品和服务集成建设的网络和信息系统密码应用的合规性、正确性、有效性进行评估的活动。 评测依据&#xff1a;GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》。 密评对象&…

智能高压森林应急消防泵|保障森林安全|深圳恒峰

随着科技的不断发展&#xff0c;我们的生活质量得到了显著提升。在森林保护领域&#xff0c;一项创新技术正在发挥着关键作用——智能高压森林应急消防泵。这种设备不仅提高了灭火效率&#xff0c;更为森林资源的安全保驾护航。 在过去&#xff0c;面对森林火灾&#xff0c;消防…

鸿蒙DevEco Service开发准备与使用

DevEco低代码是一个基于Serverless和ArkUI的端云一体化低代码开发平台&#xff0c;可通过拖拽式开发&#xff0c;可视化配置构建元服务。打通HarmonyOS云侧与端侧能力&#xff0c;轻松实现HMS Core和AGC Serverless能力的调用。通过与元服务生态、HMS Core、AGC Serverless平台…

python统计分析——线性模型的预测和评估

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 导入数据处理的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 导入绘图的库 from matplotlib import pyplot as plt import seaborn as sns sns.set() # 导入估计…

亚马逊,速卖通,国际站测评补单的必要性与方法

亚马逊平台的规则与某宝有所不同。亚马逊平台没有产品推广引流和直通车等功能。而且&#xff0c;与某宝不同的是&#xff0c;亚马逊平台没有广告位和卖家客服。在某宝上&#xff0c;当我们选择款式和颜色时&#xff0c;通常会与卖家客服进行沟通。但在亚马逊上&#xff0c;没有…

【Docker】免费使用的腾讯云容器镜像服务

需要云服务器等云产品来学习Linux可以移步/-->腾讯云<--/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;新用户首次下单享超低折扣。 目录 1、设置密码 2、登录实例&#xff08;sudo docker login xxxxxx&#xff09; 3、新建命名空间&#xff08;每个命名空…

day40打卡

day40打卡 343. 整数拆分 状态表示 ​ dp[i] 表示将正整数i拆分成至少两个正整数的和之后&#xff0c;这些正整数的最大乘积 状态转移方程 ​ i > 2 时&#xff0c;对正整数i拆出的第一个正整数是j&#xff0c;则有&#xff1a; 将i拆分为 j 和 i-j&#xff0c;且 i-j…