一句话回答

Redis 通过 RDB 快照和 AOF 日志实现数据持久化,通过异步主从复制保存副本,使用 Sentinel 完成主从架构的监控与自动切换,或使用 Redis Cluster 同时实现分片和故障转移。它们通常只能降低数据丢失风险,不能自动提供跨节点强一致。

面试考察点

  • 能否区分 RDB 和 AOF 的数据安全、恢复速度与运行开销。
  • 是否理解主从复制通常是异步的,故障切换可能丢数据。
  • 能否描述全量同步、增量同步和复制积压缓冲区。
  • 是否知道 Sentinel 解决高可用但不解决数据分片。
  • 能否说明 Cluster Slot、重定向和故障转移。
  • 是否具备脑裂、磁盘故障和恢复演练意识。

RDB 快照

RDB 在某个时间点生成内存数据快照文件,适合备份、全量复制和快速恢复。

优点:

  • 文件紧凑,适合备份和跨机房传输。
  • 重启恢复通常比重放大量 AOF 快。
  • 主进程主要负责 Fork,具体写文件由子进程完成。

不足:

  • 两次快照之间的数据可能在故障时丢失。
  • Fork 大进程会带来页表复制和延迟抖动。
  • 快照期间写入导致 Copy-on-Write,可能增加内存峰值。
  • 磁盘慢或内存大时生成时间较长。

Fork 和 Copy-on-Write

生成 RDB 时,子进程读取 Fork 时刻的内存视图。主进程继续处理写入;被修改的内存页复制后由主进程使用,子进程仍看到旧页。

因此执行 BGSAVE 时要关注:

  • 实例内存大小。
  • 系统剩余内存。
  • 写入速率。
  • Transparent Huge Pages。
  • Fork 耗时和磁盘吞吐。

高写入期间 COW 可能让 RSS 明显增长,容器 Limit 过紧会导致 OOMKilled。

AOF 日志

AOF 记录会改变数据的写命令,重启时重放恢复。

常见刷盘策略:

  • Always:每条命令同步磁盘,安全性高但吞吐和延迟成本大。
  • Everysec:通常每秒刷盘一次,性能与数据安全折中,故障时可能丢约一秒数据。
  • No:由操作系统决定刷盘,性能较好但丢失窗口更大。

生产常选择 Everysec,但要根据业务可接受的数据损失目标决定。

AOF Rewrite

AOF 持续追加会不断变大。Rewrite 根据当前内存状态生成等价但更紧凑的命令,例如一个 Key 被修改一万次,重写后只保留恢复当前值所需的命令。

Rewrite 同样涉及 Fork、COW、CPU 和磁盘 IO。不能只关注 AOF 文件大小,还要监控重写持续时间、失败次数和磁盘余量。

RDB 和 AOF 怎么选

维度 RDB AOF
数据丢失窗口 快照间隔 取决于刷盘策略
文件大小 通常较小 通常较大
恢复速度 通常较快 需要重放日志
运行开销 周期性 Fork 与写文件 持续追加与定期重写
备份 适合 也可使用但管理更复杂

重要数据可以同时开启 RDB 和 AOF。具体 Redis 版本的加载优先级和混合持久化能力需要结合官方文档和配置确认。

混合持久化

混合模式在 AOF 重写文件前部保存 RDB 格式快照,后部追加重写期间的命令,兼顾恢复速度和 AOF 的较小数据丢失窗口。

启用前要确认 Redis 版本、运维工具和备份流程都支持该格式。

持久化不等于备份

误删除和错误写入也会进入 AOF 和副本。持久化用于进程重启恢复,高可用用于实例故障切换,历史恢复仍需要独立备份、保留周期和恢复演练。

主从复制流程

Replica 连接 Master
       ↓
身份验证与复制握手
       ↓
能增量同步?
  ├── 是:发送积压缓冲区中的命令
  └── 否:生成 RDB 全量同步
       ↓
Replica 加载快照
       ↓
持续接收新写命令

主从复制通常异步,Master 执行成功后不会等待所有 Replica 应用。因此刚写入的数据可能暂时无法从 Replica 读取,Master 故障时尚未同步的数据也可能丢失。

