跳到主要内容
约 9 分钟6 张卡

Redis 持久化、复制与集群

Redis 的持久化、复制与集群解决三个不同问题:持久化把恢复需要的数据写到存储上,复制让其他节点保留运行副本,Cluster 则把数据分片到多个主节点。面试中要能区分它们各自的保证:有副本不代表数据已落盘,能够自动切换也不代表已确认的写入一定不会丢失。本文以 Redis 6、7 为基线。

1. 面试核心​

先记住这几条,再读正文
  • RDB 保存某一时刻的数据快照,AOF 记录恢复所需的写操作;复制和 Cluster 分别提供运行副本与数据分片。卡 · RDB
  • appendfsync everysec 在正常调度下每秒同步 AOF,实际能恢复到哪里,仍取决于最近已持久化的位置。
  • Redis 7.0 起,AOF 用基础文件、增量文件和 manifest 清单组织恢复数据,重写期间的新写入进入增量文件。卡 · AOF 重写与混合格式
  • Sentinel 达到 quorum 才判定主节点客观下线,执行故障转移还需要多数 Sentinel 授权。卡 · Sentinel
  • Cluster 把键分配到 16384 个槽。MOVED 要求更新槽路由,ASK 只临时转发本次请求。卡 · MOVED 与 ASK 重定向

2. RDB​

RDB 是某一时刻数据集的快照。SAVE 在主线程同步生成快照,期间会阻塞请求;BGSAVE 则通过 fork 创建子进程,让子进程在后台保存。

只依靠 RDB 恢复时,最多能回到最后一份有效快照,快照之后的修改没有记录可以重放。它的文件紧凑,适合做时间点备份,也便于整库加载。

后台保存也有成本。创建子进程时会有 fork 停顿;之后父子进程先共享内存页,父进程继续修改数据时,需要复制将被修改的共享页,这就是写时复制。写入越密集、子进程运行越久,额外内存压力就可能越大。

3. AOF​

AOF(Append Only File)保存恢复数据所需的写操作,设置 appendonly yes 后启用。写入文件不等于已经同步到磁盘,appendfsync 决定何时请求磁盘同步:

配置同步方式与代价
always每次写入批次同步,确认延迟受磁盘同步影响。
everysec后台每秒同步,正常调度下约有一秒未同步窗口。
no由操作系统安排同步,丢失窗口取决于系统刷盘。

everysec 的「约一秒」建立在正常调度的条件下。磁盘阻塞或同步延期时,实际落盘进度可能更慢,所以不能把它理解为任何故障下最多只丢一秒数据。

AOF 重写是根据当前数据生成一份更短的恢复记录。例如一个计数器被递增了许多次,恢复当前值并不需要保留每次递增的过程。重写省去这些中间修改,但生成新文件期间仍要预留磁盘和内存空间。

4. AOF 重写与混合格式​

AOF 重写期间仍要接收新写入,因此必须把生成基础数据和记录新增修改衔接起来。Redis 6 中,子进程生成新 AOF 文件,父进程继续写旧文件,同时保存重写期间的增量。等新文件补齐这些增量后,再替换旧文件。

Redis 7.0 起改用多文件 AOF:子进程生成基础文件,父进程把新写入放进新的增量文件。manifest 是记录这组文件的清单,重写完成后原子切换清单,恢复时就按它加载基础文件和增量文件。

Redis 6、7 默认启用 aof-use-rdb-preamble=yes,也就是混合格式:基础数据用 RDB 格式保存,后续增量仍用 AOF 命令记录。恢复时先加载基础数据,再重放增量。Redis 7 的 AOF 已经是一组文件,备份时要确保清单和它引用的文件相互匹配。

5. RDB 与 AOF 恢复顺序​

同时启用 RDB 和 AOF 时,Redis 重启优先加载 AOF。两者不会自动拼成一份恢复结果,独立的 RDB 文件仍可用作时间点备份。

备份完成后,还要实际恢复并检查文件完整性和数据结果。备份应放在不会随运行实例一起损坏的位置。Redis 7.x 备份 AOF 目录时,要协调重写和清单切换,避免复制到一组彼此不匹配的文件。

6. 主从复制​

主从复制让副本先取得数据集,再持续接收主节点的命令流。复制默认是异步的,主节点返回写入成功时,副本未必已经收到这次写入。如果此时主节点故障,落后的副本被提升,就会丢失尚未复制的部分。

