Redis作为目前最流行的内存数据库,持久化机制是我们必须要考虑的问题之一。这里主要总结一下Redis的持久化机制以及他们之间的优缺点。
Redis持久机制主要分为RDB和AOF。
RDB即熟称快照方式(Redis Database),AOF即文件写入方式(Append On File),下面分别介绍一下这两种方式。
RDB
RDB:快照方式,redis可以设置每隔多长时间自动生成一份当前内存中所有数据的一份快照文件。rdb文件是经过压缩的二进制文件。redis会用新的rdb文件替换旧的rdb文件,总是保存最新的一份rdb文件。
服务器在创建和载入rdb文件时主要通过SAVE命令和BGSAVE命令实现。
1、SAVE命令会阻塞Redis服务器进程,直到rdb文件创建完毕为止,在阻塞期间,服务器不能处理任何命令请求。
2、BGSAVE命令 和SAVE命令不同,BGSAVE命令会通过fork()派生出一个子进程来负责创建RDB文件,服务器进程继续处理命令请求。
子进程对当前内存中的数据进行持久化,并不会修改当前的数据结构,如果父进程收到了读写请求,那么会把处理的那一部分数据复制一份到内存,对复制后的数据进行修改,所以即使对某个数据进行了修改,redis持久化到RDB中的数据也是未修改的数据,这也是把RDB文件称为"快照"文件的原因,子进程所看到的数据在它被创建的一瞬间就固定下来了,父进程修改的某个数据只是该数据的复制品。
优点:
1、冷备:RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去。
2、持久化保持Redis高性能:当进行RDB持久化时,对redis服务处理读写请求的影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可。生成一次RDB文件的过程就是把当前时刻内存中的数据一次性写入文件中,而AOF则需要先把当前内存中的小量数据转换为操作指令,然后把指令写到内存缓存中,然后再刷写入磁盘。
3、重启和恢复快:相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis的数据会更加快速。AOF,存放的是指令日志,做数据恢复的时候,要回放和执行所有的指令日志,从而恢复内存中的所有数据。而RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可。
缺点:
1、数据丢失 :一般每隔几分钟执行一次,数据易丢失
2、RDB文件不易过大:否则客户端程序会暂停几秒,对redis性能有影响。
AOF
aof持久化是通过保存redis服务器所执行的写命令来记录数据库状态的。
redis服务器在执行完一个写命令之后,会进行参数校验,符合条件的会将执行的命令追加到服务器状态的aof_buf缓冲区末尾,然后从缓冲区中再持久化到aof文件的末尾。可以通过设置appendfsync(always,everysec,no)参数的值来设定缓冲区向硬盘进行持久化的行为,默认是everysec,每秒就要执行一次。
aof持久化造成的问题:
1、AOF文件过大问题
由于aof文件中保存的是所有执行的写命令,这样会造成文件内容随着时间流逝不断的加大,文件体积也会越来越大,这样会对redis服务器甚至整个宿主机造成影响,并且文件越大,还原时间也越长。
为了解决这个问题,redis提供了AOF文件重写。
通过该功能,redis服务器可以创建一个新的AOF文件来代替现有的AOF文件,新旧
两个AOF文件保持的数据库状态一致,但新的文件不会保护任何浪费空间的冗余命令,
所以新的文件比旧的文件体积会小很多。
2、AOF重写问题
AOF重写,redis将重写程序放到子进程执行。这样可以保证父进程继续执行命令请求,同时使用进程而不是线程避免了锁带来的安全性问题。
但是AOF重写时是直接读取的redis的数据库状态,而不是从原有的aof文件进行数据读取,命令在不断的执行,会造成数据库状态和重写aof文件数据不一致问题。
为了解决数据一致性问题,redis设置了重写缓冲区。
在重写期间,服务器进程需要执行三个工作:
1、执行客户端发来的命令
2、将执行后的写命令追加到AOF缓冲区
3、将执行后的写命令追加到AOF重写缓冲区。
当完成重写工作后子进程会向父进程发送一个信号,这时父进程会调用函数将
aof重写缓冲区的数据持久化到重写aof文件中,之后原子的替换原有的aof文件。
处理信号函数时会阻塞进程。
优点:
1、更大程度数据不丢失:一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。
2、写入性能高:AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。即使重写,也不会影响客户端操作。
3、可读性高:适合做灾难备份
缺点:
1、文件过大对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大。
2、AOF的写性能比RDB的写性能低:因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的,只不过比起RDB来说性能低,如果要保证一条数据都不丢,也是可以的,AOF的fsync设置成每写入一条数据,fsync一次,但是这样,redis的性能会大大下降。
3、基于AOF文件做恢复的速度不如基于RDB文件做恢复的速度:因为aof文件需要一条一条执行命令,而rdb直接恢复数据库状态的二进制指令就可以。
总结:
可以使用RDB和AOF相结合的方式进行Redis持久化,但是可能要考虑兼容性的问题。
2020年9月17日 更新
RDB和AOF在生成和载入文件时对过期数据的处理
生成RDB文件
生成RDB文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件中
载入RDB文件
在启动Redis服务器时,如果服务器开启了RDB功能,开始载入RDB文件时:
1、如果服务器是以主服务器模式进行,那么在载入RDB文件时,程序会对文件中保存的键进行检查,未过期的键会被载入到数据库中,而过期的键则被忽略,所以对载入RDB文件的主服务器不会造成影响。
2、如果服务器以从服务器模式运行,那么在载入RDB文件时,文件保存的所有键物理是否过期,都会被载入到数据库中。不过,因为主从服务器在进行数据同步的时候,从服务器的数据库就会被清空,所以一般来讲,过期键对载入RDB文件从服务器也不会造成影响。
AOF文件写入
当服务器以AOF模式运行时,如果数据库中的某个键已经过期,但它还没有被惰性删除或定期删除,那么AOF文件不会保存这个过期的键。
当过期的键被惰性或定期删除之后,程序会向AOF文件追加一条DEL命令,来显式地记录该键已被删除。
举例:如果客户端使用GET message命令来访问过期的message键,那么服务器会首先将数据库中的message键删除,然后追加一条DEL message命令到aof文件中,向执行GET命令的客户端返回空回复。
AOF文件的载入
和RDB模式相同
复制模式下对过期键的处理
1、主服务器在删除一个过期键之后,会显式地向所有从服务器发送一个DEL命令,告知从服务器删除这个过期键。
2、从服务器在执行客户端发送的读命令时,即使碰到过期键也不会将过期键删除,而是继续像处理未过期键一样来处理过期键
3、从服务器只有接收到主服务器发来的DEL命令之后,才会删除过期键。