尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Redis 系列(五):持久化——RDB、AOF 与混合持久化

Redis 系列(五):持久化——RDB、AOF 与混合持久化 核心目标理解 RDB、AOF、混合持久化三种方式的机制、代价与恢复语义掌握 fork COW、fsync 策略、AOF 重写等关键概念能设计符合业务丢失容忍度的持久化策略并在文件损坏后完成修复与恢复。前置知识完成 Part 1单线程事件循环——持久化是阻塞点的重要来源与 Part 3内存结构。验证环境Redis 8.10.0cygwin 移植版主实例 6379 用于常规实验隔离实例 6380 用于断电/损坏等破坏性实验、redis-py 8.1.0、Python 3.11.6、Windows 11。最后复核日期2026-08-07。0. 本篇问题场景数据没丢只是运气Redis 是内存数据库重启就清空是常见的误读。真实情况是Redis默认配置下appendonly no只做 RDB 快照且快照触发频率可能很低——kill -9或断电后上一次快照之后写入的所有数据都会消失。先定义本系列反复用到的词丢失窗口数据丢失时间窗——从最后一次落盘到故障发生之间的时间。业务能容忍丢失多少秒直接决定持久化配置业务丢失容忍合理的持久化策略商品缓存可重建分钟级RDB 即可甚至不持久化购物车/会话秒级AOF everysec支付流水/状态机零容忍AOF always 主从 备份本篇用隔离实例把三种持久化的保存-恢复-损坏-修复完整演一遍。1. RDB内存快照1.1 机制fork Copy-On-WriteRDB 是某时刻全内存数据的二进制快照。触发SAVE同步或BGSAVE后台时主进程fork()一个子进程子进程把内存中的数据序列化写入dump.rdb主进程继续服务客户端。关键在fork COW写时复制dump.rdb子进程(fork)主进程dump.rdb子进程(fork)主进程COW谁先写谁复制该页内存页fork()页表复制共享物理页继续服务写命令修改的页被复制基于快照时刻的数据写文件完成后通知主进程COW 的代价fork 瞬间复制页表大实例可能几十~几百毫秒写命令触发页复制写入越频繁复制越多快照期间内存可能短时上升被复制的页。1.2 触发方式方式命令/配置阻塞性手动同步SAVE阻塞主进程直到写完手动后台BGSAVEfork 瞬间阻塞之后后台写自动save 900 1/save 300 10/save 60 10000同 BGSAVE关闭自动save 手动控制1.3 实测保存、校验、恢复在隔离实例上完整走一遍写入 100 个键 → SAVE → 校验 → 重启$ redis-cli -p 6380 SAVE OK $ ls -la dump.rdb -rw-r--r-- 1875 dump.rdb ← 二进制快照1875 字节 $ redis-check-rdb dump.rdb [offset 1875] Checksum OK [offset 1875] \o/ RDB looks OK! \o/ [info] 100 keys read 重启实例 $ redis-cli -p 6380 DBSIZE 100 ← 数据完整恢复 $ redis-cli -p 6380 GET order:42>* Loading RDB produced by version 8.10.0 * RDB age 15 seconds * Done loading RDB, keys loaded: 100, keys expired: 0.RDB 的定位是定期快照恢复快直接载入二进制、文件紧凑但丢失窗口 距上次快照的时间。2. AOF追加式命令日志2.1 机制把写命令本身记下来AOFAppend Only File记录每条修改数据的命令RESP 协议格式重启时重放命令重建数据。相比 RDB它把丢失窗口压缩到最后一次 fsync 到故障之间。写入链路客户端写命令 → 命令执行内存生效 → 写入 AOF 缓冲 → 按 appendfsync 策略刷入 OS 文件缓存 → 按策略 fsync 落盘appendfsync三个档位的丢失窗口策略fsync 时机丢失窗口性能always每条命令后0严格说命令返回前已落盘最慢每秒数千~数万次 fsynceverysec每秒一次最多 1 秒生产默认性能/安全平衡no交给 OS 决定取决于 OS 刷盘时机理论最长可达秒级~分钟级最快2.2 7.0 的多部件 AOF文件结构变了Redis 7.0 重构了 AOF不再是单个appendonly.aof而是一个appendonlydir/目录由三部分组成appendonlydir/ ├── appendonly.aof.manifest ← 清单base/incr 文件与顺序 ├── appendonly.aof.1.base.rdb ← base 文件当前全量纯 AOF 或混合 RDB 头 └── appendonly.aof.1.incr.aof ← incr 文件base 之后的增量命令实测的 manifest 内容file appendonly.aof.1.base.rdb seq 1 type b file appendonly.aof.1.incr.aof seq 1 type i startoffset 0incr 文件就是 RESP 协议的命令日志可读*1 $5 MULTI *2 $6 SELECT $1 0 *3 $3 ...AOF 重写BGREWRITEAOF把当前全量数据写成新的 base 文件并清空/截断增量——防止 AOF 无限膨胀。重写同样是 fork 子进程 后台进行与 RDB 的 COW 机制一致。2.3 实测AOF 保存与恢复$ redis-cli -p 6380 BGREWRITEAOF Background append only file rewriting started $ ls appendonlydir/ appendonly.aof.2.base.rdb 21875 字节 ← 重写后的全量 appendonly.aof.2.incr.aof 0 字节 appendonly.aof.manifest $ redis-check-aof appendonlydir/appendonly.aof.manifest BASE AOF appendonly.aof.2.base.rdb is valid All AOF files and manifest are valid 重启实例 $ redis-cli -p 6380 DBSIZE 1000 ← 完整恢复 $ redis-cli -p 6380 GET order:99>3. 混合持久化RDB 头 AOF 尾纯 AOF 在启动加载时要重放全部命令数据量大时启动慢。混合持久化aof-use-rdb-preamble yes7.x 默认开启让 AOF 重写后的 base 文件直接用 RDB 格式快照加载之后的增量继续用 AOF 追加$ head -c 9 appendonlydir/appendonly.aof.2.base.rdb | xxd 00000000: 5245 4449 5330 3031 35 REDIS0015 ← RDB 魔数redis-check-aof对它的识别RDB preamble is OK, proceeding with AOF tail...加载优先级只要 AOF 开启启动时只从 AOF含混合 base加载不读dump.rdb——AOF 永远包含更新的数据。RDB 只在 AOF 关闭时生效。4. 失败实验损坏与修复4.1 AOF 损坏启动失败 → 修复 → 恢复向 incr AOF 文件中间插入垃圾字节后启动# Bad file format reading the append only file appendonlydir/appendonly.aof.2.incr.aof at offset 0. # make a backup of your AOF file, then use ./redis-check-aof --fix filename.manifest. # Alternatively you can set the aof-load-corrupt-tail-max-size configuration option # to 28 and restart the server.注意细节base 文件加载成功了Done loading RDB, keys loaded: 1000失败在损坏的 incr 段——多部件 AOF 让全量部分无损增量部分可修成为可能。修复$ redis-check-aof --fix appendonlydir/appendonly.aof.manifest RDB preamble is OK, proceeding with AOF tail... ... AOF appendonly.aof.2.incr.aof format error AOF analyzed: ... ok_up_to0, diff28 This will shrink the AOF ... from 28 bytes, with 28 bytes, to 0 bytes Continue? [y/N]: y Successfully truncated AOF appendonly.aof.2.incr.aof All AOF files and manifest are valid重启后数据完整恢复1000 键来自未损坏的 base$ redis-cli -p 6380 DBSIZE 1000 $ redis-cli -p 6380 GET product:999>4.2 RDB 损坏CRC 校验拦截破坏dump.rdb的 checksum 后$ redis-check-rdb dump.rdb --- RDB ERROR DETECTED --- [offset 7375] RDB CRC error [additional info] While doing: check-sum [info] 500 keys read启动时同样被拦截# Wrong RDB checksum expected: (5baeea71929c254a) but got (a451158e6d63dab5). Aborting now. # Internal error in RDB reading offset 0, function at rdb.c:5062 - RDB CRC errorRedis 拒绝加载损坏的 RDB 并直接退出默认rdbchecksum yes且不做自动修复——这比带病启动安全宁可起不来也不给应用喂一份被篡改的数据。生产修复路径是用备份 RDB → 或用redis-check-rdb报告损坏程度 → 必要时结合 AOF 恢复。4.3 断电实验appendfsync no 的意外结果用taskkill /F强制杀掉 AOFappendfsync no实例模拟断电重启后1000 个键全部还在$ taskkill /F /PID 46440 # 模拟断电 成功: 已终止 PID 为 46440 的进程。 重启 $ redis-cli -p 6380 DBSIZE 1000这个结果必须谨慎解读appendfsync no只是不主动 fsync数据仍会经OS 文件缓存异步刷盘——Windows 上缓存刷盘非常快所以写入后立即 kill通常已经落盘。它不能证明 no 策略安全如果 OS 自身崩溃或整机断电尚未刷盘的缓存照样丢丢失窗口在理论上依然存在且不可控。这个实验的意义是说明“实测没丢≠策略安全”丢失窗口是概率与环境的函数。生产仍应选everysec丢失窗口有界 ≤ 1s或always零丢失。5. 持久化策略设计5.1 三种方式对比维度RDBAOFeverysec混合默认丢失窗口距上次快照分钟级≤ 1 秒≤ 1 秒恢复速度快二进制载入慢重放命令快RDB 头 增量文件大小紧凑可能膨胀需重写紧凑重写后 RDB 头写路径开销fork COW追加 每秒 fsync同 AOF故障文件修复redis-check-rdb只报告redis-check-aof --fix可截断修复同 AOF5.2 生产推荐组合appendonly yes # 打开 AOF appendfsync everysec # 丢失窗口 ≤ 1s默认 aof-use-rdb-preamble yes # 混合持久化默认 save 900 1 300 10 60 10000 # 定期 RDB 作为额外备份点再加三道保险后续 Part 10/12 展开主从复制至少一个从库主库故障自动切换异地备份定期把 RDB/快照拷贝到其他存储恢复演练周期性地备份 → 恢复到干净实例 → 校验数据。6. 版本与环境差异差异点7.0 之前7.x / 本机 8.10影响AOF 文件形态单个appendonly.aof多部件目录appendonlydir/manifest base incr备份/修复命令参数变化redis-check-aof --fix传 manifest 文件aof-use-rdb-preamble4.0 引入5.0 起默认开启默认 yes混合持久化base 文件是.rdb格式AOF 加载失败策略直接拒绝仍拒绝但可配aof-load-corrupt-tail-max-size容忍尾部损坏高可用场景可有限容忍rdbchecksum默认 yes默认 yesCONFIG GET实测损坏 RDB 启动即 abort§4.2注意损坏与断电实验均在隔离实例 6380 上进行未触碰生产主实例 6379——这类实验永远不要在生产/开发共享实例上做。7. 测试与验收建议测试备份/恢复往返SAVE → 重启 → 校验键数、redis-check-*命令可用性、损坏文件修复脚本隔离实例生产验收清单见下。本篇验收清单能画出 fork COW 的时序并说出 RDB 的三个阻塞点fork、页复制、写盘能说出appendfsync三档的丢失窗口0 / ≤1s / 取决于 OS知道 7.0 AOF 是多部件目录结构base/incr/manifest 各自职责知道混合持久化的加载流程RDB 头 AOF 尾与AOF 优先于 RDB的规则能完成一次 AOF 损坏修复备份 →--fix→ 重启验证能为秒级容忍/零容忍/可重建三类业务各设计一套持久化配置。8. 常见误区“Redis 默认持久化重启不丢数据”——默认只 RDB 快照且触发频率低丢失窗口分钟级起步§0。“SAVE和BGSAVE一样安全”——SAVE同步阻塞主进程生产手动触发永远用BGSAVE。“AOF 是日志文件改一行加一行”——7.0 是多部件结构 重写机制直接编辑文件是灾难§2.2。“RDB 损坏了redis-check-rdb --fix能修”——redis-check-rdb只报告不修复修复靠备份或 AOF§4.2。“实测 kill -9 没丢数据所以 appendfsync no 安全”——丢失窗口是概率性的OS 崩溃/断电才是 no 的真正风险§4.3。“开启 AOF 后 RDB 就没用了”——RDB 仍是恢复快、文件小的备份点混合持久化的 base 就是 RDB 格式§5。9. 本篇小结回到开篇持久化的本质是用可控的写路径开销换取有界的丢失窗口RDB全量快照恢复最快丢失窗口 距上次快照AOF命令追加 fsync 策略丢失窗口有界everysec ≤ 1s混合base 用 RDB快加载 incr 用 AOF低丢失7.x 默认形态损坏防御RDB 靠 CRC 校验拒绝启动AOF 靠redis-check-aof --fix截断修复——备份永远是最可靠的恢复手段。下一篇 Part 6过期、内存淘汰与内存优化 把内存管起来TTL 的惰性/定期删除、maxmemory八种淘汰策略、大 key 识别与内存治理回答设置了过期时间为什么内存还在涨。10. 官方资料Redis persistence 官方文档https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/RDB 文件格式说明https://rdb.readthedocs.io/redis-check-aof/redis-check-rdbhttps://redis.io/docs/latest/operate/oss_and_stack/management/persistence/BGREWRITEAOF/BGSAVEhttps://redis.io/docs/latest/commands/
返回列表