全量同步

Replica 首次加入或断线太久时进行全量同步。Master 生成快照并发送,同时把期间的新写命令保存在缓冲区;Replica 加载快照后再应用增量命令。

大实例全量同步会消耗 Fork、磁盘、网络和 Replica 加载时间。多个 Replica 同时全量同步可能形成复制风暴。

增量同步

Master 维护复制 ID、Offset 和复制积压缓冲区。Replica 短暂断线重连后,如果缺失数据仍在缓冲区,可以只补发断线期间命令。

缓冲区过小会让稍长网络抖动退化为全量同步。大小应结合写入速率和预期最长断线时间配置。

复制延迟

常见原因:

  • 网络延迟或带宽不足。
  • Replica CPU、磁盘或内存压力。
  • Master 大量写入。
  • Big Key 传输和处理。
  • Lua 或慢命令阻塞事件循环。
  • Replica 执行持久化和全量同步。

读写分离时必须接受短暂旧数据。写后立刻读取关键状态应读 Master,或使用业务版本校验。

Sentinel 解决什么问题

Sentinel 监控 Master 和 Replica,在 Master 故障时选择 Replica 提升为新 Master,并通知其他 Replica 和客户端切换。

它提供:

  • 监控与故障检测。
  • 主观下线和客观下线判断。
  • Leader Sentinel 选举。
  • Replica 选主和故障转移。
  • 客户端获取当前 Master 地址。

Sentinel 不负责数据分片,数据集仍完整保存在每个 Master/Replica 节点。

主观下线与客观下线

单个 Sentinel 认为节点不可达是主观下线。达到配置数量的 Sentinel 都认为 Master 不可达,才形成客观下线并尝试故障转移。

这样可以减少单个 Sentinel 网络异常造成误切换,但仍需合理部署到不同故障域,并处理网络分区。

Sentinel 选新 Master 的考虑

通常综合 Replica 优先级、复制状态、数据 Offset 和稳定性选择。数据越接近原 Master 的 Replica 越适合提升。

故障切换期间客户端会经历短暂失败,需要使用支持 Sentinel 的客户端并配置重连、有限重试和幂等。

脑裂和数据丢失

网络分区时旧 Master 可能仍接收写入,而 Sentinel 在另一侧提升新 Master。网络恢复后旧 Master 降为 Replica,它在分区期间接收的写入可能丢失。

可通过限制 Master 在可用 Replica 不足或复制延迟过大时拒绝写入,降低脑裂损失。但这是用可用性换数据安全,仍无法提供严格共识一致性。

Redis Cluster

Cluster 将 16384 个 Slot 分配给多个 Master,每个 Master 管理部分数据,并可配置 Replica。

Key → CRC16 → Slot 0..16383 → 对应 Master

它解决:

  • 数据容量超过单机内存。
  • 写入和读取压力水平分散。
  • 单 Master 故障时由 Replica 提升。

MOVED 和 ASK

客户端请求到错误节点时:

  • MOVED 表示 Slot 已稳定属于另一个节点,客户端应更新拓扑缓存。
  • ASK 常见于 Slot 迁移过程中,表示本次请求临时去目标节点,但不立即永久修改归属。

生产应使用支持 Cluster 拓扑感知的客户端,不要自己手写重定向逻辑。

Cluster 的限制

  • 多 Key 操作通常要求 Key 在同一 Slot。
  • 故障切换仍可能丢失未同步写入。
  • Slot 迁移时 Big Key 会造成抖动。
  • 节点扩缩容涉及数据迁移和带宽。
  • 热 Key 可能让单 Slot、单节点过载。
  • Cluster Bus 和节点数量增加运维复杂度。

Sentinel 和 Cluster 怎么选

  • 数据量能放入单机、主要需要自动主从切换:Sentinel。
  • 数据量或吞吐需要水平分片:Cluster。
  • 强一致事务、跨 Key 复杂关系:重新评估 Redis 是否适合做事实源。