副本断线重连时,PSYNC 用复制 ID 判断是否属于匹配的复制历史,再用偏移量判断缺了哪一段。主节点的 backlog 是保留近期复制命令的缓冲区;历史匹配、缺失部分还在其中时,只需补发这一段,称为部分重同步。历史不匹配或缺口超出范围,就需要全量同步。

全量同步要重新传输数据集,再接上后续命令流。数据集越大,对主节点、网络和副本加载的压力越大。因此,规划 backlog 时,要结合写入速率和希望容忍的断连时长,尽量让短暂断线可以通过补发恢复。

7. 复制确认与落盘确认​

WAIT 等待本连接此前的写入被指定数量的副本确认,返回实际确认的副本数。如果超时时数量还没达到要求,只是停止等待,之前的写入不会自动撤销。副本收到数据,也不等于它已经把数据同步到磁盘。

Redis 7.2 起提供 WAITAOF,进一步等待本连接此前的写入在本地或副本完成 AOF 同步:

SET demo:order paid
WAITAOF 1 1 1000

这里先写入 demo:order,再要求本地和一个副本完成 AOF 同步,最多等待 1000 毫秒。相关节点要开启 AOF。返回的两个计数分别表示本地和副本的完成情况,客户端需要检查它们,不能只看命令有没有报错。

得到更多确认可以降低丢失风险,但故障后选哪个副本接管、哪些节点同时损坏,仍会影响结果。WAIT 和 WAITAOF 都不会自动把 Redis 变成强一致复制系统。

8. Sentinel​

Sentinel 监控一组主从节点,并在主节点故障时协调切换,客户端通过它发现新主节点。它解决接管服务的问题,数据是否完整仍受异步复制进度影响。

单个 Sentinel 因超时判断主节点不可达,叫作主观下线。达到配置的 quorum 个 Sentinel 同意后,才判定为客观下线。判定下线与执行切换是两步:真正发起故障转移,还需要取得多数 Sentinel 的授权。

例如有 5 个 Sentinel,quorum=2,两个节点同意就能判定主节点下线,但至少要取得 3 个节点授权才能切换。如果 quorum 本身高于多数,还要满足这个更高的数量要求。

客户端应支持主节点地址刷新和连接切换。切换期间的超时与重试,还需业务幂等处理。

9. Cluster 与哈希槽​

Cluster 先把键映射到槽,再把槽分配给主节点。哈希槽是分片的单位,总数为 16384,通常按 CRC16(key) mod 16384 计算。键包含有效 hash tag 时,改用花括号里的部分计算。每个主节点负责一部分槽,也可以配置副本。

{user:42}:profile 与 {user:42}:orders 使用相同 tag。因此它们落在同一槽,可参与要求同槽的多键操作。过度复用同一 tag,会把负载集中到一个节点。

MGET、事务和 Lua 脚本的多键访问要遵守同槽约束。客户端虽然可以把跨槽读取拆成多次请求,但这些请求分别执行,不再是一条原子操作。

10. MOVED 与 ASK 重定向​

MOVED 告诉客户端:这个槽现在由另一个节点负责。客户端要向目标节点重发请求,并更新本地的槽映射,让后续请求也去新节点。

ASK 则用于槽迁移期间,只临时转发本次请求。客户端在目标连接上先发送 ASKING,再执行原命令,长期槽映射保持不变。两者的差别是,下一次请求是否也应该改变目的地。

迁移中多键操作还会遇到 TRYAGAIN 等暂时错误。客户端应使用支持 Cluster 的实现,并限制重试预算。

11. Cluster 与网络分区​

Cluster 的异步复制仍存在已确认写入丢失窗口。分区中的旧主可在故障检测生效前短暂接受写入。另一侧提升副本后,这些写入会被丢弃。

少数派一侧失去继续服务的条件。默认 cluster-require-full-coverage=yes 时,未覆盖槽会影响整个集群服务。设为 no 后,可继续服务仍被覆盖的槽,但仍需满足集群继续服务的其他条件。

客户端需区分拓扑变化、暂时不可用与业务执行结果未知。写入重试应带幂等依据,并限制总耗时。

12. 恢复目标与配置​

RPO 是允许丢失多少数据的目标,通常用时间表示;RTO 是允许服务恢复花多长时间的目标。比如允许回退到一分钟前的数据,与必须保住每次确认写入,对持久化和复制的要求就不同。选配置时还要考虑是否需要分片、是否读副本,以及哪些节点可能同时故障。

