☰
Redis持久化机制选型:RDB、AOF与混合持久化实践
2026/10/28 12:09:44 网站建设 项目流程

Redis 这套东西用久了会发现,真正让人夜里睡不着的不是命令用错,而是持久化配置。RDB 和 AOF 这两个词几乎每个写过缓存的人都知道,可一到具体项目上——到底是关掉持久化、只留 RDB、还是 AOF 配 everysec、要不要开混合模式、主从节点是不是都该开——就开始拍脑袋。我见过太多团队把默认配置文件往生产环境一扔,跑了大半年没出事,直到某次机房断电或者磁盘写满,才发现丢掉的数据比预期多了一个量级。这篇就围绕Redis 持久化机制的策略选择方案展开,把 RDB 快照、AOF 日志、混合持久化这三条路线拆开讲清楚,包括 fork 和写时复制的真实成本、appendfsync 三档策略到底差在哪、重写为什么会造成延迟毛刺,以及不同业务场景该对号入座选哪套配置。内容偏实操,适合已经能把 Redis 跑起来、但还没想明白持久化该怎么配的后端同学,也适合正在做容量规划或者故障复盘的运维同学参考。

1. 先把问题摆清楚:持久化选型到底在纠结什么

1.1 内存数据库的断电恐惧与三档数据安全等级

Redis 的所有数据都在内存里,进程一挂,内存就没了。持久化要干的事只有一件:把内存里的状态以某种形式落到磁盘,重启时再读回来。听起来简单,但工程上的矛盾立刻出现了——落盘越勤,数据越安全,性能越差;落盘越疏,性能越好,丢得越多。这个矛盾没法消除,只能按业务的重要程度去分配。

我习惯把需求分成三档。第一档是可完全重建:缓存、页面片段、热点数据,丢了之后回源数据库重新加载就行,最多是数据库被打一波。第二档是可容忍分钟级丢失:会话、排行榜、购物车这类,丢几十秒用户会骂但是业务能继续。第三档是基本不能丢:订单状态机、幂等记录、分布式锁的持有信息、消息队列的位点,这些丢了就是数据不一致,事后对账能要人命。

这三档对应的配置完全不同。第一档可以干脆appendonly no且注释掉所有 save 规则,纯内存跑,性能拉满;第二档 RDB 或 AOF everysec 都能接受;第三档必须 AOF,而且要考虑 everysec 那最多两秒的窗口能不能扛住,扛不住就得上 always 或者换用支持多副本强同步的方案。所以选型的第一步不是看参数,是先给业务定档,这一步定错了后面怎么调都是错的。

1.2 RDB 与 AOF 的能力边界对照

很多人把 RDB 和 AOF 当成二选一,其实它们的定位是互补的:RDB 是某一时刻的全量快照,文件紧凑、恢复快,但颗粒度粗;AOF 是写命令的追加日志,颗粒度细、丢得少,但文件大、恢复慢。两者的差异不是"哪个更好",而是"在哪个维度上更划算"。

对比维度RDB 快照AOF 日志
记录内容某一时刻的全量数据(二进制压缩格式)每条写命令的文本协议记录
数据丢失窗口取决于 save 间隔,通常分钟级everysec 下最多约 2 秒,always 下基本为 0
文件体积小,同数据集通常是 AOF 的 1/2 到 1/5大,且随写入历史膨胀,需重写压缩
恢复速度快,直接加载二进制,10GB 数据通常几十秒慢,需逐条重放命令,同量级可能数分钟
对主线程的影响fork 瞬间阻塞 + 写时复制的内存开销刷盘策略影响延迟,重写时 fork 同样阻塞
数据完整性弱,崩溃可能丢最后一次快照后的全部写入强,可配置到接近零丢失
适合场景备份、冷数据、从库全量同步、可容忍丢失的缓存对数据完整性有要求的业务主库

