zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

事务和锁机制、持久化【Redis篇3】

Redis事务 机制 持久
2023-09-27 14:25:57 时间
1、事务和锁机制1.1、事务定义Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis事务的主要作用就是串联多个命令防止别的命令插队。1.2、Multi、Exec、discardMulti命令:事务开始。输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。组队的过程中可以通过discard来放弃组队。

在这里插入图片描述
案例说明

# 顺利执行的案例

127.0.0.1:6379 multi

127.0.0.1:6379(TX) set k1 v1

QUEUED

127.0.0.1:6379(TX) set k2 v2

QUEUED

127.0.0.1:6379(TX) set k3 v3

QUEUED

127.0.0.1:6379(TX) exec

1) OK

2) OK

3) OK

127.0.0.1:6379 


127.0.0.1:6379
1.3、事务中的错误处理

1. 如果其中某个命令出现了报告错误,执行时整个队列都会被取消。

在这里插入图片描述

代码说明

127.0.0.1:6379 multi

127.0.0.1:6379(TX) set k1 v1

QUEUED

127.0.0.1:6379(TX) set k2

(error) ERR wrong number of arguments for set command

127.0.0.1:6379(TX) 

127.0.0.1:6379(TX) set k3 v3

QUEUED

127.0.0.1:6379(TX) exec

(error) EXECABORT Transaction discarded because of previous errors.

127.0.0.1:6379 keys *

(empty array)

2. 如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

在这里插入图片描述
代码说明

127.0.0.1:6379 multi

127.0.0.1:6379(TX) 

127.0.0.1:6379(TX) set k1 v1

QUEUED

127.0.0.1:6379(TX) set k2 v2

QUEUED

127.0.0.1:6379(TX) incr k1

QUEUED

127.0.0.1:6379(TX) exec

1) OK

2) OK

3) (error) ERR value is not an integer or out of range
1.4、为什么需要事务?

案例说明

一个请求想给金额减8000一个请求想给金额减5000一个请求想给金额减1000

在这里插入图片描述

在多线程的情况下,一个请求8000的线程、一个请求5000的线程和一个请求1000的线程可能分别读到的是10000。然后分别对其分别执行会导致最后的总金额变为了 -4000。所以我们需要将其做成事务,让它们按序执行。1.5、锁机制1.5.1、悲观锁悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

在这里插入图片描述

1.5.2、乐观锁乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

在这里插入图片描述

1.6、WATCH、UNWATCH1.6.1、WATCH在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key 。如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

例子说明

# 第一个连接窗口

127.0.0.1:6379 watch k1

127.0.0.1:6379 

127.0.0.1:6379 multi

127.0.0.1:6379(TX) get k1

QUEUED

127.0.0.1:6379(TX) set k3 v3

QUEUED


127.0.0.1:6379(TX) exec (nil)
1.6.2、UNWATCH取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。1.7、Redis事务的特性单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。没有隔离级别的概念:队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行不保证原子性:事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚2、持久化

Redis 提供了2个不同形式的持久化方式。

RDBAOF2.1、RDB2.1.1、RDB是什么?

在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。

在这里插入图片描述

2.1.2、备份是如何执行的?

在这里插入图片描述

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。2.1.3、ForkFork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。2.1.4、相关配置
# 相关配置的配置文件名称

dbfilename dump.rdb


# 快照保持策略:第一个配置的意思就是3600秒的时间间隔如果发生改变的数据超过一个那么就会将这时间内的所有数据持久到硬盘 # save 3600 1 # save 300 100 # save 60 10000
# save :save时只管保存,其它不管,全部阻塞。手动保存。不建议。 # bgsave:Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。
# 当Redis无法写入磁盘的话,直接关掉Redis的写操作。推荐yes. stop-writes-on-bgsave-error yes
# 对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。推荐yes rdbcompression yes
#在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,推荐yes rdbchecksum yes
2.1.5、RDB的备份先通过config get dir 查询rdb文件的目录将*.rdb的文件拷贝到别的地方

rdb的恢复

