
Redis 的数据主要放在内存里所以它速度很快。但这也会带来一个问题如果 Redis 进程崩溃或者服务器突然断电内存中的数据怎么办如果没有任何持久化机制Redis 运行 ↓ 数据只在内存 ↓ 服务器断电 ↓ 内存数据丢失因此 Redis 提供了两种最核心的持久化机制RDB和AOF。官方把两者概括得很清楚RDB保存某个时间点的数据快照AOF则记录服务器收到的写操作并在重启时重新执行这些操作恢复数据。1. Redis 持久化到底是什么所谓持久化就是把原本主要存在内存中的数据保存到磁盘等持久存储中使 Redis 重启以后可以恢复数据。Redis 常见的几种选择是RDBAOFRDB AOF或者完全关闭持久化。如果 Redis 只是纯缓存底层数据库可以重新构建全部数据有些场景确实可以不启用持久化。如果 Redis 本身保存了重要业务数据就必须认真考虑持久化和备份策略。2. 什么是 RDBRDB可以理解成在某一个时间点把 Redis 当前的数据集整体保存成一个快照。例如上午 10 点Redis 内存 A 100 B 200 C 300Redis 生成一次 RDB10:00 快照 A 100 B 200 C 300之后数据继续变化10:03 A 150 B 250 C 300但是之前生成的 RDB 仍然代表10:00 那一刻的数据状态。所以RDB的核心关键词就是Snapshot也就是快照。Redis 默认的 RDB 文件名通常是dump.rdb。3. RDB 怎么触发Redis 可以根据配置自动产生 RDB也可以手动触发。例如save 60 1000可以理解为在满足对应时间和修改次数条件后触发快照。也可以执行BGSAVE让 Redis 在后台生成 RDB。还有一个命令SAVE也可以生成快照。但SAVE是同步执行的在保存期间会阻塞其他客户端因此生产环境通常不会随便使用一般更常使用BGSAVE。4. BGSAVE 为什么不会一直阻塞 Redis执行BGSAVE时Redis 会创建子进程。大致可以理解Redis 父进程 ↓ fork() ↓ ┌───────────────┐ │ │ ↓ ↓ 父进程 子进程 继续处理请求 生成 RDB子进程负责把数据写入临时 RDB 文件。生成完成后再用新的 RDB 替换旧文件。所以磁盘写 RDB 的主要工作不会直接由处理客户端请求的父进程完成。5. fork 以后是不是直接复制一整份内存不是简单地立刻把整个内存复制一份。这里用到了操作系统的Copy-On-Write也就是写时复制。刚刚fork()完成时父进程和子进程可以共享相同的物理内存页。可以简单理解fork 后 父进程 ─┐ ├── 共享内存 Page 子进程 ─┘子进程看到的是 fork 那一刻的数据快照。如果之后客户端执行SET user:1 newValue父进程需要修改某个共享内存页时操作系统才会复制对应页面原 Page ↓ 发生修改 ↓ 复制一份 ↓ 父进程使用新 Page 子进程继续使用旧 Page这样子进程仍然可以稳定地把 fork 时刻的数据写入 RDB。这就是Copy-On-Write。6. Copy-On-Write 会不会完全没有额外内存开销不会。虽然 fork 时不会立即复制整个 Redis 数据集但如果BGSAVE期间发生大量写操作越来越多内存页被修改就会产生越来越多的写时复制。例如Redis 数据集很大 BGSAVE 正在进行 大量 SET / HSET / DEL ↓ 大量内存 Page 被修改 ↓ Copy-On-Write 增加 ↓ 额外内存占用上升所以大数据量 Redis 执行后台持久化时需要给系统留出足够的内存空间。此外大实例执行fork()本身也可能带来短暂延迟因为操作系统仍然需要处理页表等数据结构。Redis 官方也专门把 fork 延迟列为需要关注的性能问题。7. RDB 最大的问题是什么假设10:00 生成 RDB然后10:01 写入数据 A 10:02 写入数据 B 10:03 写入数据 C但是下一次 RDB 还没有生成。此时10:04 服务器断电那么恢复时只能加载10:00的 RDB。也就是说10:00 之后 到宕机之前这段时间的数据可能丢失。所以 RDB 最大的缺点是它只能恢复到最近一次快照而不能天然保证恢复到宕机前的最新状态。官方同样指出如果只依赖 RDB在异常停止时需要接受最近一段时间数据丢失的可能。8. RDB 有什么优点虽然数据安全性不如高频 AOF但 RDB 有很多优点。首先RDB 是一个比较紧凑的二进制快照文件非常适合备份传输灾难恢复其次Redis 重启时直接加载快照通常会比重放大量 AOF 命令更快。另外RDB 平时不需要为每一次写操作都追加一条磁盘日志因此运行时持久化开销相对较低。官方也明确把文件紧凑、适合备份和灾备、重启恢复较快列为 RDB 的主要优势。9. 什么是 AOFAOF全称是Append Only File它的思路和 RDB 完全不同。RDB 记录某一个时间点 Redis 中有什么数据。AOF 更关注Redis 执行了什么写操作。例如依次执行SET count1INCR count INCR countAOF 会记录这些导致数据发生变化的操作。重启以后读取 AOF ↓ 重新执行这些写操作 ↓ SET count 1 ↓ INCR count ↓ INCR count ↓ count 3最终重新构建出原来的数据集。10. AOF 会记录 SELECT 吗通常不会。例如GET user:1不会改变 Redis 数据。AOF 真正关心的是会改变数据集状态的写操作。例如SETHSETLPUSHDEL等。因为 Redis 重启恢复时只需要知道数据是怎么一步一步变成现在这个状态的。查询命令没有必要参与这个过程。11. AOF 是每执行一条命令就立刻写磁盘吗这里一定要区分write和fsync它们不是一回事。大致可以理解执行写命令 ↓ 生成 AOF 内容 ↓ 写入文件 ↓ 先进入操作系统文件缓存 ↓ fsync ↓ 真正要求操作系统同步到持久存储如果只是调用普通文件写入并不代表数据已经真正安全地持久化到了磁盘。所以 AOF 提供了不同的fsync策略。12. appendfsync 有哪几种Redis 常见有三种策略alwayseverysecno。13. appendfsync always配置appendfsync always可以简单理解每批新的 AOF 写入之后都进行 fsync。优点数据安全性最高。缺点频繁执行fsync磁盘 I/O 压力大性能影响也最大。因此安全性 ★★★★★ 性能 相对最低适合对数据丢失极其敏感的场景但实际使用时需要接受相应的性能成本。14. appendfsync everysec配置appendfsync everysec意思是大约每秒执行一次 fsync。这是 Redis 官方配置中推荐且常见的折中策略。可以理解写命令 ↓ 不断追加 AOF ↓ 大约每秒 fsync 一次如果突然断电最坏情况下可能损失最近大约一秒左右尚未同步完成的数据。所以安全性 较高 性能 较好这也是非常常见的配置。15. appendfsync no配置appendfsync no意思不是不写 AOF。而是Redis 自己不主动要求每次或每秒执行 fsync把具体什么时候真正刷盘交给操作系统。因此写入 AOF ↓ OS 文件缓存 ↓ 什么时候真正同步 ↓ 由操作系统决定性能更好但数据安全性相对更弱。所以千万不要把appendfsync no理解成AOF 关闭真正控制是否开启 AOF 的是appendonly yes16. AOF 为什么会越来越大假设一个 KeySET count1之后执行INCR count INCR count INCR count INCR count最终只是count 5但是 AOF 可能积累了很多历史操作。再比如SET name A SET name B SET name C SET name D最终 Redis 真正关心的只是name D但是历史 AOF 中保存了大量已经没有必要重新执行的操作。时间越长写操作越多 ↓ AOF 越来越大 ↓ 占用磁盘越来越多 ↓ 重启重放时间也越来越长所以 Redis 需要AOF Rewrite17. 什么是 AOF RewriteAOF Rewrite 的核心不是把旧 AOF 文件重新复制一次。而是根据当前 Redis 数据状态生成一份更精简的持久化基础文件。例如原 AOFSET count 1 INCR count INCR count INCR count INCR count当前状态count 5重写以后并不需要保留所有历史过程。只要能够重新构造count 5即可。因此旧 AOF 大量历史命令 ↓ Rewrite 新持久化数据 只保留恢复当前状态真正需要的信息AOF Rewrite 可以通过BGREWRITEAOF触发。Redis 也可以根据 AOF 大小自动触发 Rewrite。18. AOF Rewrite 会阻塞 Redis 吗和 RDB 类似Redis 会通过后台子进程完成主要 Rewrite 工作。但真实流程在 Redis 7.0 以后发生过比较重要的变化。当前 Redis 会fork 子进程 ↓ 子进程生成新的 Base AOF 与此同时 父进程继续处理客户端请求 ↓ 新的写操作进入新的增量 AOF当 Base 文件生成完成以后再通过 manifest 把新的 Base 文件和增量文件组织起来。所以现在不能只按很多老博客中的“Rewrite 期间新命令全部先存在一个大内存缓冲区最后一次性追加到新 AOF”来理解 Redis 7 的实现。19. Redis 7 以后 AOF 已经不是简单一个文件了这是比较容易被旧资料误导的地方。Redis 7.0 开始使用Multi Part AOF也就是多文件 AOF。主要包括Base FileIncremental AOF FileManifest例如appendonlydir/ ├── appendonly.aof.1.base.rdb ├── appendonly.aof.1.incr.aof ├── appendonly.aof.2.incr.aof └── appendonly.aof.manifest其中Base File表示某个时间点的基础数据状态。Incremental AOF保存 Base 之后继续发生的写操作。Manifest则记录这些文件之间的关系和加载顺序。所以现在说AOF 就是一个 appendonly.aof 文件。对于 Redis 7 来说已经不够准确。20. 什么是 Redis 混合持久化以前单纯使用 AOF 有一个问题AOF 记录大量命令文件可能比较大恢复时重放命令也比较慢。而 RDB文件紧凑加载速度快但是单独使用时数据可能不够新。所以 Redis 可以让 AOF 的 Base File 使用 RDB 格式。当前官方配置中aof-use-rdb-preamble yes就是默认启用这种方式Redis 官方配置也说明 RDB 格式的 AOF Base File 更快、更高效。于是可以理解成AOF 持久化目录 Base File ↓ RDB 格式 ↓ 快速保存基础数据状态 Incremental AOF ↓ 记录 Base 之后的新写操作恢复时加载 RDB 格式 Base ↓ 恢复大部分数据 ↓ 继续重放 Incremental AOF ↓ 恢复最新状态这通常就是大家所说的RDB AOF 混合持久化。21. 混合持久化不是简单的“同时开 RDB 和 AOF”这一点一定要区分。Redis 本身确实支持独立 RDB 快照 AOF同时开启。但是我们经常说的AOF 混合持久化更具体指的是AOF 的 Base 部分使用 RDB 二进制格式后续增量部分继续使用 AOF。也就是AOF 持久化体系 │ ┌───────┴────────┐ ↓ ↓ Base File Incremental File ↓ ↓ RDB Format AOF Commands所以“开启 RDB 开启 AOF”与“AOF 使用 RDB preamble/base”不是完全同一个概念。这个区别非常容易被博客写混。22. RDB、AOF 同时开启重启加载谁如果独立 RDB 和 AOF 都开启在正常启动恢复时Redis 会优先使用 AOF 来重建数据。原因是AOF 通常包含比最近一次 RDB 快照更完整、更新的数据变化。Redis 官方当前文档也明确说明同时启用两种持久化时启动会使用 AOF 来重建数据集。所以可以简单理解Redis Restart ↓ AOF 存在并启用 ↓ 优先加载 AOF而不是先加载 RDB 再随便加载一遍 AOF当前 Redis 7 的 AOF 自己又可能包含 RDB 格式 Base因此实际结构会比老版本更复杂。23. RDB 和 AOF 到底怎么选可以先看这张表对比RDBAOF记录方式数据快照写操作日志 / Base Increment文件大小通常较小通常更大数据安全性相对较低通常更高数据丢失范围可能丢失两次快照之间的数据取决于appendfsync恢复速度通常较快通常相对慢运行时开销相对较低持续写日志适合备份很适合可以但通常更复杂Redis 官方同样指出RDB 文件更紧凑、恢复通常更快AOF 可以提供更好的持久性但通常文件更大、资源开销也更高。24. 什么时候只用 RDB如果业务可以接受发生极端故障时丢失最近一段时间的数据。例如Redis 只是缓存或者数据可以从 MySQL 等数据库重新构建那么 RDB 就可能已经够用。例如MySQL ↓ 真正数据源 Redis ↓ 缓存Redis 崩了重启 ↓ 加载 RDB ↓ 缺少的数据重新从数据库缓存这种场景没必要为了 Redis 缓存追求极强持久性。25. 什么时候更适合 AOF如果 Redis 中的数据不能轻易丢失。例如希望即使机器异常断电也尽量只损失极少量最近数据那么 AOF 会更加合适。例如使用appendonly yes appendfsync everysec就在性能和数据安全性之间取得了一个比较常见的平衡。不过Redis 持久化不应该被理解成完整的灾备方案。硬盘损坏、机器丢失、误操作、机房故障等问题仍然需要复制、异地备份等机制配合。26. RDB 和 AOF 能一起用吗官方甚至建议如果非常重视数据安全可以同时考虑两种持久化方式。因为两者互相补充RDB ↓ 文件紧凑 恢复快 适合备份 AOF ↓ 数据更新 持久性更强所以RDB AOF能够同时获得快照备份能力 更强的数据持久性。27. Redis 持久化是不是越强越好持久性越强往往意味着更多磁盘 I/O 和更高延迟。例如appendfsync always数据更安全但是频繁fsync会明显增加磁盘压力。而appendfsync no性能更好但是数据安全性更弱。所以 Redis 持久化本质上也是一个取舍性能 ↑ │ │ └────────→ 数据安全性实际选择要回答一个问题业务到底能够接受丢多少数据如果一条都不能丢那么 Redis 单机持久化本身可能都不是完整答案还需要复制、集群、备份甚至其他数据库系统共同保证。28. 最容易搞错的几个地方第一RDB不是实时保存每一次写操作它保存的是某个时间点的数据快照。第二AOF不是简单“每条命令立刻写入物理磁盘”。真正的数据安全程度取决于appendfsync。第三appendfsync no不代表关闭 AOF它只是把何时真正同步磁盘主要交给操作系统。第四AOF Rewrite不是把旧 AOF 原封不动压缩而是根据当前数据状态重新生成更精简的持久化基础。第五Redis 7 已经使用Multi Part AOF不能再简单认为 AOF 永远只有一个appendonly.aof文件。第六所谓“混合持久化”通常指 AOF 的 Base File 使用 RDB 格式后续变化用 Incremental AOF 保存并不等于简单把独立dump.rdb和 AOF 两种机制混为一个概念。第七RDB和AOF可以同时开启如果两者都启用Redis 重启时通常使用 AOF 恢复因为它的数据通常更加完整。