Redis持久化——AOF机制详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

在运行情况下Redis 以数据结构的形式将数据维持在内存中为了让这些数据在 Redis 重启之后仍然可用需要将数据写入持久存储

持久化是指将数据写入持久存储例如固态磁盘(SSD)

Redis 提供了一系列持久化选项。这些包括

  • RDBRedis Database将数据库的快照snapshot以二进制的方式保存到磁盘中
  • AOFAppend Only File以协议文本的方式将所有对数据库进行过写入的命令及其参数记录到 AOF 文件以此达到记录数据库状态的目的
  • RDB + AOFRDB和AOF混合方式4.0版本)

RDB详解见Redis持久化——RDB机制详解

AOF

本文首先介绍 AOF 功能的运作机制了解命令是如何被保存到 AOF 文件里的观察不同的 AOF 保存模式对数据的安全性、以及 Redis 性能的影响。

之后会介绍从 AOF 文件中恢复数据库状态的方法以及该方法背后的实现机制。

最后还会介绍对 AOF 进行重写以调整文件体积的方法并研究这种方法是如何在不改变数据库状态的前提下进行的

在这里插入图片描述

AOF文件使用网络通讯协议的格式来保存这些命令

AOF例子

若执行以下命令

redis> RPUSH list 1 2 3 4
(integer) 4

redis> LRANGE list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"

redis> KEYS *
1) "list"

redis> RPOP list
"4"

那么其中两条对数据库有修改的写入命令就会被同步到 AOF 文件中

RPUSH list 1 2 3 4

RPOP list

上面列举的两个命令在 AOF 文件实际保存如下

*2
$6
SELECT
$1
0
*6
$5
RPUSH
$4
list
$1
1
$1
2
$1
3
$1
4
*2
$4
RPOP
$4
list

除了 SELECT 命令是 AOF 程序自己加上去的之外 其他命令都是之前我们在终端里执行的命令

*表示后面语句的词个数$表示后面词的字节数

AOF同步步骤

同步命令到 AOF 文件的整个过程可以分为三个阶段

  1. 命令传播 Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中
  2. 缓存追加 AOF 程序根据接收到的命令数据将命令转换为网络通讯协议的格式然后将协议内容追加到服务器的 AOF 缓存中
  3. 文件写入和保存 AOF 缓存中的内容被写入到 AOF 文件末尾如果设定的 AOF 保存条件被满足的话fsync函数或者fdatasync函数会被调用将写入的内容真正地保存到磁盘中

命令传播

当一个 Redis 客户端需要执行命令时它通过网络连接将协议文本发送给 Redis 服务器

比如说要执行命令SET KEY VALUE客户端将向服务器发送文本*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n

服务器在接到客户端的请求之后它会根据协议文本的内容选择适当的命令函数并将各个参数从字符串文本转换为 Redis 字符串对象StringObject

每当命令函数成功执行之后 命令参数都会被传播到 AOF 程序 以及 REPLICATION 程序

命令传播过程图

缓存追加

当命令被传播到 AOF 程序之后程序会根据命令以及命令的参数将命令从字符串对象转换回原来的协议文本

缓存追加过程可以分为以下三步

  1. 接受命令、命令的参数、以及参数的个数、所使用的数据库等信息
  2. 将命令还原成 Redis 网络通讯协议
  3. 将协议文本追加到aof_buf末尾

协议文本生成之后它会被追加到redis.h/redisServer结构的aof_buf末尾

redisServer结构维持着 Redis 服务器的状态aof_buf域则保存着所有等待写入到 AOF 文件的协议文本

struct redisServer {

    // 其他域...

    sds aof_buf;

    // 其他域...
};

文件写入和保存

每当服务器常规任务函数被执行、或者事件处理器被执行时aof.c/flushAppendOnlyFile函数都会被调用这个函数执行以下两个工作

  • WRITE根据条件将aof_buf中的缓存写入到 AOF 文件
  • SAVE根据条件调用fsyncfdatasync函数将 AOF 文件保存到磁盘中

两个步骤都需要根据一定的条件来执行 而这些条件由 AOF 所使用的保存模式来决定。以下会介绍 AOF 所使用的三种保存模式以及在这些模式下步骤WRITE和SAVE的调用条件

AOF 保存模式

Redis 目前支持三种 AOF 保存模式

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

保存模式优缺点

AOF重写

根据键的类型使用适当的写入命令来重现键的当前值这就是 AOF 重写的实现原理

所谓的“重写”其实是一个有歧义的词语实际上 AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取它针对的是数据库中键的当前值

AOF重写图例

AOF后台重写

AOF 重写是一个有歧义的名字实际的重写工作是针对数据库的当前值来进行的程序既不读写、也不使用原有的 AOF 文件

AOF 后台重写是为了避免主进程被阻塞无法处理请求所以采用主进程fork出子进程用于 AOF 重写。为了避免在 AOF 重写期间新命令对现有数据的修改导致的不一致问题Redis 增加了一个AOF 重写缓存这个缓存在fork出子进程之后开始启用Redis 主进程在接到新的写命令之后除了会将这个写命令的协议内容追加到现有的 AOF 文件之外还会追加到这个缓存中

在这里插入图片描述

换言之 当子进程在执行 AOF 重写时 主进程需要执行以下三个工作

  1. 处理命令请求
  2. 将写命令追加到现有的 AOF 文件中
  3. 将写命令追加到 AOF 重写缓存中

当子进程完成 AOF 重写之后它会向主进程发送一个完成信号主进程在接到完成信号之后会调用一个信号处理函数并完成以下工作

  1. 将 AOF 重写缓存中的内容全部写入到新 AOF 文件中。
  2. 对新的 AOF 文件进行改名覆盖原有的 AOF 文件

以上就是 AOF 后台重写 也即是BGREWRITEAOF命令的工作原理

AOF优缺点

  • 优点
    • 拥有不同的fsync策略fsync是使用后台线程执行的写入性能很好
    • AOF是一个仅追加日志没有查找和断电时的损坏问题。即使由于某种原因磁盘已满或其他原因日志以写入一半的命令结束redis-check-aof工具也能够轻松修复它
    • 当 AOF 变得太大时Redis 能够在后台自动重写 AOF
    • AOF 以易于理解和解析的格式包含一个接一个地记录所有操作的日志使得导出和恢复十分简单
  • 缺点
    • 对于相同的数据集AOF 文件通常比等效的 RDB 文件大

    • 根据确切的 fsync 策略AOF 可能比 RDB 慢

      Redis < 7.0

    • 如果在重写期间有对数据库的写入AOF 会使用大量内存

    • 重写期间到达的所有写入命令都会写入磁盘两次

    • Redis 可能会在重写结束时冻结写入并将这些写入命令同步到新的 AOF 文件

RDB和AOF混合方式4.0版本)

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说内存快照以一定的频率执行在两次快照之间使用 AOF 日志记录这期间的所有命令操作。

这样一来快照不用很频繁地执行这就避免了频繁 fork 对主线程的影响。而且AOF 日志也只用记录两次快照间的操作也就是说不需要记录所有操作了因此就不会出现文件过大的情况了也可以避免重写开销。

如下图所示T1 和 T2 时刻的修改用 AOF 日志记录等到第二次做全量快照时就可以清空 AOF 日志因为此时的修改都已经记录到快照中了恢复时就不再用日志了。

这个方法既能享受到 RDB 文件快速恢复的好处又能享受到 AOF 只记录操作命令的简单优势, 实际环境中用的很多。


参考资料

  1. Redis persistence
  2. Redis 设计与实现
  3. Redis持久化详解
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: redis