Redis持久化
redis持久化的两种方式:RDB和AOF
1,RDB
RDB 持久化是把当前进程数据⽣成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和⾃动触发。
手动触发分别对应 save 和 bgsave 命令:
• save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为⽌,基本不采用。
• bgsave 命令:Redis 进程执行fork 操作创建⼦进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,⼀般时间很短。
Redis 内部的所有涉及 RDB 的操作都采⽤类似 bgsave 的方式。
除了手动触发之外,Redis 运行自动触发 RDB 持久化机制,这个触发机制才是在实战中有价值的。
使用save 配置。如 "save m n" 表示m 秒内数据集发生了 n 次修改,自动 RDB 持久化。
从节点进行全量复制操作时,主节点自动进行RDB 持久化,随后将 RDB ⽂件内容发送给从节点。(这个在主从复制部分会进行说明)。
执行shutdown 命令关闭 Redis 时,执行RDB 持久化。
2,RDB生成文件流程
执行bgsave 命令,Redis ⽗进程判断当前进是否存在其他正在执行的子进程。比如现在已经有一个子进程正在执行bgsave了,此时就把当前的bgsave给返回。也就是说,此时redis服务器可能会收到多个客户端发送来的bgsave命令,但只处理一个,其他的都返回。
父进程执行fork 创建⼦进程。
子进程负责写文件,生成快照的过程。父进程继续接受其他客户端的请求,继续正常提供服务。这个写文件的过程中,如果rdb文件不存在,则直接创建文件再写入数据。而如果存在rdb文件,就会把数据先保存到一个临时rdb文件中,当快照生成完毕之后,再删除之前旧的rdb,把临时rdb文件的名称改为原来rdb文件的名称。这里涉及到一个文件替换的过程。
子进程完成持久后工作后,就会通过信号通知父进程,之后子进程就可以退出销毁了。
3,RDB特点
1,RDB:RDB是一个紧凑的二进制文件,代表redis在某一时刻的数据快照。
2,Redis加载RDB比AOF的方式更快:RDB这里使用的是二进制的方式来组织数据的,直接把数据加载到内存中,按照字节的格式去出来,放到结构体/对象中即可。而AOF是使用文本的方式来组织数据的,这会涉及到一些字符串分割操作。
3,RDB文件使用特点的二进制格式保存,Redis版本演进过程中,有多个RDB版本没兼容性可能有风险。
4,RDB最大的问题:
不能实时的持久化保存数据。在两次生成快照之间,实时的数据可能会随着重启而丢失。
5,AOF
类似于MySQL的的binlog,就会把用户的每个操作都记录在文件中。当redis重新启动的时候,就会读取这个AOF文件的内容,用来恢复数据。
aof功能是默认关闭的,可以通过修改配置文件或者命令来启动。
当aof功能开启后,rdb就不再生效了,服务器启动的时候就不会读取rdb文件了。
6,AOF写文件的机制
redis是一个单线程的服务器,AOF机制并非是让工作线程把数据写入硬盘,而是先写入内存中的一块缓冲区中,积累一波后,再写入硬盘中。
而写入缓冲区,可以大大降低写硬盘的次数。
硬盘上读写数据,顺序读写的速度是很快的(但还是比内存慢很多),而随机读写的速度是比较慢的。
而AOF每次把新的操作写入到原有文件的末尾,属于顺序写入。
但是AOF写文件的本质仍然是向内存中写,如果redis服务器挂了,那么内存中的数据仍然是会丢失的。
所以redis给出了一些选项,来决定缓冲区的刷新策略。
当缓冲区的刷新频率越高,也就是写文件操作的频率越高,对性能的影响就越大,同时数据的可靠性就越高。
当缓冲区的刷新频率越高低,也就是写文件操作的频率越低,对性能的影响就越小,同时数据的可靠性就越低。
一共有3个选项,always,everysec,no;always表示当向缓冲区写入数据后,立即刷新,立即执行写文件的操作;
everysec表示每秒执行刷新的操作;no,频率最低,将什么时候刷新交给操作系统,比如当服务退出了,执行刷新操作,当缓冲区满了,执行刷新操作。
默认情况下采取的是everysec刷新策略。
7,AOF文件的重写机制
- Redis存在一种机制,能够对aof文件进行整理操作,这个整理操作就是剔除其中的冗余操作,并且合并一些操作,达到给aof文件瘦身的效果。
比如现在有以下几个操作:
1,set key 111,set key 222,set key 333,最后整合成一个命令set key 333,也就是前面的两个操作不用保存,只保留最后一个即可。
2,同理还有对列表的操作:lpush key 111,lpush key 222,lpush key 333,这几个操作最后也可以整合成一个命令:lpush key 111 222 333
通过这样的方式,可以减少aof文件的大小。
- 重写机制的触发时机:
- 手动触发:
bgrewriteaof
命令。 - 自动触发:修改配置文件(在ubutun下,配置文件的目录是在/etc/redis下)。
8,AOF文件的重写流程
当触发AOF文件重写机制时:
父进程会fork出子进程,子进程负责将当前内存中的数据写入到新的aof文件中。
在子进程重写文件的同时,父进程仍然在不停的接受其他客户端的请求,父进程还是会把这些请求写入到缓冲区aof_buf中,同时父进程这里又准备了一个aof_rewrite_buf缓冲区,也会将新收到的请求写入到这个缓冲区中,也就是说aof_rewrite_buf缓冲区专门放fork之后收到的数据。
子进程这边,把aof数据写完之后,会通过信号通知一下父进程。父进程再把aof_rewrite_buf缓冲区的数据也写入到新的aof文件中。
最后使用新的aof文件代替旧的aof文件。
在上述重写流程中,父进程fork之后,子进程就开始写新的aof文件了,并随着时间的推移,子进程很快就写完了新的文件,要让新的aof文件代替旧的aof文件。在这个过程中,父进程仍然在继续写这个即将消亡的旧的aof文件,是否还有意义?
注意,这里不能不写,考虑到极端情况,如果子进程在重写的过程中,服务器挂了,子进程内存中的数据就会丢失,此时 新的aof文件中的内容还不完整。所以,如果父进程不坚持写旧的aof文件,重启之后就无法保证数据的完整性了。
如果,在执行bgrewriteaof的时候,当前redis已经正在进行aof重写了,此时不会再执行重写了,会直接返回。
如果,在执行bgrewriteaof的时候,发现redis正在生成rdb文件的快照,此时,aof重写操作就会等待,等待rdb快照生成完成之后,再执行aof重写。
注意:AOF本来是按照文本的方式来写入文件的,但是以文本的方式写文件,后续加载的成本是比较高的。
所以redis就引入了"混合持久化"的方式,结合了rdb和aof的特点。
按照aof的格式 ,每次的请求/操作,都记录写入文件(文本的形式)。
在触发aof重写之后,就会把当前内存的状态按照rdb的二进制形式写入 aof文件中。
后续再进行操作,仍然是按照aof文本的方式追加到文件后面。