这张表里最容易被忽略的是"恢复速度"和"文件体积"这两行的反向关系。RDB 体积小、恢复快,但丢得多;AOF 丢得少,但一个跑了半年的 AOF 文件如果没重写,几个 GB 甚至几十 GB 都正常,重启时逐条重放的耗时会让整个发布窗口失控。我在一个中等规模的项目里见过 12GB 的 AOF,机器重启后加载花了接近 4 分钟,那 4 分钟里所有依赖它的服务都在超时重试。

2. RDB 快照:fork 与写时复制才是成本大头

2.1 一次 bgsave 到底发生了什么

很多人对 RDB 的理解停留在"定时存盘",但真正决定它能不能用的,是bgsave内部的两个动作:fork 子进程和写时复制。

执行bgsave时,主进程调用fork()创建子进程。子进程拿到的是主进程内存的"副本视图",但 Linux 并不真的复制物理内存,而是让父子进程共享同一批内存页,页表标记为只读。子进程负责把这些共享页写进 RDB 文件,主进程继续处理请求。当主进程要修改某一页时,内核触发缺页异常,把那一页复制一份给主进程,这就是写时复制(Copy-On-Write)。

成本分两块。fork 本身是阻塞的,主进程在这期间完全停摆,耗时和内存页表规模正相关。64 位系统上一个页表项约 8 字节,每 4KB 内存对应一个页表项,也就是说每 GB 内存对应约 2MB 的页表。一个 32GB 的实例,fork 时需要复制的页表约 64MB,实测阻塞时间通常在 20 到 60 毫秒之间,内存越大越明显,如果开了透明大页(THP),这个数字可能翻几倍——因为大页会让页表项变少但单页变大,COW 的复制粒度从 4KB 变成 2MB,一次修改就要复制 2MB。

第二块成本是COW 带来的内存膨胀。快照期间如果有大量写操作,被修改的页会不断复制,最坏情况下额外占用接近一倍内存。实际经验是:快照持续期间写入量占全量数据的比例越高,膨胀越明显。一个 16GB 的实例,如果快照持续 30 秒、期间写入覆盖了 20% 的热数据,额外内存大概在 2 到 3GB。这也是为什么很多团队会把maxmemory设在物理内存的 50% 到 60%,而不是 80%——留出来的空间就是给 COW 用的。

提示:fork的耗时可以用INFO stats里的latest_fork_usec直接观测,单位是微秒。这个值持续超过 100000(即 100ms)就说明 fork 已经成为延迟毛刺的来源,需要从内存规模、THP 设置、实例拆分三个方向去查。

2.2 save 规则怎么定才不拍脑袋

redis.conf里默认的三条规则是save 900 1、save 300 10、save 60 10000,意思是 900 秒内至少 1 次写、300 秒内至少 10 次写、60 秒内至少 10000 次写,任一条件满足就触发 bgsave。这套默认值是十多年前针对小内存实例设计的,放到今天动辄几十 GB 的实例上,问题很明显:写请求稍微密集一点,60 秒那条就会频繁触发,一天下来几百次 bgsave,每次都是 fork 加一轮磁盘写入。

我的做法是按能容忍丢多少倒推,而不是按默认值调。假设业务能接受丢 5 分钟数据,那就只留save 300 100一条(5 分钟内至少 100 次写才触发),并且把save ""之外的其他规则全部删掉。为什么要加"至少 100 次写"这个条件?因为低频写入的场景下,每 5 分钟存一次盘纯属浪费 IO,数据变化本来就小,多存几次和少存几次的收益差不多。

另外两个参数值得注意。rdbcompression yes开启 LZF 压缩,能显著减小文件体积,代价是 fork 出来的子进程要多消耗一点 CPU,这个开销在主进程之外,通常可以接受,除非你的实例 CPU 已经贴着上限跑。rdbchecksum yes会在文件末尾加 CRC64 校验,加载时验证完整性,代价是快照时多花约 10% 的时间,生产环境建议保持开启,因为一个损坏的 RDB 在恢复时才发现,损失远大于那点开销。

