← 返回题目列表

Raft 日志压缩和快照有什么作用?

中等 第 20 / 26 题 更新于 2026/09/30
Raft日志压缩快照故障恢复
学习 AI 实战项目

简化版

Raft 日志会无限增长,快照把某个已应用索引之前的状态机结果压缩成一个检查点,随后可删除被快照覆盖的旧日志。 快照必须记录 lastIncludedIndex/Term,安装时原子替换状态机。 落后 Follower 所需日志已被删除时,Leader 发送快照,再补快照之后的日志。

详细版

只有已经提交并应用的前缀才能进入快照,不能压缩未提交条目。 生成快照时要得到一致状态视图,可使用 copy-on-write、存储引擎 checkpoint 或短暂停写,不能读取半更新状态。 快照文件包含版本、校验和、成员/状态机所需元数据及 lastIncludedIndex/Term。

安装采用临时文件、分块校验和原子切换,失败保留旧状态。 若 Follower 已有与快照边界匹配的后续日志可以保留,否则丢弃冲突后缀。 日志保留阈值要平衡磁盘空间、生成开销和落后节点触发快照的频率。

完整版教学

一、为什么不能永久保留日志

每个写命令都追加日志,运行一年可能积累数十亿条。 重启从头重放会非常慢,磁盘与备份成本也持续增长。 快照保存某个确定点的状态机结果,使恢复从检查点开始。

快照压缩历史,不改变共识历史的提交语义;边界之前的效果必须已经确定。

二、快照边界信息

snapshot:
  lastIncludedIndex: 500000
  lastIncludedTerm:  87
  stateMachineData:  ...
  checksum:          ...

index/term 用于把快照与后续日志连接,并参与日志匹配。 仅保存业务数据而不保存边界,会让恢复后无法判断日志前缀。

三、何时可以创建

快照上限通常不超过 appliedIndex。 commitIndex 高于 appliedIndex 的部分尚未执行,不能凭日志内容猜测状态。 可按日志字节、条目数、恢复时间目标或磁盘水位触发。 多个节点可各自生成相同逻辑状态的快照,不要求二进制字节完全相同,但状态机必须确定。

四、一致快照如何生成

状态机在持续应用写入时直接遍历可能得到混合时点。 存储引擎 checkpoint、MVCC snapshot 或 copy-on-write 可提供一致视图。 小状态机也可短暂暂停 apply,但会增加延迟。 生成失败不能删除旧日志,必须等快照完整验证和持久化后再裁剪。

五、安装快照

安装情况接收方动作保留哪些日志
快照边界早于本地提交进度忽略或仅作校验保留现有更新状态
边界后的本地日志与快照 term 匹配原子替换状态机可保留匹配边界之后的后缀
边界冲突或本地严重落后原子安装完整快照丢弃无法衔接的旧后缀
传输中断不切换活动状态重试分块传输,避免半快照可见

Leader 发现 Follower nextIndex 早于日志保留起点,发送 InstallSnapshot。 大快照分块传输,携带 offset、校验和和会话标识。 Follower 写临时文件,完整校验后原子替换状态机与元数据。 断线可安全重试,半文件不可对外服务。

六、与现有日志的衔接

若 Follower 在 lastIncludedIndex 位置的 term 与快照一致,可保留其后的匹配日志。 若边界冲突,则丢弃不兼容后缀,从快照后重新复制。 安装后 commitIndex/appliedIndex 至少达到快照边界。 成员配置若由日志状态决定,也必须在快照中保留恢复所需信息。

七、容量与观测

压缩过于频繁会消耗 CPU、IO 和网络。 保留太少日志会让短暂掉线节点也频繁安装大快照。 监控日志大小、快照生成时长、文件大小、安装次数、失败率和 tail catch-up 时间。 例如每天 100 GB 日志、快照 500 GB 时,网络带宽可能比日志保留更昂贵,需要实测权衡。

八、常见误区与追问

  • 误区:日志提交后立刻就能删除。 至少要由完整持久快照覆盖。
  • 误区:快照只保存业务数据。 还要保存 index、term 和恢复所需元数据。
  • 误区:安装时直接覆盖线上文件。 半途失败会损坏状态,应临时写入后原子切换。
  • 误区:快照越频繁恢复越快。 生成与传输成本可能拖慢系统。
  • 追问:为何需要 lastIncludedTerm? 用于快照边界后的日志匹配与安全判断。
  • 追问:生成时能继续写吗? 可以,但必须有一致视图机制;否则需暂停 apply。
  • 追问:Follower 太落后怎么办? 安装快照,再追快照后的增量日志。

九、加强记忆

  1. 快照只覆盖已提交且已应用的日志前缀。
  2. 必带 lastIncludedIndex 和 Term。
  3. 完整持久化并校验后才能裁剪日志。
  4. 安装使用分块、校验和原子替换。
  5. 阈值在磁盘、恢复时间与快照成本之间权衡。