跳转至

Redis Core

磁盘持久化

AOF

AOF(Append Only File)日志是Redis数据持久化的方式之一,它属于写后日志(命令执行完再记录日志,和数据库中的写前日志(WAL)刚好相反)

写后日志的好处:

  1. 天然的过滤错误命令(只有正常执行的命令才会走到日志存储这里)
  2. 不阻塞写操作(因为日志是命令执行后才执行)

AOF存在的两个风险:

  1. 刚执行完写命令,还未记录日志(写盘),系统宕机了
  2. AOF在主线程中执行,如果写盘太慢,会阻塞后面的操作也无法执行

仔细观察,会发现这两个风险都与写盘操作(时机)有关,如果能控制写命令执行完后的AOF写盘时机,就可以解除这两个风险,AOF提供了三种写盘策略:

  • Always,同步写回:每个写命令执行完,立马同步日志到磁盘
  • Everysec,每秒写回:写命令执行完,先把日志写入到AOF内存缓冲区,每隔一秒将缓冲区数据写入磁盘
  • No,操作系统控制的写回:写命令执行完,先把日志写入到AOF内存缓冲区,由操作系统决定何时写入磁盘

三种策略的优缺点:

配置项 写回时机 优点 缺点
Always 同步写回 可靠性高,数据基本不丢失 每个写命令都要落盘,性能影响较大
Everysec 每秒写回 性能适中 宕机时丢失1s内数据
No 操作系统控制写回 性能好 宕机时丢失数据较多

由于AOF日志会记录所有的写命令,所以AOF文件会越来越大,主要有以下几个性能问题:

  1. 系统对文件大小有限制,无法保存过大文件
  2. 文件太大,每次追加内容时效率也低
  3. 若发生宕机,需要使用AOF文件恢复数据,日志文件太大,恢复数据较慢且需要一个一个执行写命令

鉴于以上种种问题(基本是由于文件过大导致的),AOF提供了重写机制

重写机制具有"多变一"功能,也就是说,旧日志文件中的多条写命令,在重写后的新日志中变成一条命令,在使用AOF恢复数据时,只需要执行这一条命令也可以正确的恢复数据

AOF重写日志会阻塞吗?

不会,与AOF日志由主线程写回不同,重写过程由后台子进程bgrewriteaof来完成,也是为了避免主线程阻塞,导致数据库性能下降

AOF重写的过程可以总结为:"一个拷贝,两处日志"

一个拷贝是指:在进行重写时,主线程fork出后台的bgrewriteaof子进程,fork会把主线程的内存拷贝一份给bgrewriteaof,里面就包含了数据库的最新数据,然后bgrewriteaof在不影响主线程的情况下,实现日志的重写操作,并生成新的日志重写文件

两处日志:

  • 第一处:主线程未被阻塞,仍然可以执行写操作,仍然会被记录AOF日志(这里Redis会将日志写入缓冲区)
  • 第二处:新的重写日志,主线程目前执行的写操作,也会被copy一份到重写日志的缓冲区,当完成日志重写后,重写日志会将缓冲区中的内容写入到重写日志中,以保证数据库最新状态的记录,此时可以使用重写日志文件替换旧日志文件了

RDB

前面了解到AOF是以日志文件的形式进行持久化,日志文件太大会影响数据恢复的时间(因为需要把日志中的命令都执行一遍),下面介绍另外一种持久化方案:内存快照(Redis Database,RDB)。

与AOF相比,RDB记录的是某一时刻的数据,并不是操作,所以在数据恢复时可以直接把RDB文件读入内存,恢复相对比AOF的写命令快

内存快照需要考虑的两个点:

  • 对哪些数据进行快照?关系到快照的执行效率
  • 做快照时,数据还能被增删改吗?(Redis是否被阻塞,能否同时正常的处理请求?)