Redis 持久化怎么配:RDB 和 AOF 的默认值、丢数据窗口与重写的代价

📅 发布时间:2026/10/11 17:06:20
Redis 持久化怎么配:RDB 和 AOF 的默认值、丢数据窗口与重写的代价
本文首发于 CSDN转载请注明出处。先说结论RDB 和 AOF 不是二选一官方建议两个都开。RDB 是周期性快照文件小、恢复快代价是丢数据窗口大AOF 是追加写日志appendfsync everysec下最坏丢 1 秒代价是文件大、恢复慢。真正需要记准的是几个默认值——save的默认阈值在Redis 6.2改过一次不是 7.0appendonly从 4.0 到现在的默认值一直是no。先把两个机制的定位分清RDB 是快照把某一时刻的整个数据集写成一个二进制文件dump.rdb。AOF 是日志把每一条写命令追加进文件重启时重放一遍就能还原数据集。两者的取舍一目了然快照文件小、恢复快但两次快照之间的数据全在内存里宕机就没了日志几乎不丢数据但文件大、重放慢、还要定期重写。官方文档在 RDB 的劣势一节写得很直接RDB is NOT good if you need to minimize the chance of data loss … you should be prepared to lose the latest minutes of data.注意是最新几分钟。这个量级由save的阈值决定而阈值这块的默认值有个容易搞错的细节。save的默认值到底是多少分水岭是Redis 6.2不是很多人以为的 7.0。先说清楚这里有两层东西源码里内置的 C 默认值和发行版redis.conf里写的值。两者在 6.2 之前并不一致实际生效的是redis.conf。Redis ≤ 6.0redis.conf里显式写着save 900 1、save 300 10、save 60 10000三行都没注释实际生效Redis 6.2 起这三行被注释掉文档注释里写明默认变为 3600 秒 1 次变更、300 秒 100 次变更、60 秒 10000 次变更所以拿标准redis.conf跑起来时两者真正生效的默认值是版本生效的 save 配置含义Redis ≤ 6.0900 1/300 10/60 10000最多 15 分钟窗口Redis 6.23600 1/300 100/60 10000最多1 小时窗口而源码里内置的那份 C 默认值appendServerSaveParams(60*60,1)那几行从 4.0 起就是 3600/300/60——6.2 做的其实是让redis.conf与源码对齐。这个差错的影响不小以为默认是 15 分钟窗口的人在 6.2 上实际面对的是1 小时窗口大促期间这个差距是会出事的。上生产前把save显式写死别依赖默认。fork 会阻塞吗会但比阻塞这个说法更准确的是阻塞发生在 fork 那一刻而不是整个写盘过程。官方对流程的描述是Redis forks. We now have a child and a parent process. The child starts to write the dataset to a temporary RDB file. When the child is done writing the new RDB file, it replaces the old one.子进程负责写盘父进程继续服务客户端靠 COW写时复制保证两边看到的数据一致。真正的问题在 fork 本身——官方在劣势一节直接承认fork() can be time consuming if the dataset is big, and may result in Redis stopping serving clients for some milliseconds or even for one second if the dataset is very big and the CPU performance is not great.大实例上 fork 可以卡住主线程到秒级。所以RDB 不阻塞这句话是错的准确的表述是写盘不阻塞fork 会短暂阻塞。实例内存越大这个停顿越明显。另外注意SHUTDOWN时会做一次阻塞式的 SAVE前提是配了 save pointPerform a blocking SAVE if at least one save point is configured.所以正常下线时的最后一次落盘是同步的这也解释了为什么大实例的关闭会比较慢。AOF 的三个 fsync 档位怎么选appendonly的默认值从 4.0 一直到 8.0 都是no——AOF 默认不开这一点没变过。开了之后appendfsync的默认值是everysec。三个档位的官方定义取值官方描述最坏丢多少性能always每次写入都 fsync几乎不丢很慢everysec每秒 fsync 一次可能丢 1 秒够快默认no交给操作系统决定何时刷视内核而定最快、最不安全官方文档对everysec的原文是 “you may lose 1 second of data”——注意是可能。很多文章写成一定只丢 1 秒把可能性说成了保证。还有一个更隐蔽的例外配置了no-appendfsync-on-rewrite yes时重写期间 AOF 的持久性会降到等同于appendfsync no。redis.conf的注释原文是In practical terms, this means that it is possible to lose up to 30 seconds of log in the worst scenario (with the default Linux settings).最坏 30 秒。这个值只有在你主动打开那个开关时才会出现但它说明everysec 丢 1 秒这个等式并不是无条件成立的。重写是怎么做的代价在哪AOF 文件会随时间膨胀同一个 key 被改 100 次就有 100 条命令所以要定期重写。默认触发条件写在redis.conf里auto-aof-rewrite-percentage100auto-aof-rewrite-min-size 64mb即AOF 文件比上次重写后增长超过 100%且超过 64MB时自动触发BGREWRITEAOF。重写期间的写入怎么处理Redis 7 前后不一样Redis 7.0父进程把新写入累积在内存缓冲区同时仍然写旧的 AOF 文件子进程写完后把缓冲区追加到新文件末尾Redis 7.0父进程新开一个增量 AOF 文件继续写重写失败也能靠旧 base 增量文件还原完整数据集老版本的两个代价官方在劣势里列了AOF can use a lot of memory if there are writes to the database during a rewrite. … All write commands that arrive during rewrite are written to disk twice.内存暴涨缓冲区占内存和写两次既写旧文件又进缓冲区。这正是 Redis 7 引入多文件 AOF 想解决的问题。混合持久化与 Redis 7 的新格式混合持久化RDB-AOF hybrid在Redis 4.0 引入当时默认是noThis is currently turned off by default in order to avoid the surprise of a format change, but will at some point be used as the default.这个at some point就是Redis 5.0——从 5.0 起aof-use-rdb-preamble默认变成yes。它的做法是重写时 AOF 文件前半段用 RDB 格式生成快、体积小后半段继续追加正常的 AOF 命令流。这样重写更快、重启加载也更快。到了Redis 7.0AOF 从单文件变成了多文件Multi-Part AOFSince Redis 7.0.0, Redis uses a multi part AOF mechanism. That is, the original single AOF file is split into base file (at most one) and incremental files.目录结构大致是这样appendonlydir/ appendonly.aof.1.base.rdb# 基础快照RDB 格式appendonly.aof.1.incr.aof# 增量文件appendonly.aof.manifest# 清单文件记录哪些文件构成当前数据集版本AOF 形态重写期间新写入≤ 6.x单文件内存缓冲区可能引起内存峰值7.0base incr manifest新开增量文件不再写两次manifest 是这套机制的关键它记录了当前有效的是哪几个文件redis-check-aof也适配了多文件形态。升级到 7 之后如果还按老路径找appendonly.aof会发现目录里是空的——文件都搬到appendonlydir里去了。同时开着重启时用哪个**用 AOF。**官方原文In the case both AOF and RDB persistence are enabled and Redis restarts the AOF file will be used to reconstruct the original dataset since it is guaranteed to be the most complete.理由就是 AOF 更完整。这也带来一个运维上的常见误区开了 AOF 之后如果 AOF 文件损坏即使 RDB 是好的也可能起不来除非显式改配置。所以 AOF 文件的完整性监控不能省。官方给的取舍建议官方文档里有一段很务实的建议值得原文照搬想要接近 PostgreSQL 级别的数据安全 →两个都开“The general indication you should use both persistence methods is if you want a degree of data safety comparable to what PostgreSQL can provide you.”能接受灾难时丢几分钟数据 →只用 RDB 就够不建议只用 AOF“There are many users using AOF alone, but we discourage it”——理由是 RDB 还能用来做备份、加快重启以及在 AOF 引擎出 bug 时兜底所以正确的默认姿势是两个都开RDB 负责备份与快速恢复AOF 负责把丢数据窗口压到秒级。四个流传说法逐个对一下“RDB 会丢很多数据所以不能用”——夸大了。官方明说能容忍几分钟损失时可以只用 RDB只是不建议依赖它做秒级安全。“AOF everysec 一定只丢 1 秒”——不严谨。官方用的是可能且no-appendfsync-on-rewrite打开后最坏能丢到 30 秒。“开了 AOF 就不需要 RDB 了”——反了。官方反而不建议只用 AOF。“bgsave 会阻塞主线程”——半对。BGSAVE 本身后台执行、父进程继续服务但 fork 那一刻官方承认可能卡到毫秒级甚至一秒。要说RDB 完全不阻塞就是错的。持久化参数这套东西版本一升级默认值就动老笔记很容易变成误导。我现在的做法是把「参数—版本—生效值」整理成一张对照表统一维护需要的时候用AI 图文同步一次推到几个平台留档集中核对版本差异的那几天靠发文额度提升不用排队发完再用批量 GEO 检测确认内容在 AI 搜索里的引用情况墨衍会员权益 有需要可以了解。常见问题Q生产上save该配多少不依赖默认值显式写死。经验上按能接受丢多少数据倒推如果能接受丢 5 分钟配save 300 1如果数据敏感把 AOF 也打开save就退化成备份用途配得宽松一点比如save 3600 1减少 fork 频率。核心是别让 fork 在流量高峰频繁发生。Qappendfsync always能用在生产吗能用但通常不值得。官方原话是 “Very very slow, very safe”。它把每次写入都变成一次 fsync 系统调用吞吐会掉一个数量级。真需要这个级别的安全性一般会往上换成 PostgreSQL 这类数据库而不是让 Redis 扛。Q实例内存几十 GBfork 那一下会不会直接把服务打死有这个风险。fork 的耗时与内存页表大小正相关几十 GB 的实例可能卡到秒级。两个缓解手段一是在从库上做持久化主库专心服务二是打开no-appendfsync-on-rewrite并把save频率调低。另外要留意 COW 带来的额外内存占用——写入频繁时fork 后内存可能涨到接近 2 倍要留够余量。QRedis 7 之后去哪找 AOF 文件appendonlydir目录下。默认路径由appenddirname控制默认值就是appendonlydir。文件名形如appendonly.aof.1.base.rdb、appendonly.aof.1.incr.aof加一个appendonly.aof.manifest。做备份脚本时要注意这个目录结构变了别只备份单个.aof文件。QAOF 文件损坏了怎么救用redis-check-aof修复Redis 7 支持多文件形态。但更该做的是事前预防定期备份appendonlydir整个目录上线前压测重写过程别在流量高峰让它触发重写。修 AOF 只能救回一部分数据且是最后手段。关于墨衍如果你也在多个平台发技术文章值得看看墨衍。三个最常用的权益——发文额度提升密集更新不再受限、批量 GEO 检测一次扫完全部文章的 AI 引用状态、AI 图文同步一稿多平台分发。点这里了解墨衍会员