如需转载,请根据 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 许可,附上本文作者及链接。
本文作者: 执笔成念
作者昵称: zbcn
本文链接: https://1363653611.github.io/zbcn.github.io/2021/02/12/redis_07%E5%8A%9F%E8%83%BD/
Redis 事物
## 事物介绍
- Redis的事务是通过MULTI,EXEC,DISCARD和WATCH这四个命令来完成。
- Redis的单个命令都是原子性的,所以这里确保事务性的对象是命令集合。
- Redis将命令集合序列化并确保处于一事务的命令集合连续且不被打断的执行。
- Redis不支持回滚的操作。
相关命令
MULTI
注:用于标记事务块的开始。
Redis会将后续的命令逐个放入队列中,然后使用EXEC命令原子化地执行这个命令序列。
语法: MULTI
EXEC
在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。
语法:EXEC
DISCARD
清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
语法:DISCARD
WATCH
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的状态。
语法:WATCH key [key ….]
注:该命令可以实现redis的乐观锁
语法
1 | 127.0.0.1:6379> set ss1 vv1 |
2 | QUEUED |
3 | 127.0.0.1:6379> get ss1 |
4 | QUEUED |
5 | 127.0.0.1:6379> exec |
6 | 1) OK |
7 | 2) "vv1" |
8 | |
9 | |
10 | 示例2 |
11 | 127.0.0.1:6379> type ss1 |
12 | string |
13 | 监控 ss1 |
14 | 127.0.0.1:6379> watch ss1 |
15 | OK |
16 | 127.0.0.1:6379> MULTI |
17 | OK |
18 | 若 ss1 发生变化,则事务提交失败,返回: nil. 成功则为:ok |
19 | 127.0.0.1:6379> set ss1 222 |
20 | QUEUED |
21 | 127.0.0.1:6379> EXEC |
22 | 1) OK |
事务失败处理
- Redis语法错误(编译器错误)
- Redis类型错误(运行期错误)
为什么redis不支持事务回滚?
- 大多数事务失败是因为语法错误或者类型错误,这两种错误,再开发阶段都是可以避免的
- Redis为了性能方面就忽略了事务回滚
Redis 持久化方案
概述
Redis是一个内存数据库,为了保证数据的持久性,它提供了两种持久化方案。
- RDB 方式(默认)
- AOF 方式
RDB(redis DataBase)方式
- RDB是Redis默认采用的持久化方式。
- RDB方式是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。
RDB触发条件
- 符合自定义配置的快照规则
- 执行save或者bgsave命令
- 执行flushall命令
- 执行主从复制操作
在redis.conf中设置自定义快照规则
RDB持久化条件
格式:save
示例:
save 900 1:表示15分钟(900秒)内至少1个键更改则进行快照。
save 300 10:表示5分钟(300秒)内至少10个键被更改则进行快照。
save 60 10000:表示1分钟内至少10000个键被更改则进行快照。
配置dir指定rdb快照文件的位置
1 | Note that you must specify a directory here, not a file name. |
2 | dir ./ |
配置dbfilename指定rdb快照文件的名称
1 | The filename where to dump the DB |
2 | dbfilename dump.rdb |
说明
- Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存
- 根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将记录1千万个字符串类型键,大小为1GB的快照文件载入到内存中需要花费20-30秒钟
快照的实现原理
快照过程
- redis使用fork函数复制一份当前进程的副本(子进程)
- 父进程继续接受并处理客户端发来的命令,而子进程开始将内存中的数据写入到硬盘中的临时文件。
- 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。
注意
- redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。
- 这就使得我们可以通过定时备份RDB文件来实现redis数据库的备份,RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。
RDB优缺点
缺点
使用RDB方式实现持久化,一旦redis异常退出,就会丢失最后一次快照以后更改的所有数据。这个时候我们就需要根据具体的应用场景,通过组合设置自动快照条件的方式将可能发生的数据损失控制在能够接受范围。如果数据相对来说比较重要,希望将损失降到最小,则可以使用AOF方式进行持久化
优点
RDB可以最大化redis的性能:父进程在保存RDB文件时唯一要做的就是fork出一个字进程,然后这个子进程就会处理接下来的所有保存工作,父进程无需执行任何磁盘I/O操作。同时这个也是一个缺点,如果数据集比较大的时候,fork可能比较耗时,造成服务器在一段时间内停止处理客户端的请求。
AOF (Append Only File) 方式
介绍
默认情况下Redis没有开启AOF(append only file)方式的持久化
开启AOF持久化后每执行一条会更改Redis中的数据命令,Redis就会将该命令写入硬盘中的AOF文件,这一过程显示会降低Redis的性能,但大部分下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。
配置redis.conf
设置appendonly参数为yes
1 | appendonly yes |
AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
1 | dir ./ |
默认的文件名是appendonly.aof,可以通过appendfilename参数修改
1 | appendfilename appendonly.aof |
AOF重写原理(优化AOF文件)
- Redis可以在AOF文件体积变得过大时,自动地后台对AOF进行重写
- 重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。
- 整个重写操作是绝对安全的,因为Redis在创建新的AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。
- AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。
参数说明
- #auto-aof-rewrite-percentage 100:表示当前aof文件大小超过上次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时aof文件大小为基准。
- #auto-aof-rewrite-min-size 64mb:表示限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
同步磁盘数据
Redis每次更改数据的时候,aof机制都会将命令记录到aof文件,但是实际上由于操作系统的缓存机制,数据并没有实时写入到硬盘,而是进入硬盘缓存。再通过硬盘缓存机制去刷新到保存文件中。
参数说明
- appendfsync always:每次执行写入都会进行同步,这个是最安全但是效率比较低
- appendfsync everysec:每一秒执行
- appendfsync no:不主动进行同步操作,由于操作系统去执行,这个是最快但是最不安全的方式
AOF文件损坏以后如何修复
服务器可能在程序正在对AOF文件进行写入时停机,如果停机造成AOF文件出错(corrupt),那么Redis在重启时会拒绝载入这个AOF文件,从而确保数据的一致性不会被破坏。
当发生这种情况时,可以以以下方式来修复出错的AOF文件:
1、为现有的AOF文件创建一个备份。
2、使用Redis附带的redis-check-aof程序,对原来的AOF文件进行修复。
3、重启Redis服务器,等待服务器字啊如修复后的AOF文件,并进行数据恢复。
如何选择RDB和AOF
- 一般来说,如果对数据的安全性要求非常高的话,应该同时使用两种持久化功能。
- 如果可以承受数分钟以内的数据丢失,那么可以只使用RDB持久化。
- 有很多用户都只使用AOF持久化,但并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份,并且RDB恢复数据集的速度也要比AOF恢复的速度要快。
- 两种持久化策略可以同时使用,也可以使用其中一种。如果同时使用的话,那么Redis启动时,会优先使用AOF文件来还原数据。