还有一个坑:stop-writes-on-bgsave-error yes是默认值,意思是快照失败后直接拒绝所有写请求。这个设计的初衷是提醒你持久化坏了,但实际后果是在磁盘写满的瞬间,Redis 从"能读能写但持久化失败"变成"完全不可写",业务直接雪崩。我的建议是把它设为no,同时用监控盯住rdb_last_bgsave_status和磁盘剩余空间——让持久化失败变成告警,而不是变成一次线上事故。

2.3 RDB 的隐藏陷阱与规避手法

RDB 有几个不那么显眼的问题,踩过的人才知道疼。

第一是多个实例同时 bgsave 打满磁盘带宽。一台物理机上跑十几个 Redis 实例,如果 save 规则设得一样,它们的触发时机很容易撞在一起,十几个子进程同时往磁盘写,IO 队列瞬间拉满,所有实例的延迟一起飙。解决办法是给不同实例的 save 规则错开,或者用外部调度在低峰期统一触发,再或者干脆把 RDB 目录放到独立磁盘上。

第二是从库全量同步和 RDB 快照叠加。主从首次同步时,主库会触发一次 bgsave 生成 RDB 发给从库,如果这时恰好又满足了 save 规则,两个 bgsave 会串行执行(Redis 同一时刻只允许一个 bgsave),排队等待期间主库的写缓冲区持续增长,可能触发client-output-buffer-limit把从库连接踢掉,然后重连、再同步、再被踢,形成循环。见过一次这种情况,从库反复全量同步了一晚上。

第三是RDB 文件被误当备份。RDB 快照是运行态的一致性视图,不是备份。有人在主库上配了 save,然后直接把 dump.rdb 拷走当归档,结果某次误操作FLUSHALL之后五分钟内触发了一次快照,把空数据写进了 dump.rdb,归档也跟着被覆盖。备份一定要用BGSAVE之后单独拷贝,或者用外部工具定期拉取并保留多版本。

3. AOF:刷盘策略决定了你丢多少数据

3.1 appendfsync 三档策略的真实代价

AOF 的工作流程是这样的:写命令先追加到内存里的aof_buf缓冲区,然后按appendfsync的策略调用fsync()落盘。三档策略的差别,本质上是"什么时候把缓冲区的内容真正交给磁盘"。

策略行为数据丢失窗口性能影响
always每条写命令执行后立即 fsync基本为 0(除非磁盘缓存骗人)极大,QPS 可能降到原来的几分之一
everysec每秒由后台线程 fsync 一次最多约 2 秒小,主线程不参与 fsync
no由操作系统决定何时刷盘通常几十秒,最坏更多最小,但完全不可控

always的实际代价比很多人想象的大。每次 fsync 都是一次真实的磁盘同步操作,在普通 SSD 上单次大约 0.1 到 1 毫秒,看起来不多,但它是串行阻塞在写路径上的。一个每秒 5 万次写操作的实例,如果每条都 fsync,光是磁盘同步就吃掉几十秒的 CPU 时间,QPS 会断崖式下跌。这个配置基本只适合写入极低频但绝对不能丢的场景,比如配置中心、账务流水。

everysec是绝大多数业务的默认选择。它由后台线程每秒 fsync 一次,主线程只管往缓冲区写。这里有个细节容易被误解:所谓"最多丢 2 秒",是因为如果上一秒的 fsync 还没完成,主线程会被阻塞等待,所以实际丢失窗口是"上一次成功 fsync 到崩溃之间",通常是 1 到 2 秒。如果磁盘特别慢,fsync 耗时超过 1 秒,主线程就会被拖住,表现为周期性延迟尖刺——这时候问题不在 Redis 配置,在磁盘。

no这一档我不建议用。它把刷盘完全交给操作系统,看起来性能最好,但你既不知道什么时候落盘,也不知道会丢多少,出问题的时候连排查方向都没有。省下来的那点性能,换不来任何确定性。

