日志项的结构与理解
日志项是Raft中存储数据的基本单元,由以下三部分组成:
- 指令(Command):客户端请求的操作指令,由状态机执行。
- 索引值(Log Index):连续递增的整数,标识日志项的唯一位置。
- 任期编号(Term):创建该日志项的领导者任期编号。
日志项的连续性确保了数据的一致性,索引值和任期编号共同用于检测日志冲突和同步状态。
日志复制过程
Raft通过优化后的二阶段提交实现日志复制,具体流程如下:
- 领导者创建日志项:客户端请求到达后,领导者将指令封装为日志项并追加到本地日志。
- 日志复制RPC:领导者向所有跟随者发送包含新日志项的
AppendEntries RPC。 - 多数派确认:若大多数节点成功复制日志项,领导者将该日志项应用到状态机并返回成功给客户端。
- 跟随者提交日志:跟随者通过心跳或RPC消息感知领导者的提交位置,将未应用的日志项提交到本地状态机。
此过程通过减少消息往返次数(二阶段优化为一阶段)降低了延迟。
处理日志不一致
当节点间日志出现分歧时,Raft通过以下机制强制同步:
- 一致性检查:领导者发送
AppendEntries RPC时附带前一条日志的索引(PrevLogIndex)和任期(PrevLogTerm)。 - 日志匹配:跟随者检查本地日志是否匹配
PrevLogIndex和PrevLogTerm。若不匹配,返回失败。 - 回溯同步:领导者逐步递减索引值,直到找到双方一致的最后一条日志,随后覆盖跟随者后续的不一致日志。
关键点:
- 领导者始终不删除或覆盖自身日志。
- 跟随者的不一致日志会被领导者的日志强制替换。
课堂思考解答
问题:若某个节点未成功复制日志(不在“大多数”中),Raft如何保证一致性?
回答:
- 领导者处理:若领导者未收到多数派确认,客户端请求被视为失败,日志项不会被提交到状态机。
- 后续同步:当该节点恢复通信时,领导者通过
AppendEntries RPC强制同步缺失的日志项,覆盖其本地不一致部分。 - 选举限制:只有日志最完整的节点能成为新领导者,确保未提交的日志项不会通过选举扩散。
例子:若领导者提交日志后崩溃,新领导者必须拥有该日志(即使未提交),并在后续同步中强制其他节点匹配。
补充说明
- 日志连续性:Raft要求日志必须连续,而Multi-Paxos允许非连续日志。
- 选举与日志完整性:只有日志最完整的节点能当选领导者,确保数据一致性优先。
- 优化建议:实际实现中可让跟随者主动报告缺失的日志范围,减少RPC往返次数(如扩展
AppendEntries的响应字段)。