Redis 持久化详解:AOF、RDB 与混合持久化如何平衡性能和可靠性

引言

Redis 作为内存数据库,虽然读写速度非常快,但也正因为数据主要存放在内存中,一旦进程退出、机器宕机或者服务异常重启,如果没有持久化机制,数据就可能全部丢失。

因此,持久化是 Redis 保障数据可靠性的关键能力。

Redis 主要提供两类持久化方式:

  • AOF(Append Only File)
  • RDB(Redis DataBase Snapshot)

前者偏向记录操作过程,后者偏向记录某一时刻的数据结果。Redis 4.0 之后又进一步提供了混合持久化方案,用于在性能和数据安全之间做更好的平衡。

本文就从这三部分出发,梳理 Redis 持久化的核心机制和适用思路。

什么是 AOF 日志

AOF 的全称是 Append Only File。它的核心思路是:

  • 把 Redis 收到的写命令,以追加的方式记录到日志文件中

当 Redis 重启恢复时,就可以重新执行这些命令,从而恢复数据。

AOF 日志格式

AOF 中记录的是 Redis 执行过的写命令,这些命令会以协议相关的文本形式写入文件。

例如一次 SET、一次 HSET、一次 INCR,都会被追加到 AOF 文件中。

所以可以把 AOF 理解成:

  • 一份"命令流水账"

它记录的不是某个时间点的全量数据,而是"为了变成现在这个状态,Redis 都执行过哪些命令"。

AOF 日志写入时机

AOF 和很多数据库日志的设计思路不完全一样。

Redis AOF 采用的是:

  • 写后日志

也就是:

  1. 先执行命令
  2. 再把命令写入 AOF 日志

为什么采用写后日志

这么设计有几个明显好处:

  1. 只有真正执行成功的命令才会被记录
  2. 不会把错误命令写进日志
  3. 可以减少额外校验和回滚处理的复杂度

但它也带来一个问题:

  • 如果命令执行成功了,但日志还没来得及落盘,Redis 就宕机了,那么这条命令就会丢失

所以 AOF 的可靠性,很大程度上取决于写回策略。

AOF 的三种写回策略

Redis 提供了三种典型的 AOF 写回策略,用于在性能和数据安全之间做取舍。

Always:每条命令都立即写回

Always 的意思是:

  • 每执行完一条写命令,就立刻同步把日志写回磁盘

它的优点是:

  • 数据最安全
  • 宕机时最多只会丢失极小范围内的操作

缺点也很明显:

  • 每条命令都要触发磁盘同步
  • 对性能影响最大

所以它更适合数据可靠性要求极高、但吞吐压力不算特别大的场景。

Everysec:每秒写回一次

Everysec 是 Redis AOF 的默认常见策略。

它的方式是:

  1. 写命令执行完后,先把日志写入内存缓冲区
  2. 每隔一秒把缓冲区内容写回磁盘

它的优点是:

  • 性能和安全性比较平衡
  • 对大多数业务来说是一个比较稳妥的选择

它的代价是:

  • 理论上可能丢失 1 秒左右的数据

No:由操作系统决定何时写回

No 的意思是:

  • Redis 只负责把日志写到 AOF 文件对应的内存缓冲区
  • 具体什么时候刷盘,交给操作系统决定

这种策略的优点是:

  • 性能最好

缺点是:

  • 可控性最差
  • 一旦宕机,可能丢失的数据会更多

因此工程上更常用的通常还是 Everysec

为什么需要 AOF 重写

AOF 有一个天然问题:

  • 文件会越来越大

因为 AOF 是通过追加命令记录变化的,只要有写请求,文件就会持续增长。

如果一个键被反复修改很多次,AOF 中就会保留很多条历史命令。例如:

text 复制代码
SET k 1
SET k 2
SET k 3
SET k 4

但恢复数据时,真正有意义的其实只是最后一次结果。

这就意味着:

  • AOF 文件会不断膨胀
  • 恢复时间也会越来越长

所以 Redis 引入了 AOF 重写机制。

AOF 重写是怎么做的

AOF 重写的核心思想是:

  • 不再基于旧 AOF 文件逐条改写
  • 而是基于当前内存中的最新数据状态,重新生成一份更精简的新 AOF 文件

这样一来,一个键值对最终只需要保留能够表达"当前状态"的命令,而不需要保留所有历史修改过程。

例如某个键最终值是 4,那么重写后只需要一条:

text 复制代码
SET k 4

而不需要保留前面的 SET k 1SET k 2SET k 3

AOF 重写过程怎么理解

AOF 重写过程常被概括成:

  • 一个拷贝
  • 两处日志

一个拷贝

当 Redis 执行 AOF 重写时,主线程会通过 fork 创建一个后台子进程,比如 bgrewriteaof

这个子进程会基于当前内存数据,生成新的 AOF 文件。

这里要注意一点:

  • fork 并不会立刻把整块物理内存完整复制一份

子进程复制的主要是父进程的页表,也就是虚拟内存到物理内存的映射关系。父子进程在初始阶段会共享同一份物理内存,只有后续发生写入时,才会通过写时复制机制分离。

所以更准确地说,这里不是"立刻完整拷贝所有内存数据",而是:

  • 先共享内存映射
  • 需要修改时再复制

两处日志

在 AOF 重写期间,Redis 主线程并不会停止处理新的写请求。

这时新写操作会同时落到两个地方:

第一处:原有 AOF 缓冲区

新的写命令仍然会写入当前正在使用的 AOF 缓冲区。

这样即使在重写过程中发生宕机,原来的 AOF 仍然是完整可用的。