注意:no-appendfsync-on-rewrite这个参数和刷盘策略相关。设为yes时,AOF 重写期间暂停 fsync,能明显减少重写造成的延迟毛刺,代价是重写那几分钟内数据丢失窗口会变大。如果重写耗时长且业务对延迟敏感,可以开;如果数据安全优先级更高,保持no。

3.2 AOF 重写:什么时候触发、要花多少资源

AOF 是追加写的,同一个 key 被改一百次就记一百条命令,文件必然膨胀。重写(rewrite)的作用是:读取当前数据库的全量状态,用最少的命令重新生成一个等价的新 AOF 文件。注意它不是压缩旧文件,而是根据当前数据重新"拍"一份,所以重写后的体积只和键的数量、值的平均大小有关,和历史上写了多少次无关。

触发条件由两个参数控制:auto-aof-rewrite-percentage 100和auto-aof-rewrite-min-size 64mb。前者是"当前 AOF 体积比上次重写后增长了百分之多少",后者是"文件至少多大才考虑"。两个条件同时满足才触发。

这里有个非常常见的误配。假设一个实例的 AOF 重写后稳定在 200MB,业务是高频更新同一批热点 key,AOF 每小时增长 300MB。按默认的 100% 阈值,只要涨到 400MB 就会触发重写,也就是一小时多点就重写一次,而每次重写都要 fork、都要扫全量数据。这种情况下应该把 percentage 调到 200 甚至 300,min-size 调到 256MB 或 512MB,让重写频率降到每天一两次。判断标准很简单:看INFO persistence里的aof_rewrite_count,一天超过三五次就说明阈值定低了。

反过来,如果 AOF 体积增长很慢,但文件本身很大(比如 20GB),那说明 min-size 卡住了重写,应该把它调大到超过当前文件体积的一半左右,避免刚重写完又立刻触发。

3.3 重写期间的两个尖刺与参数应对

重写期间会出现两个性能问题,很多人配了 AOF 却不知道它们的来源。

第一个是fork 阻塞,和 RDB 一样。重写也是 fork 子进程来做,同样有页表复制带来的停顿。区别在于 AOF 重写期间主进程还在持续接收写命令,这些新命令要同时写进旧的 AOF 缓冲区和重写缓冲区(aof_rewrite_buf),重写缓冲区没有上限,如果重写耗时太长而写入量很大,这部分内存会持续增长,极端情况下吃光内存。

第二个是磁盘 IO 争抢。重写子进程要把新 AOF 文件写满,同时主进程的 fsync 还在继续,两块 IO 打在同一块磁盘上。如果no-appendfsync-on-rewrite是no,就会出现主线程 fsync 被重写的写操作拖慢,表现为周期性卡顿。Redis 4.0 之后加了aof-rewrite-incremental-fsync yes(默认开启),让重写子进程分批 fsync,每次最多写 32MB 就同步一次,避免一次性刷太多把 IO 打满,这个参数建议保持默认。

还有一个值得说的是重写期间的内存峰值。因为要保留重写缓冲区,重写期间的内存占用 = 当前数据 + 缓冲区增量 + COW 复制的页。一个 10GB 的实例做重写,如果期间写入 2GB 数据,内存峰值可能到 13 到 14GB。所以做容量规划时,AOF 开启的实例内存水位线要比纯 RDB 留得更宽。

4. 混合持久化与版本差异:别拿老配置上新版本

4.1 aof-use-rdb-preamble 解决的是什么问题

RDB 和 AOF 各有短板,Redis 4.0 引入的混合持久化就是想把两者的优点拼起来:AOF 重写的时候,不再生成纯文本的命令序列,而是先写一段 RDB 格式的全量数据作为文件头(preamble),后面再追加重写期间的增量命令。这样得到的文件,前面是紧凑的二进制,后面是少量文本命令。

