Redis 持久化深度解密:从 RDB、AOF 到混合持久化,彻底搞懂数据不丢失的底层原理
作为后端开发我们每天都在和 Redis 打交道。它凭借内存级别的读写性能成为了高并发系统的标配。但 Redis 的一切优势都建立在一个前提之上数据不能丢。如果 Redis 服务器突然断电或宕机内存中的所有数据都会消失。对于电商订单、用户会话、支付记录这些核心数据来说数据丢失意味着灾难性的后果。为了解决这个问题Redis 设计了一套完整的持久化机制将内存中的数据保存到磁盘上保证数据的持久性。面试时Redis 持久化更是 100% 的必考题RDB 和 AOF 有什么区别各自的优缺点是什么bgsave命令的执行流程是什么为什么不会阻塞主进程AOF 的三种刷盘策略有什么区别线上该怎么选什么是 AOF 重写为什么需要重写什么是混合持久化为什么说它是现在的最佳实践很多人能背出 RDB 和 AOF 的名字却搞不清它们的底层执行流程知道混合持久化好却不知道它好在哪里。这篇文章我们就从问题本质、底层原理、执行流程、源码级细节、线上最佳实践五个维度彻底搞懂 Redis 持久化。一、为什么需要持久化Redis 的天生缺陷Redis 是一个基于内存的数据库所有的数据都存储在内存中。这是它读写性能极高的根本原因但也带来了一个致命的缺陷数据易失性。当服务器断电、重启或进程崩溃时内存中的所有数据都会被清空。如果没有持久化机制Redis 就只能作为一个纯缓存使用不能存储任何需要持久保存的数据。持久化的本质就是将内存中的数据异步保存到磁盘上。当 Redis 重启时可以从磁盘上的持久化文件中恢复数据从而保证数据不丢失。Redis 提供了三种独立的持久化方式RDBRedis Database全量快照持久化保存某个时间点的完整数据快照AOFAppend Only File增量日志持久化保存所有的写操作命令混合持久化Redis 4.0 引入结合了 RDB 和 AOF 的优点是目前的最佳实践下面我们逐个深入讲解每一种持久化方式的底层原理。二、RDB 持久化全量数据快照RDB 是 Redis 最原始的持久化方式也是默认开启的持久化方式。它的核心思想是在某个时间点将 Redis 内存中的所有数据生成一个二进制快照文件保存到磁盘上。这个文件默认名为dump.rdb。1. 触发方式RDB 的触发分为自动触发和手动触发两种。自动触发在 Redis 配置文件redis.conf中可以通过save参数配置自动触发 RDB 的条件# 格式save 秒数 修改的key数量 # 表示在指定秒数内有指定数量的key发生了修改就自动触发RDB快照 save 900 1 # 900秒15分钟内有至少1个key被修改触发RDB save 300 10 # 300秒5分钟内有至少10个key被修改触发RDB save 60 10000 # 60秒1分钟内有至少10000个key被修改触发RDB只要满足其中任意一个条件Redis 就会自动执行 RDB 快照。手动触发有两个命令可以手动触发 RDBsave同步执行RDB 快照。执行过程中会阻塞 Redis 的所有请求直到快照完成。线上绝对禁止使用会导致服务不可用。bgsave异步执行RDB 快照。这是手动触发 RDB 的推荐方式也是自动触发时 Redis 内部使用的方式。2.bgsave完整执行流程面试必问bgsave的执行流程是 RDB 的核心也是面试中最常被问到的知识点。很多人以为bgsave就是开一个子线程去写文件其实远没有这么简单。完整的bgsave执行流程分为 7 步客户端执行bgsave命令Redis 主进程检查是否有正在执行的 RDB 或 AOF 重写子进程如果有直接返回错误主进程调用fork()系统调用创建一个子进程。fork 过程中主进程会完全阻塞不能处理任何请求fork 成功后主进程立即恢复服务继续处理客户端请求子进程遍历内存中的所有数据生成 RDB 快照文件写入临时文件子进程完成快照生成后用临时文件原子替换旧的 RDB 文件子进程退出向主进程发送信号通知主进程 RDB 执行完成3. 核心原理写时复制COW很多人会问子进程在生成 RDB 快照的过程中主进程还在修改数据怎么保证快照的一致性答案就是写时复制Copy-On-WriteCOW机制。这是操作系统提供的一种进程间内存共享机制。当主进程 fork 出子进程后父子进程会共享同一块物理内存。此时操作系统会将内存页的权限设置为只读。如果主进程只是读取数据那么父子进程共享同一块内存不需要任何复制如果主进程要修改某一块内存页的数据操作系统会先复制一份该内存页的副本然后主进程修改副本子进程仍然使用原来的内存页这样子进程看到的内存数据就是 fork 瞬间的完整快照不会受到主进程后续修改的影响。这就是为什么bgsave可以在不阻塞主进程的情况下生成一致性的快照。4. RDB 的优缺点优点恢复速度极快RDB 是二进制压缩文件加载速度比 AOF 快几个数量级非常适合灾难恢复文件体积小RDB 是压缩后的二进制格式占用的磁盘空间远小于 AOF 文件对性能影响小bgsave是异步执行的主进程只在 fork 时短暂阻塞不影响正常服务备份方便RDB 文件是一个单一的二进制文件非常适合定期备份和异地容灾缺点数据丢失风险大RDB 是全量快照两次快照之间的所有数据都会丢失。如果每 5 分钟生成一次快照那么最多会丢失 5 分钟的数据fork 阻塞问题当 Redis 内存很大时比如几十 GBfork 子进程的时间会很长可能会导致 Redis 毫秒级甚至秒级的阻塞这对于高并发系统来说是不可接受的不适合实时持久化频繁生成 RDB 会消耗大量 CPU 和磁盘 IO 资源影响系统性能三、AOF 持久化增量写日志为了解决 RDB 数据丢失风险大的问题Redis 引入了 AOF 持久化。AOF 的核心思想是记录 Redis 所有的写操作命令以追加的方式写入到磁盘文件中。当 Redis 重启时通过重新执行 AOF 文件中的所有命令来恢复数据。1. 开启与配置AOF 默认是关闭的需要在配置文件中手动开启# 开启AOF持久化 appendonly yes # AOF文件名 appendfilename appendonly.aof2. 核心机制三种刷盘策略AOF 的核心是将写命令写入磁盘但为了性能操作系统会将写入操作先放到内存缓冲区中然后再异步刷到磁盘。Redis 提供了三种刷盘策略通过appendfsync参数配置这是 AOF 最重要的配置。刷盘策略含义数据安全性性能推荐指数always每个写命令执行完成后立即调用fsync()将数据刷到磁盘最高最多丢失 1 条命令最低IO 压力极大⭐everysec每秒调用一次fsync()将缓冲区中的数据刷到磁盘较高最多丢失 1 秒的数据较高⭐⭐⭐⭐⭐no不主动调用fsync()由操作系统决定什么时候刷盘最低可能丢失大量数据最高⭐⭐线上推荐使用默认的everysec策略这是性能和数据安全性的最佳平衡。在绝大多数场景下丢失 1 秒的数据是可以接受的。3. AOF 重写机制随着 Redis 的运行AOF 文件会越来越大。比如对同一个 key 执行了 100 次set操作AOF 文件中会记录这 100 条命令但实际上只需要最后一条命令就能恢复数据。为了解决 AOF 文件膨胀的问题Redis 提供了AOF 重写机制。AOF 重写的核心思想是生成一个新的 AOF 文件只保留能够恢复当前数据的最小命令集合。重写的触发方式自动触发通过两个配置参数控制# 当AOF文件大小比上一次重写后的大小增长了100%时自动触发重写 auto-aof-rewrite-percentage 100 # 当AOF文件大小超过64MB时才会考虑自动重写 auto-aof-rewrite-min-size 64mb手动触发执行bgrewriteaof命令异步执行 AOF 重写AOF 重写完整流程AOF 重写的流程和bgsave非常相似也是基于 fork 和写时复制机制客户端执行bgrewriteaof命令主进程检查是否有正在执行的 RDB 或 AOF 重写子进程如果有直接返回主进程 fork 出一个子进程fork 过程中主进程阻塞fork 成功后主进程恢复服务同时将新的写命令同时写入两个缓冲区AOF 缓冲区用于写入旧的 AOF 文件保证原有 AOF 的正常工作AOF 重写缓冲区用于记录重写期间的新写命令子进程遍历内存中的所有数据生成最小命令集合写入新的 AOF 临时文件子进程完成重写后通知主进程主进程将 AOF 重写缓冲区中的所有命令追加到新的 AOF 临时文件末尾主进程用新的 AOF 临时文件原子替换旧的 AOF 文件重写完成后续的写命令继续写入新的 AOF 文件4. AOF 的优缺点优点数据安全性高使用everysec策略最多丢失 1 秒的数据远高于 RDB 的安全性文件可读性好AOF 是纯文本文件记录了所有的写命令可以直接查看和修改方便数据恢复适合实时持久化AOF 是增量写入对性能影响小适合需要实时持久化的场景自动重写AOF 重写机制可以自动压缩文件体积避免文件无限膨胀缺点恢复速度慢AOF 是文本文件重启时需要重新执行所有命令当 AOF 文件很大时恢复时间会非常长文件体积大即使经过重写AOF 文件的体积仍然比 RDB 文件大得多对性能影响比 RDB 大虽然everysec策略性能已经很好但还是比 RDB 略差重写阻塞问题AOF 重写时也需要 fork 子进程同样会有短暂的阻塞问题四、混合持久化RDBAOF 的完美结合RDB 恢复快但数据丢失多AOF 数据安全但恢复慢。为了结合两者的优点Redis 4.0 引入了混合持久化。这是目前 Redis 官方推荐的持久化方式也是绝大多数线上环境的标准配置。1. 核心原理混合持久化的核心思想是AOF 重写时将当前内存中的数据以 RDB 格式写入 AOF 文件开头然后将重写期间的写命令以 AOF 格式追加到文件末尾。这样新的 AOF 文件就由两部分组成前半部分RDB 格式的全量数据快照体积小加载速度快后半部分AOF 格式的增量写命令数据安全性高2. 开启与配置混合持久化默认是开启的需要在配置文件中配置# 开启AOF持久化 appendonly yes # 开启混合持久化 aof-use-rdb-preamble yes3. 执行流程混合持久化的执行流程和普通 AOF 重写几乎完全一样唯一的区别是子进程生成新文件的格式触发 AOF 重写自动或手动主进程 fork 出子进程子进程将当前内存中的数据以 RDB 格式写入新的 AOF 临时文件主进程将重写期间的新写命令写入 AOF 重写缓冲区子进程完成 RDB 部分的写入后通知主进程主进程将重写缓冲区中的命令以 AOF 格式追加到新的 AOF 文件末尾原子替换旧的 AOF 文件重写完成4. 混合持久化的优势混合持久化完美结合了 RDB 和 AOF 的优点恢复速度极快前半部分是 RDB 格式加载速度和纯 RDB 一样快数据安全性高后半部分是 AOF 格式最多丢失 1 秒的数据文件体积小结合了 RDB 的压缩特性文件体积比纯 AOF 小很多兼容性好向下兼容纯 AOF 格式Redis 可以识别并加载混合持久化的 AOF 文件五、三种持久化方式对比与选择为了方便大家快速对比和选择我整理了一张核心对比表特性RDBAOF混合持久化数据安全性低丢失两次快照之间的数据高最多丢失 1 秒数据高最多丢失 1 秒数据恢复速度极快慢极快文件体积小大中等对性能影响小中等中等实现复杂度低中等中等推荐版本所有版本所有版本Redis 4.0适用场景备份、灾难恢复、非核心数据核心数据、实时持久化绝大多数线上场景不同场景的选择建议Redis 4.0 及以上版本优先使用混合持久化这是目前的最佳实践Redis 3.2 及以下版本如果对数据安全性要求高使用 AOF如果可以接受一定的数据丢失使用 RDB纯缓存场景如果可以接受数据丢失并且重启后可以从数据库重建缓存可以关闭持久化主从架构建议主库关闭持久化从库开启持久化避免主库 fork 阻塞影响线上服务六、线上最佳实践与避坑指南1. 永远不要使用save命令save命令会同步执行 RDB 快照阻塞整个 Redis 进程直到快照完成。线上环境绝对禁止使用所有手动触发都应该使用bgsave和bgrewriteaof。2. 合理配置 RDB 自动触发条件不要配置过于频繁的 RDB 快照否则会导致频繁 fork影响 Redis 性能。建议根据业务的数据丢失容忍度配置合理的触发条件比如# 关闭默认的自动触发 save # 只保留每天凌晨3点自动生成一次RDB save 86400 13. 控制 Redis 的最大内存Redis 的内存越大fork 子进程的时间就越长阻塞时间也就越长。建议单个 Redis 实例的内存不要超过 16GB最好控制在 8GB 以内。如果数据量太大使用 Redis Cluster 分片集群。4. 主从库持久化分工主库只负责处理业务请求不要开启任何持久化。所有的持久化操作都放到从库上执行这样即使从库 fork 阻塞也不会影响线上服务。5. 监控持久化状态一定要建立完善的监控体系监控以下指标RDB 和 AOF 的执行时间、执行频率RDB 和 AOF 文件的大小、增长速度fork 操作的耗时持久化失败的次数如果发现 fork 耗时过长或者持久化执行过于频繁及时调整配置或扩容。6. 定期备份持久化文件持久化文件保存在本地磁盘上如果磁盘损坏数据还是会丢失。一定要定期将持久化文件备份到异地存储比如对象存储服务。七、常见误区纠正误区bgsave完全不会阻塞主进程。纠正bgsave在 fork 子进程的时候会阻塞主进程只是阻塞时间很短。当 Redis 内存很大时阻塞时间会很长。误区AOF 刷盘设为always最安全所以线上应该用这个。纠正always策略会导致每个写命令都刷盘性能极差IO 压力极大线上绝对不要使用。everysec是性能和安全的最佳平衡。误区混合持久化就是同时开启 RDB 和 AOF。纠正混合持久化是 AOF 的一种模式只需要开启 AOF 和aof-use-rdb-preamble即可不需要单独开启 RDB。误区开启了持久化就不会丢失数据。纠正任何持久化方式都不能保证 100% 不丢失数据只能将数据丢失的风险降到最低。误区AOF 重写会丢失数据。纠正AOF 重写不会丢失任何数据。重写期间的新命令会被写入重写缓冲区最后追加到新的 AOF 文件中。八、高频面试题解答问RDB 和 AOF 有什么区别答RDB 是全量二进制快照恢复快但数据丢失多AOF 是增量写日志数据安全但恢复慢。混合持久化结合了两者的优点。问bgsave的执行流程是什么答主进程 fork 出一个子进程子进程基于写时复制机制生成 RDB 快照文件主进程只在 fork 时短暂阻塞。问什么是写时复制它在 Redis 持久化中有什么作用答写时复制是操作系统提供的内存共享机制。fork 后父子进程共享内存只有当主进程修改数据时才会复制内存页。这样可以保证子进程生成的快照是 fork 瞬间的一致性视图。问AOF 的三种刷盘策略有什么区别答always每个命令都刷盘最安全但性能最差everysec每秒刷一次盘性能和安全平衡no由操作系统决定刷盘时机性能最好但最不安全。问为什么需要 AOF 重写重写的流程是什么答AOF 文件会随着运行时间不断膨胀重写可以生成最小命令集合压缩文件体积。重写流程和bgsave类似fork 子进程生成新的 AOF 文件同时记录重写期间的新命令最后合并到新文件中。问什么是混合持久化有什么优点答混合持久化是 Redis 4.0 引入的AOF 重写时将当前数据以 RDB 格式写入文件开头然后追加增量写命令。优点是恢复速度快数据安全性高文件体积小。九、总结Redis 持久化的本质是在性能和数据安全之间做权衡。没有完美的持久化方案只有最适合业务的方案。RDB 追求极致的恢复速度和最小的文件体积牺牲了部分数据安全性AOF 追求更高的数据安全性牺牲了部分恢复速度和性能混合持久化完美结合了两者的优点是目前的最佳实践理解了 Redis 持久化的底层原理你就能根据自己的业务场景做出合理的配置选择避免线上的各种坑。同时这也是面试中考察 Redis 核心能力的重要部分掌握了这些内容你就能轻松应对所有 Redis 持久化相关的面试题。

相关新闻

最新新闻

日新闻

周新闻

月新闻