这篇文章简单聊下redis里的RDB与AOF两种持久化。

RDB(redis database)持久化的特点,它可以手动执行也可以通过配置定期执行,手动执行的命令是SAVE与BGSAVE,其中SAVE会阻塞redis服务器进程,直到RDB文件创建完成,在创建过程中,服务器不处理其它命令;BGSAVE则会派生出一个子进程,由子进程创建RDB文件,服务器进程继续处理其它命令。如果是通过配置,那配置的方法是:

save 900 1
save 300 10
save 60 10000

只要满足三个中的一个,BGSAVE就会执行:

  • 服务器在900S之内,对数据库进行了至少1次修改。
  • 服务器在300S之内,对数据库进行了至少10次修改。
  • 服务器在60S之内,对数据库进行了至少10000次修改。

再说下RDB的文件保存的是所有的键值对数据,是经过压缩后的二进制文件,如果键值带有过期时间,那么过期时间也会被保存起来。

AOF(append only file)所存的内容是写命令,且是以纯文本形式保存。服务器在执行完一个写命令之后,会将这个写命令追加到aof_buf缓冲区末尾。AOF可以通过配置appendfsync的值来控制将缓冲区写入和保存到AOF文件的频率,可配置的值有:always/everysec/no。

AOF数据不同步的问题
因为是将写命令先写到aof_buf缓存区然后间隔一段时间后再写入到AOF文件里,如果在写入文件之前数据进行了修改,则会造成内存里的数据与AOF文件里的数据不一致。针对这个问题,redis会在后台fork一个子进程进行AOF重写:先生成一个新的AOF文件,然后使用新生成的文件替换旧的AOF文件。

AOF文件多条重复命令问题
在AOF重写过程中,会去数据库里读取键现有的值(而不是去分析已生成的旧的AOF文件),如果可以使用一条命令进行记录则只记一条。比如:

redis> RPUSH list "a" "b"
2
redis> RPUSH list "c"
3

先生成的旧的AOF文件会分别对应两条命令,而重写的AOF经过分析了现在数据库里存的数据后会将上面两条命令合成一条进行记录。Redis使用另外的线程来进行数据重写,这个过程不会阻塞主线程。

这里再对rdb与aof进行一下对比:

  • rdb优点:体积小(存的是数据)、恢复快、性能影响小(fork子进程)
  • rdb缺点:数据丢失可能性大(不能频繁执行)、影响cpu(fork时间长后会有影响)
  • aof优点:数据丢失可能性小
  • aof缺点:体积大(存的是命令)、性能影响大(在主线程中先记录命令再记录日志,虽然不会阻塞当前写但会有磁盘压力,要是AOF很慢会影响下一次写)、恢复慢(需要解析命令)

针对AOF在主线程中写AOF给磁盘带来的压力,有以下三种策略:

  1. Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
  2. Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲 区,每隔一秒把缓冲区中的内容写入磁盘;
  3. No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓 冲区,由操作系统决定何时将缓冲区内容写回磁盘。

image.png

提到了AOF追加阻塞问题
image.png

选择哪种需要根据业务场景来定:

  1. 对性能要求高、需要快速恢复建议使用rdb
  2. 对数据完整性要求高,建议使用aof
  3. 需要两者兼容,可使用二者混合(redis4.0后)

参考:AOF日志


步履不停
38 声望13 粉丝

好走的都是下坡路