第二处:AOF 重写缓冲区

新的写命令也会写入 AOF 重写缓冲区。

等后台子进程完成新 AOF 文件重写后,这部分"重写期间产生的新命令"会被追加到新的 AOF 文件末尾,确保新文件也能反映数据库最新状态。

所以整个过程的关键就是:

  • 一边生成新 AOF
  • 一边不丢失重写期间的新写入

什么是 RDB 快照

和 AOF 不同,RDB 记录的不是命令过程,而是:

  • 某一时刻 Redis 的全量数据快照

RDB 文件是二进制格式,因此恢复时可以直接把快照内容读入内存,而不需要逐条重放命令。

这也是为什么:

  • RDB 恢复速度通常比 AOF 更快

生成 RDB 时会阻塞主线程吗

Redis 提供了两个命令生成 RDB 文件:

  • save
  • bgsave

save

save 会在主线程中直接执行快照生成,因此会阻塞 Redis 主线程。

这意味着:

  • 在生成 RDB 文件期间,Redis 无法正常处理其他请求

所以线上生产环境一般不推荐直接使用它。

bgsave

bgsave 会创建一个后台子进程来生成 RDB 文件,从而避免主线程长时间阻塞。

这也是 Redis 中更常见的快照方式。

所以如果希望尽量不影响业务请求,通常应当使用:

  • bgsave

生成 RDB 时,数据还能被修改吗

可以。

Redis 在执行 bgsave 时,会借助操作系统提供的:

  • 写时复制(Copy-On-Write,简称 COW)

来保证快照和在线写请求可以同时进行。

写时复制怎么理解

当主线程 forkbgsave 子进程后,父子进程初始时共享同一份物理内存页面。

如果主线程只读数据

如果主线程只是读取某块数据,那么它和 bgsave 子进程可以继续共享同一份内存,彼此没有影响。

如果主线程修改数据

如果主线程要修改某块数据,那么操作系统会把这块数据复制一份出来。

之后:

  • 主线程修改新的副本
  • bgsave 子进程继续读取旧数据

这样就保证了:

  • RDB 快照写入的是某一时刻的稳定数据
  • 主线程也能继续处理新的写请求

这就是 COW 在 Redis 快照中的核心作用。

Redis 持久化的最佳方案怎么选

如果只用 RDB:

  • 恢复速度快
  • 文件紧凑
  • 但两次快照之间如果发生宕机,可能丢失较多数据

如果只用 AOF:

  • 数据安全性通常更高
  • 可控性更强
  • 但文件更大,恢复过程也可能更慢

所以 Redis 4.0 提出了混合持久化方案。

什么是混合持久化

混合持久化的核心思路是:

  • 以 RDB 快照作为基础
  • 在两次快照之间,用 AOF 记录增量命令

也就是说:

  1. 定期做一次内存快照
  2. 快照之后的写操作,再通过 AOF 记录

这样做的好处是:

  • 不需要频繁执行全量快照,减少 fork 带来的影响
  • AOF 只需要记录两次快照之间的操作,文件不会无限膨胀得太快
  • 恢复时可以先加载快照,再重放后续少量 AOF 命令,兼顾恢复速度和数据安全

为什么混合持久化更平衡

混合持久化本质上是在吸收两种方案的优点:

  • 用 RDB 解决全量恢复效率问题
  • 用 AOF 解决快照间隔导致的数据丢失问题

所以如果从性能、恢复效率和数据安全这三个维度综合考虑,混合持久化通常是更均衡的方案。

总结

这篇文章可以压缩成几条核心结论:

  1. AOF 记录的是写命令,采用写后日志机制
  2. AOF 有 AlwaysEverysecNo 三种写回策略,其中 Everysec 是常见平衡方案
  3. AOF 重写不是基于旧日志裁剪,而是基于当前内存状态重建精简日志
  4. RDB 记录的是某一时刻的全量快照,恢复速度通常更快
  5. save 会阻塞主线程,bgsave 则通过后台子进程减少阻塞
  6. RDB 在生成快照时依赖写时复制技术,保证主线程仍可继续处理写请求
  7. Redis 4.0 的混合持久化方案,能够更好地平衡性能、恢复速度和数据安全

如果把 Redis 持久化的目标概括成一句话,那就是:

"尽量少影响在线性能,同时尽量少丢数据,并尽量提高恢复效率。"


如果这篇文章对你有帮助,欢迎继续阅读本系列后续内容。若文中有不准确或需要补充的地方,也欢迎指出。

相关推荐
qqxhb2 小时前
23|工具生态全景:本地文件、网络、数据库、浏览器自动化
网络·数据库·自动化·ai编程·最小权限·人工确认
Meme Buoy2 小时前
10.2需求分析-获取-定义-验证-管理
数据库·需求分析
Trouvaille ~2 小时前
【MySQL篇】从零开始:安装与基础概念
linux·数据库·mysql·ubuntu·c·教程·基础入门
一个有温度的技术博主2 小时前
Redis Cluster 核心原理:哈希槽与数据路由实战
redis·算法·缓存·哈希算法
周末也要写八哥2 小时前
追求性能极致为何不用Redis?
数据库·redis·缓存
JosieBook3 小时前
【Redis】Redis如何修改密码?
数据库·redis·bootstrap
gihigo19983 小时前
基于MSComm控件的PC串口通信程序(中断方式接收数据)
数据库·mongodb
十五年专注C++开发3 小时前
达梦数据库在Linux备份报错 -8003: 缺少本地或者远程归档 解决方案
数据库·c++·dm·备份复原