带来两个直接收益。恢复速度大幅提升,因为加载时先读 RDB 部分,那是直接内存映射的批量加载,比逐条重放命令快一个数量级;只有尾部那一小段增量需要逐条执行。文件体积明显下降,RDB 部分的压缩率远高于文本命令。

开启方式是aof-use-rdb-preamble yes,4.0 之后默认就是开启的(早期某些发行版默认关闭,升级时要确认)。要注意的是,开了这个之后,AOF 文件不再是纯文本,用cat看是乱码,redis-check-aof依然能校验,但想人工阅读就得关掉混合模式重新生成。

有一个兼容性坑:混合持久化生成的文件,低于 4.0 的版本读不了。如果做过降级回滚,老版本的 Redis 会直接启动失败并报格式错误。所以升级前一定要确认回滚路径,别只想着往前升。

4.2 多部分 AOF 带来的目录结构变化

Redis 7.0 对 AOF 做了一次比较大的改造,叫多部分 AOF(multi-part AOF)。以前是单个appendonly.aof文件加临时文件,重写过程中文件会被反复替换,一旦在替换过程中崩溃,恢复逻辑很脆弱。7.0 之后改成一个目录appendonlydir(由appenddirname配置),里面分三类文件:一个 manifest 文件记录当前有效的文件清单,一个 base 文件(RDB 格式或 AOF 格式的全量),若干个 incr 文件(增量)。

这个改动的实际意义在于重写过程变成原子的:重写时先生成新的 base 和 incr 文件,然后原子地更新 manifest 指向新文件,旧的留到之后再清理。崩溃恢复时按 manifest 加载,不会再出现"文件写了一半"的中间态。对于经常因为 OOM 或磁盘满导致进程异常退出的环境,这个改进很实在。

升级到 7.x 时要注意几点。第一,appendfilename在 7.0 里依然存在但作用变了,实际路径是appenddirname下的文件,运维脚本里如果硬编码了appendonly.aof的路径,升级后会找不到文件。第二,7.0 支持aof-timestamp-enabled,在 AOF 里记录时间戳注释,方便做时间点恢复(PITR)时定位,默认关闭,有审计需求可以打开,代价是文件略微变大。第三,从 6.x 升级上来时,旧的单文件 AOF 会在首次启动时被自动转换成多部分结构,这个过程需要额外的磁盘空间,升级前要确认剩余空间足够。

5. 按业务场景对号入座的选择方案

5.1 四类典型场景的配置清单

把前面所有分析落到具体场景,我给几套可以直接抄的配置。这些配置的共同前提是:Redis 版本 6.2 或 7.x,物理内存 16GB 以上,SSD 存储。

场景 A:纯缓存,数据可完全重建。这类实例的唯一目标是把数据库的压力挡掉,丢了就回源。配置上直接关掉所有持久化:appendonly no,save 规则写成save ""。同时把maxmemory-policy设为allkeys-lru或allkeys-lfu,让内存满了自动淘汰。要提醒的是,关掉持久化不等于关掉 fork——主从全量同步还是会触发 bgsave,所以 COW 的内存预留还是要留。

场景 B:会话/排行榜,允许丢一分钟。用 RDB 就够了,配置save 300 100,rdbcompression yes,rdbchecksum yes,stop-writes-on-bgsave-error no。如果实例内存超过 16GB,建议把save 300 100再放宽到save 600 100,减少 fork 频率。

场景 C:业务主库,丢几秒可接受。这是最常见的生产配置:appendonly yes,appendfsync everysec,aof-use-rdb-preamble yes,auto-aof-rewrite-percentage 200,auto-aof-rewrite-min-size 256mb,no-appendfsync-on-rewrite no,同时保留一条低频 RDB 规则作为额外备份:save 3600 1。这样日常靠 AOF 保证低丢失,每小时一次的 RDB 提供一个体积小、恢复快的兜底快照。

