AOF日志与RDB是Reids中两大持久化机制,当服务器或者Reids宕机的时候可以通过这两大机制恢复Redis的数据。
先说说AOF日志吧,在执行一条操作请求时,Redis先将命令在内存中执行,之后再将命令写到AOF日志中,与我们熟悉的MySQL的redo log日志先写日志再执行sql的顺序刚好相反。
这么做的好处主要有两点:
- 先执行命令再写入AOF日志确保命令不存在语法错误能正常的被执行;
- 不阻塞主线程;
在Redis中AOF日志有三种写回的策略:
- Always,同步写回。执行完命令立即写入AOF文件;
- Everysec,每秒写回。执行完命令后将命令写入缓冲区,每秒将缓冲区命令写入AOF文件;
- No,由操作系统写回。执行完命令后将命令写入缓冲区,由操作系统决定何时将缓冲区命令写入AOF文件;
由于持续不断的操作Redis服务,这时AOF日志文件的将持续变大,将会带来一些性能上的问题:
- 系统无法保存过大的文件;
- AOF文件过大时将会影响命令写入的效率;
- 如果发生宕机,AOF文件过大会导致数据恢复变得缓慢;
针对AOF文件过大问题Redis采用重写AOF文件的方式来避免AOF文件过大带来的性能问题。与AOF日志由主线程写入的方式不同,AOF重写由后台子线程bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
重写的过程主要体现在两个方面:一个拷贝,两处日志。
Redis中通过auto-aof-rewrite-min-size、auto-aof-rewrite-percentage来判断是否触发重写机制,当AOF文件大小同时超出这两个参数设定的值后就会触发AOF重写。
当触发AOF重写后,主线程会fork一个子线程bgrewriteaof ,同时将复制一份主线程的页表(一个拷贝)给子线程,这样子线程就能访问到内存中的数据了,在不影响主线程的情况下逐一将数据转成命令记录重写日志。
在AOF日志重写过程中,当有新的操作命令的时候,Redis会将命令写入AOF缓冲区的同时也会写入重写AOF的缓冲区(两处日志),当重写完成后,重写缓冲区的命令会写入新的AOF文件中。此时,新的AOF文件就可以代替旧的AOF文件了。
你可能会疑惑为什么重写后的AOF文件会比较小呢?
因为旧的AOF文件记录着每一条操作命令,可能存在多条命令执行同一个数据的情况,而AOF重写是将内存中的数据转成命令存储这样一条数据就只会存在一条命令,从而达到缩小AOF文件文件大小的目的。
与AOF日志相比RDB快照的逻辑就相对简单一些。
RDB快照可以理解为Redis数据的全量备份,Redis通过两个命令来生成RDB文件:
- save:在主线程中执行,会阻塞主线程;
- bgsave:创建一个子线程去写入RDB文件,避免了主线程阻塞,Redis默认配置;
首先在Redis主线程会fork一个子线程bgsave,同时复制一份主线程页表给bgsave,这样bgsave子线程就能读到主线程的内存中的数据了将其写到RDB快照中,所以不会影响主线程的读操作。
但是,如果是一个操作请求这时Redis为了保证正常操作请求会借助系统的写时复制技术(Copy-On-Write, COW),当有操作请求时,主线程会申请一份新的内存空间存放数据同时修改自己的页表映射。
这样既保证了快照的完整性,也保证了主线程的正常操作。
在Redis4.0后提出了混合使用AOF和RDB快照的方法,先通过全量备份Redis数据的RDB快照,之后通过AOF日志文件做增量备份。