一、RDB
1.1 RDB持久化流程
fork子进程是阻塞的,如果同时开启RDB和AOF,默认使用AOF。
1、Redis父进程首先判断: 当前是否在执行save,或bgsave/bgrewriteaof (aof文件重写命令)的子进程,如果在执行则bgsave命令直接返回。
2、父进程执行fork(调用OS函数复制主进程)操作创建子进程,这个复制过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令。
3、父进程fork后,bgsave命令返回”Bacground saving started"信息并不再阻塞父进程,并可以响应其他命令。
4、子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换。 (RDB始终完整)。
5、子进程发送信号给父进程表示完成,父进程更新统计信息。
6、父进程fork子进程后,继续工作。
1.2 redis配置
#1. 下面配置为默认配置,默认就是开启的,在一定的间隔时间中,检测key的变化情况,然后持久化数据
save 900 1 #900s后至少1个key发生变化则进行存储
save 300 10 #300s后至少10个key发生变化则进行存储
save 60 10000 #60s后至少10000个key发生变化则进行存储
#2. rdb文件的存储路径(默认当前目录下,文件名为dump.rdb)
dbfilename dump.rdb
1.3 RDB优缺点
优点
RDB是二进制压缩文件,占用空间小,便于传输 (传给slaver)主进程fork子进程,可以最大化Redis性能,主进程不能太大,复制过程中主进程阻塞。
缺点
不保证数据完整性,会丢失最后一次快照以后更改的所有数据。
二、AOF
2.1 AOF介绍
AOF (append only file) 是Redis的另一种持久化方式。Redis默认情况下是不开启的。开启AOF持久化后Redis 将所有对数据库进行过写入的命令(及其参数) (RESP)记录到 AOF 文件,以此达到记录数据库状态的目的,这样当Redis重启后只要按顺序回放这些命令就会恢复到原始状态了。AOF会记录过程,RDB只管结果。
2.2 AOF持久化实现
文件内容示例:
2.3 AOF写入过程
AOF文件中存储的是redis的命令,同步命令到 AOF 文件的整个过程可以分为三个阶段:
1、命令传播: Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中。
2、缓存追加: AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。
3、文件写入和保存: AOF缓存中的内被写入到AOF文件末尾,如果设定的 AOF 保存条件被满足的话,fsync函数或者fdatasync函数会被调用,将写入的内容真正地保存到磁盘中。
2.4 AOF写入频率
AOF有这样几种配置用来控制读写的频率:
(1)appendfsync always:每次一收到写命令就立即强制写入磁盘,保证完全的持久化。
(2)appendfsync no:由操作系统决定何时同步数据。
(3)appendfsync everysec:每秒钟强制写入磁盘一次。
2.5 AOF重写
AOF重写的实现
为了减小aof文件的体量,可以手动发送“bgrewriteaof”指令,通过子进程生成更小体积的aof,然后替换掉旧的、大体量的aof文件。
AOF重写的工作原理
需要注意的是,在这里子进程把数据转为写指令存入新的AOF文件时,记录的只是每个数据的最后一次写指令,也就是最新的数据,不会记录之前冗余的操作,所以这样会很大程度的缩小AOF的体量,同时,该操作是产生新的AOF文件进行写入,而不是在原有文件上的修改,通过上图也可以看出来。而缓存中叠加到新的aof的操作仍是新增的全部操作,但是这些数据已经很有限,相比之前的全部添加,这种机制很好的解决的AOF文件不断增大的问题。
2.6 AOF重写的相关配置
1)auto-aof-rewrite-percentage 100
2)auto-aof-rewrite-min-size 64mb
在aof文件体量超过64mb,且比上次重写后的体量增加了100%时自动触发重写。
2.7 AOF服务重启恢复数据
AOF文件里面包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态,步骤如下:
1、创建一个不带网络连接的伪客户端 (fake client)[因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服 务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。
2、从AOF文件中分析并读取出一条写命令。
3、使用伪客户端执行被读出的写命令,一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止。
4、当完成以上步骤之后,AOF文件所保存的数据库状态就会被完整地还原出来,整个过程如下图所示:
2.8 AOF配置
#二. AOF存储
#1.默认是关闭的,日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据,启用的话通常使用每隔一秒持久化一次的策略appendonly no(默认no) --> appendonly yes (开启aof)
# appendfsync always #每一次操作都进行持久化appendfsync everysec #每隔一秒进行一次持久化
# appendfsync no # 不进行持久化
#2. aof文件路径 (默认为当前目录下,文件名为 appendonly.aof)
appendfilename "appendonly.aof"
dir ./ (同上)
#3. 控制触发自动重写机制频率
# auto-aof-rewrite-min-size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就很快,重写的意义不大
# auto-aof-rewrite-percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写
三、混合持久化
3.1 混合持久化介绍及配置
RDB和AOF各有优缺点,Redis 4.0 开始支持 rdb 和 aof 的混合持久化,5.0以后默认开启。如果把混合持久化打开,AOF Rewrite 的时候就直接把 RDB 的内容写到 aof 文件开头。(RDB的头+AOF的身体---->appendonly.aof)
开启混合持久化
#三. 混合持久化
#1. 开启混合持久化配置 (5.0版本默认就是yes)
aof-use-rdb-preamble yes
#2. rdb和aof自身的配置也都需要开启
3.2 混合持久化原理
开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件。
1、重写这一刻之前的内存做RDB快照处理(重写期间执行的指令和之后的指令仍然是转换成resp指令吸入aof文件)。
2、将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,会覆盖原有的AOF文件,完成新旧两个AOF文件的替换。
3、Redis重启的时候,可以先加载RDB的内容,然后再重放增量AOF日志就可以完全替代之前的AOF全量文件重放,因此重启效率大幅得到提升。
3.3 演示
(3). 演示
A. 开启混合持久化机制 【aof-use-rdb-preamble yes】
B. 运行指令【bgrewriteaof】手动进行aof重写(前提内存中有内容),此时查看aof文件中的内容,类似乱码的东西,就是rdb快照处理。
C. 再任意执行几个set指令,然后查看aof文件中内容。
四、应用场景
1、内存数据库 rdb+aof 数据不容易丢。
2、有原始数据源: 每次启动时都从原始数据源中初始化 ,则不用开启持久化(数据量较小)
3、缓存服务器一般性能高rdb
4、在数据还原时:
有rdb+aof 则还原aof,因为RDB会造成文件的丢失,AOF相对数据要完整。
只有rdb,则还原rdb。
五、实际场景
1、追求高性能: 都不开redis宕机从数据源恢复。
2、字典库:不驱逐,保证数据完整性,不开持久化。
3、用作DB不能主从 数据量小。
4、做缓存 较高性能: 开rdb。
5、Redis数据量存储过大,性能突然下降: fork 时间过长 阻塞主进程,则只开启AOF。