场景 D:绝对不能丢。单机 AOF always 的性能代价太大,正确做法是主从 + AOF everysec + 从库 AOF always,或者直接用 Redis 的WAIT命令做同步确认。业务写入后调用WAIT 1 100等待至少一个副本确认,超时就报错重试。这套组合能在可接受的延迟下把丢失窗口压到接近零,代价是多一次网络往返。

场景AOFRDB save 规则fsync重写阈值额外说明
A 纯缓存关闭save ""不涉及不涉及配 LRU 淘汰,注意主从同步仍触发 fork
B 可丢一分钟关闭save 300 100不涉及不涉及关闭 stop-writes-on-bgsave-error
C 业务主库开启save 3600 1everysec200% / 256MB混合持久化开启,作双保险
D 不可丢开启按需everysec(主)/ always(从)200% / 512MB配合 WAIT 或副本确认

5.2 主从与集群拓扑下的持久化布局

单机配置想清楚了,放到主从和集群里还有一层取舍,核心原则是:不要让所有节点同时做重活。

主从架构下,我倾向于主库开 AOF everysec 保证写入安全,从库开 RDB 做备份和快速恢复。为什么主库不也开 RDB?因为主库同时跑 bgsave 和 AOF 重写会互相抢 IO 和 fork,而且主库的延迟最敏感。从库则可以放心地跑 RDB——它本来就在接收主库同步过来的数据,多一次 bgsave 对业务没有直接影响。备份也从从库上做,避免在主库上执行BGSAVE造成停顿。

集群模式下,每个分片都是独立的主从组,配置思路一样,但要额外注意全量同步的时间窗口。一个分片的数据量越大,新从库加入时全量同步的时间越长,这期间主库的复制缓冲区持续增长。如果集群规模大、扩缩容频繁,建议调大repl-backlog-size(默认 1MB,生产建议 64MB 到 256MB),并且把client-output-buffer-limit replica的硬限制放宽,否则从库容易在同步过程中被踢。

还有一个容易忽略的点:repl-diskless-sync yes(无盘复制)在 6.0 之后默认开启,全量同步时不再落 RDB 文件到磁盘,而是直接通过网络把 RDB 流推给从库。这个能省掉一次磁盘写入,但对网络带宽要求更高,而且如果同时有多个从库要同步,repl-diskless-sync-delay(默认 5 秒)会让主库等一小会儿再开始,把多个从库的请求合并成一次传输。数据量大的集群里,这个延迟值可以适当调大到 10 到 15 秒,用一点等待时间换一次传输,很划算。

6. 线上问题排查实录与速查手册

6.1 六类高频故障的定位路径

持久化相关的问题,现象往往雷同——延迟抖动、请求超时、连接被拒——但根因差别很大。我整理了一张速查表,按现象反查。

现象优先检查项常见根因处置动作
周期性延迟尖刺(秒级)latest_fork_usec、aof_rewrite_countfork 阻塞、AOF 重写频繁拆分实例、放宽重写阈值、检查 THP
写入被拒绝,报 MISCONFrdb_last_bgsave_status、磁盘剩余bgsave 失败触发 stop-writes清理磁盘,或关闭该参数
重启后加载极慢AOF 文件体积、是否混合持久化纯文本 AOF 过大开混合持久化,或触发一次重写
内存突然涨到接近翻倍快照/重写是否在进行COW 复制 + 重写缓冲区降低内存水位线,错开重写时间
从库反复全量同步client-output-buffer-limit、复制缓冲区同步期间缓冲区溢出被踢调大 backlog 和输出缓冲限制
启动报 AOF 格式错误redis-check-aof校验结果异常退出导致尾部写坏用--fix截断损坏尾部后启动

这里面最需要展开说的是 fork 阻塞的排查。拿到latest_fork_usec之后,要判断是不是 THP 导致的。检查方式很简单,看/sys/kernel/mm/transparent_hugepage/enabled的值,如果是always或madvise且 Redis 进程命中了 THP,fork 耗时会明显偏高。处置方式是关闭 THP,或者在启动脚本里用echo never > /sys/kernel/mm/transparent_hugepage/enabled。这一条在很多环境里能直接把 fork 耗时砍掉一半以上。

