Raft协议:新/重选领导者如何获取真实lastApplied?是否重复应用日志?
Raft中关于lastApplied的两个核心问题解析
1. 新领导者如何知晓真实的lastApplied?
首先明确:lastApplied是每个节点本地维护的volatile变量,记录已经成功应用到状态机的日志条目索引,它不需要在节点间同步。
新领导者当选后,根本不需要主动去获取其他节点的lastApplied值。Raft的核心逻辑是通过日志复制一致性来保证状态机一致:
- 新领导者凭借自身拥有集群中最新的日志(Raft选主规则强制要求),会向所有跟随者发送
AppendEntriesRPC,携带自己的日志信息(包括当前commitIndex)。 - 跟随者收到RPC后,会对比自身日志与领导者日志的一致性,返回匹配结果;领导者根据回复调整对该跟随者的
nextIndex,逐步完成日志同步。 - 跟随者自己负责在日志同步完成后,将已提交的日志(commitIndex >= 日志索引)应用到状态机,并更新本地的
lastApplied。
新领导者只需要关注日志的一致性和提交状态,不需要关心每个跟随者的lastApplied具体数值——只要日志同步完成,跟随者的状态机自然会和领导者一致。
2. 领导者崩溃后再次当选,如何获取真实的lastApplied?会重复应用日志吗?
获取真实lastApplied的机制
Raft规范中,lastApplied属于不需要持久化的volatile变量,但节点重启(崩溃后恢复)时,有两种可靠方式恢复真实的lastApplied:
- 从状态机读取:状态机本身可以记录最后一次应用的日志索引(比如在状态机中维护一个元数据字段),节点重启后直接读取这个值作为初始
lastApplied。 - 基于幂等性重新确认:如果状态机没有记录,节点可以将
lastApplied初始化为0,然后将commitIndex设置为本地日志中已提交的最大索引(通过日志的持久化记录判断),之后逐步将commitIndex之前的日志重新应用到状态机——由于状态机的应用操作是幂等的,重复应用同一日志条目不会改变状态机的最终状态。
避免重复应用的核心逻辑
领导者崩溃后再次当选时,不会出现破坏性的重复应用:
- 首先,领导者崩溃前已经将所有日志条目持久化到本地存储,重启后可以完整恢复日志。
- 当选新领导者后,它会先确认集群中已提交的日志范围(通过与多数派节点的日志一致性检查),更新自己的commitIndex。
- 之后,它只会将
commitIndex大于lastApplied的日志条目应用到状态机——如果重启后lastApplied因未持久化被重置,状态机的幂等性会保证重复应用的日志不会产生错误结果。 - 另外,Raft的日志条目本身带有唯一的term和索引标识,状态机可以通过这些标识跳过已经应用过的条目,进一步避免无效的重复操作。
内容的提问来源于stack exchange,提问作者merow
相关产品推荐
相关产品推荐

