Redis 持久化 AOF 原理:命令追加、重写与混合模式

好的,没问题,直接开始!

各位老铁,大家好!今天咱们来聊聊 Redis 的持久化,特别是 AOF (Append Only File) 这种姿势。这玩意儿啊,说白了就是把咱们对 Redis 的所有操作都记下来,像个小本本一样,万一 Redis 宕机了,还能照着小本本重放一遍,数据就回来啦!

一、AOF:一个尽职尽责的小本本

AOF 的核心思想很简单:每次执行完写操作(SETHSETDEL 等等),就把这条命令以追加的方式写到 AOF 文件里。这样,即使 Redis 挂了,重启后也能通过重新执行 AOF 文件里的命令,恢复到之前的状态。

  1. 命令追加 (Command Append)

    AOF 的第一步,就是把命令追加到 AOF 文件。这个过程就像咱们写日记,每天都往后加,永远不回头改。

    Redis 内部的实现大概是这样:

    // 假设我们执行了 SET mykey myvalue 命令
    char *command = "SET mykey myvalue";
    
    // 把命令格式化成 Redis 的协议格式
    char *redis_protocol = redisFormatCommand(command);
    
    // 把格式化后的命令追加到 AOF 缓冲区
    aof_buf_append(redis_protocol, strlen(redis_protocol));
    
    // 把 AOF 缓冲区的数据刷到磁盘
    aof_flush_to_disk();

    redisFormatCommand 函数负责把命令转换成 Redis 协议格式,这个格式是 Redis 客户端和服务器之间通信的标准。例如,SET mykey myvalue 会被转换成:

    *3rn$3rnSETrn$5rnmykeyrn$7rnmyvaluern

    这个格式看起来有点吓人,但其实很简单:

    • *3:表示这个命令有 3 个参数(SETmykeymyvalue)。
    • $3:表示第一个参数(SET)的长度是 3 个字节。
    • rn:是换行符,用于分隔参数。

    aof_buf_append 函数负责把格式化后的命令追加到 AOF 缓冲区。这个缓冲区是内存里的一块区域,用于临时存放要写入 AOF 文件的命令。

    aof_flush_to_disk 函数负责把 AOF 缓冲区的数据刷到磁盘。这个过程才是真正把数据写入 AOF 文件。

  2. AOF 刷盘策略 (AOF Flush Policies)

    把 AOF 缓冲区的数据刷到磁盘,这个过程可不是随便刷的,Redis 提供了三种刷盘策略:

    • always (每次写都刷):每次执行完写命令,都立即把 AOF 缓冲区的数据刷到磁盘。这种策略最安全,但性能也最差,因为每次都要进行磁盘 I/O。
    • everysec (每秒刷一次):每秒钟把 AOF 缓冲区的数据刷到磁盘。这种策略在安全性和性能之间做了一个折中,即使 Redis 宕机,最多也只会丢失 1 秒钟的数据。
    • no (让操作系统来决定):让操作系统来决定何时把 AOF 缓冲区的数据刷到磁盘。这种策略性能最好,但安全性也最差,因为操作系统可能会延迟刷盘,导致数据丢失。

    这三种策略可以通过 redis.conf 文件进行配置:

    appendfsync always
    # appendfsync everysec
    # appendfsync no
    刷盘策略 安全性 性能
    always 最高 最低
    everysec 中等 中等
    no 最低 最高

    选择哪种策略,取决于你的应用对数据安全性和性能的要求。如果你的应用对数据安全性要求很高,那就选择 always 策略。如果你的应用对性能要求很高,那就选择 no 策略。大多数情况下,everysec 策略是一个不错的选择。

二、AOF 重写:给小本本瘦身

随着时间的推移,AOF 文件会越来越大,因为每次写操作都会被记录下来。即使我们删除了某个键,AOF 文件里仍然会保留删除命令。这就像咱们的日记,写了很多废话,占地方不说,还影响查找。