另一个高频的是 AOF 尾部损坏。进程被kill -9或者机器突然断电时,AOF 最后一条命令可能只写了一半,重启时报 "Bad file format reading the append only file"。处置方式是用redis-check-aof --fix appendonly.aof,它会把不完整的尾部命令截掉,保留之前的数据。这时候aof-load-truncated yes(默认开启)其实已经能在启动时自动处理尾部截断,但如果损坏位置在文件中间(比如磁盘坏块),就得靠--fix或者从 RDB 恢复。

6.2 几条用血换来的实操心得

第一条:把持久化配置当成容量规划的一部分,而不是附带的开关。我见过太多人开 AOF 的时候只看"数据安全了",没算过重写期间的内存峰值和磁盘增量。一个 20GB 的实例开 AOF,磁盘至少要给 60GB 空间(当前文件 + 重写期间的临时文件 + 余量),内存至少留 30% 给 COW 和缓冲区。这两个数字不预留,迟早出事。

第二条:监控要盯过程指标,不只是结果指标。只监控"是否存活"是不够的,至少要盯这几个:rdb_last_bgsave_status(快照是否成功)、aof_last_write_status(AOF 是否写得进去)、aof_current_size与aof_base_size的比值(离重写还有多远)、latest_fork_usec(fork 是否变慢)、磁盘剩余空间(低于 20% 告警)。最后一项特别重要,磁盘写满引起的连锁反应是 Redis 故障里最典型的死法之一,而且它往往先影响持久化,再影响写入,最后影响整个服务。

第三条:变更持久化配置前,先想好回滚路径。从 RDB 切到 AOF,需要重启并触发一次全量重写,重写期间性能会下降;从混合持久化切回纯 AOF,老文件读不了;从 6.x 升到 7.x,AOF 目录结构会变,运维脚本要同步改。这些操作我都建议先在从库上演练一遍,确认加载耗时和文件体积在预期内,再推到主库。

第四条:恢复演练比配置本身更重要。配置文件写得再漂亮,没有演练过就是纸上谈兵。我习惯在每个季度做一次恢复测试:从备份的 RDB 拉起一个实例,验证数据完整性;从 AOF 重建一个实例,记录加载耗时。这两个数字要写进容灾文档,因为它直接决定了故障时的恢复时间。有个项目第一次演练时才发现,按当时的 AOF 体积,恢复要花 8 分钟,而他们对外承诺的 RTO 是 3 分钟——这个差距只有演练才暴露得出来。

第五条:不要用 RDB 的 save 规则去替代备份。前面提过一次,这里再强调:RDB 是运行态快照,备份是独立的、多版本的、异地存放的。正确做法是定时从从库执行BGSAVE,然后把 dump 文件拉到对象存储或者备份服务器,保留至少 7 天的多个版本。线上误删数据之后,你需要的是"昨天下午三点的数据",而不是"最后一次快照"。

第六条:低频场景别过度设计。我见过一个日活几万的小系统,为了"数据安全"上了 AOF always 加同步复制,结果接口 P99 从 20ms 涨到 200ms,用户抱怨卡顿。后来改成 everysec,延迟回到正常,丢的那一两秒对业务毫无影响。持久化方案的选择,始终是拿业务确定的损失去换确定的性能,别为了心理上的安全感付出十倍的代价。

最后分享一个小技巧:如果拿不准某套配置的实际表现,不用急着上生产,用redis-benchmark在测试环境跑一轮写入压测,同时用INFO persistence采样,观察 fork 耗时、重写频率和内存峰值,半天时间就能把参数摸清楚。这套方法比翻文档管用得多,因为每个实例的数据特征都不一样,别人的最优参数搬到你这儿大概率要重新调。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询