关闭Redis先把备份的文件拷贝到工作目录下 cp dump2.rdb dump.rdb启动Redis, 备份数据会直接加载2.1.6、优点适合大规模的数据恢复对数据完整性和一致性要求不高更适合使用节省磁盘空间恢复速度快2.1.7、缺点虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。2.2、AOF2.2.1、AOF是什么?以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。2.2.2、AOF持久化流程

在这里插入图片描述

客户端的请求写命令会被append追加到AOF缓冲区内;AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;2.2.3、文件名称和路径AOF默认情况下是不开启的。可以在redis.conf中配置文件名称,默认为 appendonly.aofAOF文件的保存路径,同RDB的路径一致。如果AOF和RDB同时开启的话,系统默认读取AOF的数据(数据不会存在丢失)。2.2.4、AOF恢复

1. 正常恢复

修改默认的appendonly no,改为yes将有数据的aof文件复制一份保存到对应目录(查看目录:config get dir)恢复:重启redis然后重新加载

2. 异常恢复

修改默认的appendonly no,改为yes如遇到AOF文件损坏,通过/usr/local/bin/redis-check-aof --fix appendonly.aof进行恢复备份被写坏的AOF文件恢复:重启redis,然后重新加载2.2.5、AOF同步频率设置
# 始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好

appendfsync always


# redis不主动进行同步,把同步时机交给操作系统 appendfsync no
2.2.6、压缩当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集。

例如

set k1 v1 

set k2 v2

# 它会被压缩为 

set k1 v1 k2 v2
如果Redis的AOF当前大小 = base_size +base_size*100% (默认)且当前大小 =64mb(默认)的情况下,Redis会对AOF进行重写。2.2.7、优点备份机制更稳健,丢失数据概率更低。可读的日志文本,通过操作AOF稳健,可以处理误操作。2.2.8、缺点比起RDB占用更多的磁盘空间。恢复备份速度要慢。每次读写都同步的话,有一定的性能压力。存在个别Bug,造成恢复不能。2.3、选择官方推荐两个都启用。如果对数据不敏感,可以选单独用RDB。不建议单独用 AOF,因为可能会出现Bug。如果只是做纯内存缓存,可以都不用。
又陷入知识盲区了,面试被问Redis事务,我差点脸都“绿”了 前几天有读者说自己面试被问到Redis的事务,虽然不常用,但是面试竟然被问到,平时自己没有注意Redis的事务这一块,面试的时候被问到非常不好受。 虽然,这位读者面试最后算是过了,但是薪资方面没有拿到自己理想的薪资。 其实这个也是正常的,一般面试被问到烂大街的,谁还问你啊,专门挑一些不常见的来问你,就是为了压你的薪资。
一文讲透 Redis 事务 (事务模式 VS Lua 脚本) 先说结论: Redis 的事务模式具备如下特点: - 保证隔离性; - 无法保证持久性; - 具备了一定的原子性,但不支持回滚; - 一致性的概念有分歧,假设在一致性的核心是约束的语意下,Redis 的事务可以保证一致性。 但 Lua 脚本更具备实用场景,它是另一种形式的事务,他具备一定的原子性,但脚本报错的情况下,事务并不会回滚。Lua 脚本可以保证隔离性,而且可以完美的支持**后面的步骤依赖前面步骤的结果**。
简短截说阐述redis中事务(Redis Transactions)的使用 我们知道,在关系型数据库中,比如mysql,如果要使用事务,首先向数据库服务器发送 BEGIN ,然后执行各个相互一致的写操作和读操作,最后,用户可以选择发送 COMMIT 来确认之前所做的修改,或者发送 ROLLBACK 来放弃那些修改。
Redis事务,Redis实现悲观锁,乐观锁详解 redis 事务可以一次执行多个命令,并带有三个保证 - exec命令执行前,多个命令被放入队列缓存 - exec命令执行后,缓存队列中的命令顺序执行,一旦有一个有误,不影响其它命令的执行 - 在事务执行过程中,其它客户端提交的命令请求不会插入到当前的缓存命令队列