云厂商代理版 Redis 可能隐藏 Sentinel 或 Cluster 细节,但数据丢失窗口、分片限制和故障语义仍需向厂商确认。

故障切换期间客户端设计

  • 使用连接池和拓扑感知客户端。
  • 设置连接、命令和重试超时。
  • 只对幂等操作进行有限重试。
  • 写失败不能无限重试并堵塞业务线程。
  • 关键写入要有数据库或消息日志作为事实源。
  • 熔断和降级避免重连风暴。

数据恢复流程

  1. 隔离故障实例,避免继续接受写入。
  2. 保存 RDB、AOF 和日志副本。
  3. 在隔离环境验证文件完整性。
  4. 启动临时实例加载数据。
  5. 对比业务数据库或事件日志进行校验。
  6. 根据恢复点补偿缺失数据。
  7. 灰度切换流量并持续观察。

不要直接拿未经验证的持久化文件覆盖线上当前数据。

监控指标

  • used_memory、RSS 和内存碎片率。
  • RDB/AOF 最近成功时间和失败次数。
  • AOF 重写状态和文件大小。
  • 主从复制 Offset 和延迟。
  • Replica 连接状态与全量同步次数。
  • Sentinel 切换事件。
  • Cluster Slot 覆盖和失败节点。
  • 磁盘容量、Fork 耗时和 COW 内存。

常见误区

  • 开启 AOF 就绝对不丢数据。
  • 有 Replica 就等于完成备份。
  • Sentinel 能解决数据分片。
  • Cluster 能提供强一致。
  • Redis 只使用内存,磁盘性能不重要。
  • Fork 不会影响线上延迟。
  • 故障切换后客户端会自动无感恢复。

核心考点清单

  • RDB 适合快照备份和快速恢复,AOF 提供更小的数据丢失窗口。
  • Fork 和 COW 会带来延迟和内存峰值。
  • 主从复制通常异步,故障切换可能丢失未同步数据。
  • Sentinel 提供单主多从的自动故障转移,不负责分片。
  • Cluster 使用 16384 个 Slot 实现数据分片和节点扩展。
  • 高可用、持久化和备份解决不同问题,三者都需要。

高频追问与参考回答

追问 1:RDB 和 AOF 应该怎么选?

缓存可只使用 RDB 或接受重建;重要数据通常同时使用 RDB 与 AOF,并选择 Everysec 等合适刷盘策略。但 Redis 仍不应替代关键业务事实数据库。

追问 2:AOF Everysec 会丢多少数据?

通常可能丢失最近约一秒尚未同步磁盘的数据,但具体还受操作系统、磁盘和 Redis 实现影响。机器或磁盘故障场景不能做绝对承诺。

追问 3:为什么主从切换会丢数据?

复制异步,Master 已确认但尚未发送或 Replica 尚未应用的写入,在原 Master 故障后不会存在于新 Master。

追问 4:Sentinel 需要几个节点?

通常至少三个并部署在不同故障域,以形成多数判断。还要根据 Quorum 和故障转移授权配置,不能只看进程数量。

追问 5:Redis Cluster 为什么是 16384 个 Slot?

Slot 是 Key 到节点之间的逻辑分片层,便于迁移和拓扑管理。固定数量在集群消息开销和分片粒度间折中,客户端无需为每个 Key 保存节点映射。

追问 6:如何减少脑裂造成的数据丢失?

限制 Master 在可用 Replica 数不足或复制延迟过大时拒绝写入,将节点分布在合理故障域,并让关键业务拥有外部事实源和补偿。这会牺牲部分可用性。

追问 7:持久化文件损坏怎么办?

先复制原文件,在隔离环境使用官方检查和修复工具评估,再结合历史备份和业务事实源恢复。不要直接在唯一线上副本上操作。

机制全景图

「Redis 持久化和高可用是怎么实现的?」的实现链路如下,节点可与后面的源码和运行证据逐一对应。

flowchart LR
    A["内存写入完成"]
    A --> B["AOF 或 RDB 持久化"]
    B --> C["主从复制传播"]
    C --> D["Sentinel/Cluster 检测故障"]
    D --> E["选主恢复并核对数据"]