为了解决这个问题,Redis 引入了 AOF 重写机制。AOF 重写并不是简单地把旧的 AOF 文件压缩一下,而是通过读取 Redis 数据库的当前状态,然后用最少的命令来生成一个新的 AOF 文件。

  1. 重写原理 (Rewrite Principles)

    AOF 重写的核心思想是:只记录数据库的当前状态,而不是记录所有的操作历史。

    举个例子,假设我们执行了以下命令:

    SET mykey value1
    SET mykey value2
    DEL mykey

    如果没有 AOF 重写,AOF 文件里会记录这三条命令。但是,如果进行 AOF 重写,新的 AOF 文件只会记录数据库的当前状态,也就是空数据库,所以新的 AOF 文件里不会有任何命令。

    再举个例子,假设我们执行了以下命令:

    SET mykey value1
    SET mykey value2

    如果没有 AOF 重写,AOF 文件里会记录这两条命令。但是,如果进行 AOF 重写,新的 AOF 文件只会记录最后一条命令,也就是 SET mykey value2

    AOF 重写的流程大概是这样:

    • Redis 创建一个新的 AOF 文件 (temp file)。
    • Redis 遍历数据库,把每个键值对转换成 SET 命令,然后写入到新的 AOF 文件。
    • Redis 把重写期间执行的写命令,追加到一个内存缓冲区。
    • 当数据库遍历完成后,Redis 把内存缓冲区里的命令追加到新的 AOF 文件。
    • Redis 用新的 AOF 文件替换旧的 AOF 文件。
  2. 重写触发 (Rewrite Trigger)

    AOF 重写可以手动触发,也可以自动触发。

    • 手动触发:可以通过执行 BGREWRITEAOF 命令来手动触发 AOF 重写。
    • 自动触发:可以通过配置 redis.conf 文件来自动触发 AOF 重写:
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    • auto-aof-rewrite-percentage:表示当前 AOF 文件的大小,超过上一次重写后的 AOF 文件大小的百分之多少时,触发 AOF 重写。例如,如果设置为 100,表示当前 AOF 文件的大小是上一次重写后的 AOF 文件大小的 2 倍时,触发 AOF 重写。
    • auto-aof-rewrite-min-size:表示 AOF 文件最小多大时,才触发 AOF 重写。

    这两个参数共同决定了 AOF 重写的触发时机。只有当 AOF 文件的大小同时满足这两个条件时,才会触发 AOF 重写。

  3. 重写过程 (Rewrite Process)

    AOF 重写是一个比较耗时的过程,为了避免阻塞主线程,Redis 把 AOF 重写放在一个子进程里执行。

    这样,主线程可以继续处理客户端的请求,而子进程则负责 AOF 重写。

    但是,这样做也会带来一个问题:在 AOF 重写期间,如果主线程执行了写命令,这些命令不会被立即写入到新的 AOF 文件,而是会被追加到一个内存缓冲区。

    当 AOF 重写完成后,Redis 会把内存缓冲区里的命令追加到新的 AOF 文件,然后用新的 AOF 文件替换旧的 AOF 文件。

    这个过程保证了 AOF 重写期间的数据一致性。

三、混合持久化 (Mixed Persistence)

AOF 有它的优点,就是数据安全性高,但是缺点也很明显,就是文件体积大,恢复速度慢。RDB 则相反,文件体积小,恢复速度快,但是数据安全性不如 AOF。

Redis 5.0 引入了混合持久化,就是把 RDB 的优点和 AOF 的优点结合起来。

  1. 混合模式原理 (Mixed Mode Principles)

    混合持久化的核心思想是:AOF 文件的前半部分是 RDB 格式的数据,后半部分是 AOF 格式的命令。

    这样,在 Redis 重启时,可以先加载 RDB 格式的数据,然后再执行 AOF 格式的命令。

    混合持久化的优点是:

    • 恢复速度快:因为 RDB 格式的数据加载速度比 AOF 格式的命令执行速度快。
    • 数据安全性高:因为 AOF 格式的命令可以保证数据的完整性。

    混合持久化的缺点是:

    • 文件体积比 RDB 大:因为 AOF 格式的命令会占用一定的空间。
  2. 开启混合模式 (Enable Mixed Mode)

    可以通过配置 redis.conf 文件来开启混合持久化:

    aof-use-rdb-preamble yes

    aof-use-rdb-preamble 设置为 yes,就开启了混合持久化。

  3. 混合模式下的重写 (Rewrite in Mixed Mode)

    在混合模式下,AOF 重写的流程和之前的流程基本相同,唯一的区别是:新的 AOF 文件的前半部分是 RDB 格式的数据,后半部分是 AOF 格式的命令。

    这样,在 Redis 重启时,可以先加载 RDB 格式的数据,然后再执行 AOF 格式的命令,从而实现快速恢复和数据安全。

四、AOF 总结与建议

特性 描述 优点 缺点
命令追加 记录所有写操作,追加到 AOF 文件末尾。 数据安全性高,即使 Redis 宕机,也能通过重新执行 AOF 文件里的命令恢复到之前的状态。 文件体积大,恢复速度慢。
重写 通过读取 Redis 数据库的当前状态,然后用最少的命令来生成一个新的 AOF 文件。 可以减小 AOF 文件的体积,提高恢复速度。 重写过程比较耗时,需要占用一定的 CPU 资源。
混合模式 AOF 文件的前半部分是 RDB 格式的数据,后半部分是 AOF 格式的命令。 结合了 RDB 和 AOF 的优点,既能保证数据安全性,又能提高恢复速度。 文件体积比 RDB 大。
刷盘策略 always (每次写都刷),everysec (每秒刷一次),no (让操作系统来决定)。 always 安全性最高,no 性能最高,everysec 在安全性和性能之间做了一个折中。 always 性能最低,no 安全性最低。
建议 根据应用对数据安全性和性能的要求,选择合适的 AOF 刷盘策略和重写策略。如果对数据安全性要求很高,那就选择 always 策略。如果对性能要求很高,那就选择 no 策略。大多数情况下,everysec 策略是一个不错的选择。

AOF 就像一个尽职尽责的小本本,记录了我们对 Redis 的所有操作。通过 AOF 重写,我们可以给小本本瘦身,让它更加高效。通过混合持久化,我们可以把 RDB 和 AOF 的优点结合起来,实现快速恢复和数据安全。

总而言之,AOF 是 Redis 持久化的一种重要方式,掌握 AOF 的原理和使用,对于保证 Redis 数据的安全性和可靠性至关重要。

好了,今天的分享就到这里,希望对大家有所帮助!如果有什么问题,欢迎留言讨论!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注