缓存可从数据库重建时,重点是重建容量和恢复速度。Redis 保存权威状态时,还需独立备份与结果核对。选定策略后,应演练进程、磁盘与主节点故障。

13. 常见问题​

13.1 开启 AOF 后,已确认的写入就不会丢了吗?​

仍然可能丢失。AOF 只能恢复实际持久化的记录;如果发生主从切换,还要看新主节点已经接收了多少数据。持久化文件也可能损坏,所以要按 RPO 规划独立备份,并通过恢复演练验证结果。

13.2 客户端拆分跨槽操作后,还能保证原子性吗?​

14 · 面试题卡片​

本页题目与参考回答

14.1 Redis 的 RDB、AOF、复制和 Cluster 分别解决什么问题​

考察重点

  • 快照与命令日志的恢复点差异。
  • 异步复制和故障转移的数据窗口。
  • hash slot、重定向与多 key 限制。

相关内容:RDB至恢复目标与配置。

参考回答

RDB 和 AOF 提供恢复依据,复制保留运行副本,Cluster 将数据分片到多个主节点。

RDB 保存时间点快照,AOF 保存恢复所需的写操作。副本接收主节点的数据,Sentinel 协调主从故障转移;Cluster 则将 16384 个槽分给多个主节点。

持久化恢复点取决于有效文件和同步策略。故障转移还取决于副本已接收的进度。选择时应按 RPO、RTO 和分片需求配置并验证。

14.2 Redis 的 AOF 重写期间如何接收新写入,混合格式是什么?​

考察重点:基础文件、增量文件、manifest 与 RDB 前导。

相关内容:AOF 重写与混合格式。

参考回答

重写由子进程生成基础数据,父进程继续接收并记录新增写入,完成后把两部分衔接起来。

Redis 6 的父进程继续写旧 AOF,并保存增量;子进程生成的新文件补齐增量后,再替换旧文件。Redis 7.0 起,父进程写新的增量文件,子进程生成基础文件,完成后原子切换 manifest 清单。

Redis 6、7 默认 aof-use-rdb-preamble=yes。基础数据采用 RDB 格式,增量采用 AOF 命令。恢复时加载基础,再重放增量命令。

14.3 WAIT 与 WAITAOF 分别等待什么,超时会回滚写入吗?​

考察重点:复制确认、AOF 同步与返回计数。

相关内容:复制确认与落盘确认。

参考回答

WAIT 等待副本收到写入,WAITAOF 等待 AOF 同步完成;两者超时都不会自动回滚原写入。

WAITAOF 从 Redis 7.2 起提供,需要相关节点开启 AOF。客户端必须检查实际确认数:等待结束不代表要求的副本都已完成,故障转移时仍要看被提升副本的数据进度。

14.4 5 个 Sentinel、quorum=2 时,两个节点能完成自动故障转移吗?​

考察重点:客观下线与多数授权。

相关内容:Sentinel。

参考回答

5 个 Sentinel 中只有两个能互通时,无法完成自动故障转移。

quorum=2 允许这两个节点共同判定主节点客观下线,但切换仍需至少 3 个 Sentinel 的多数授权。quorum 负责故障判定,多数授权负责协调切换。

14.5 Cluster 的 MOVED 和 ASK 有什么区别?​

考察重点:槽映射、迁移与 ASKING。

相关内容:MOVED 与 ASK 重定向。

参考回答

MOVED 要求客户端更新槽映射,ASK 只临时改变本次请求的目的地。

收到 MOVED 后,客户端向目标节点重发,并让后续请求使用新的槽路由。收到 ASK 后,在目标连接先执行 ASKING,再重发原命令,原来的长期槽路由保持不变。

14.6 Redis 副本断线重连后,什么条件下能部分重同步?​

考察重点:复制 ID、偏移量与 backlog 保留范围。

相关内容:主从复制。

参考回答

复制历史必须匹配,backlog 还需覆盖副本缺失的偏移范围。

满足时,PSYNC 只补发缺失命令。历史不匹配或缺口超出范围时,需要全量同步。backlog 应结合写入速率和允许断连时长规划。

15. 参考资料​

来源:Coding 101 原文 · 免费阅读,引用请保留出处。内容使用说明