源码与实现定位

入口 阅读重点
src/rdb.c/aof.c 快照、AOF 与重写
INFO persistence/replication fork、fsync、复制偏移

源码或系统表应按上表顺序追踪:先确认入口实际走到哪条路径,再用运行时数据验证,而不是仅凭类名或配置推测。

参数配置与可复现实验

CONFIG SET appendonly yes
CONFIG SET appendfsync everysec
CONFIG SET repl-backlog-size 256mb

分别 kill -9 主库、断开副本超出 backlog、在高写入时 BGSAVE,测 RPO、RTO 与 COW 内存。

验证步骤与预期结果

1. 固定输入和基线

先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「fork COW」为主基线,记录值应满足「<容器余量」;同时保存 aof_delayed_fsync、fork 耗时与 COW,使后续变化能够回到同一时间轴比较。

2. 从实现入口确认路径

在「src/rdb.c/aof.c」确认请求确实进入「快照、AOF 与重写」对应的实现,再沿「INFO persistence/replication」观察「fork、fsync、复制偏移」。如果入口路径都未命中,就不应继续调整下游参数,而应先检查调用条件、版本或路由是否与假设一致。

3. 注入本文特有的失败模式

优先复现「fork 时写时复制导致内存翻倍」,并把单一变量逐级放大,直到「fork COW」越过「RSS逼近limit」。随后再分别验证「复制积压不足频繁全量同步」和「把异步副本当成强一致备份」,三类故障分开执行,避免多个变量同时变化而无法归因。

4. 执行止损和根因修复

第一轮只应用「为 fork 预留内存」,确认它能控制影响范围;第二轮应用「backlog 覆盖最长断线窗口」,验证核心链路恢复;最后落实「明确 Redis 是否可从事实源重建」,消除同类问题再次出现的条件。每一步都保留变更前后数据,不用“感觉变快了”替代测量。

5. 通过退出条件

实验只有同时满足三项才算通过:「fork COW」回到「<容器余量」、「复制偏移差」回到「故障目标内」、「aof delayed fsync」回到「0 或偶发」,并且业务结果差异为零。若性能恢复但结果不一致,仍应视为失败;若指标恢复后很快再次越线,则说明只完成了临时止损,没有消除根因。

量化基线

指标 样例基线/口径 风险线 结论
fork COW <容器余量 RSS逼近limit 快照风险
复制偏移差 故障目标内 超 backlog 全量同步
aof delayed fsync 0 或偶发 持续增长 磁盘抖动

这些数值是实验口径或示例告警线,不是可复制到所有系统的固定答案;上线阈值应由本系统稳态、峰值和故障演练共同确定。

事故复盘:故障切换后少量订单资格丢失

主库返回成功后尚未把写传播到副本就宕机,新主缺少该 Key。异步复制不能承诺零丢失;资格状态若不可丢,应落可靠数据库/日志或在写入时等待足够副本并接受延迟。

失败模式 首要证据 第一处置动作
fork 时写时复制导致内存翻倍 aof_delayed_fsync 为 fork 预留内存
复制积压不足频繁全量同步 fork 耗时与 COW backlog 覆盖最长断线窗口
把异步副本当成强一致备份 master_repl_offset 差距 明确 Redis 是否可从事实源重建

发布与回滚检查点

  • 发布前:确认「src/rdb.c/aof.c」对应实现和上述配置在目标版本仍然有效,并保存「fork COW」基线。
  • 灰度中:同时观察 aof_delayed_fsync、fork 耗时与 COW、master_repl_offset 差距;任一指标越过表中风险线,就停止继续扩量。
  • 回滚时:先执行「为 fork 预留内存」控制影响,再回退代码或参数;涉及持久状态时必须额外核对结果差异。
  • 发布后:至少覆盖一个完整峰值周期,确认「fork 时写时复制导致内存翻倍」没有再次出现,才关闭变更观察窗口。

设计边界与工程取舍

高可用保证服务尽快恢复,不自动保证所有已确认写都存在;必须按数据价值选择 Redis 是事实源还是可重建派生数据。