Skip to content

因果时钟与日志投票推演 · 完整向量时钟推演至日志投票完整推演 ​

返回分篇目录

前置:能区分消息发送与接收、读写调用与返回,理解副本和网络分区;Python 3.10+ 仅用于离线时钟与日志推演。教学范围为Lamport1978;Gilbert/Lynch2002与2012回顾;Python 3.10+。核对日期2026-10-17。示例未执行,本轮没有安装依赖、生成协议代码、启动服务或浏览器预览。完整源码和输入文件见下方「同源完整文件」;推演结论只适用于写明的模型。

因果时钟与日志投票推演 ​

前置:能区分消息发送与接收、读写调用与返回,理解副本和网络分区;Python 3.10+ 仅用于离线时钟与日志推演。教学范围为Lamport1978;Gilbert/Lynch2002与2012回顾;Python 3.10+。核对日期2026-10-17。示例未执行,本轮没有安装依赖、生成协议代码、启动服务或浏览器预览。完整源码和输入文件见下方「同源完整文件」;推演结论只适用于写明的模型。

完整向量时钟推演 ​

完整向量时钟推演支持本地事件、发送和接收,发送事件递增本节点,接收先逐分量合并再递增。输入只描述离线事件,不运行网络;消息标识必须存在且只发送一次,保持因果引用可追踪。

向量时钟预期历史 ​

向量时钟预期历史:A发送m得到快照[1,0],B先有本地事件[0,1],B接收m合并并递增得[1,2]。发送快照必须复制,若保存同一可变列表,后续事件会篡改过去消息的时间戳,破坏历史证据。

并发与因果练习 ​

并发与因果练习比较[2,0]与[1,2],两者不可比较;再比较[1,0]与[1,2],前者先行。加入B回复A,计算传递后的知识;不能只比较分量总和,因为不同方向的分量代表不同事件来源。

日志投票完整推演 ​

日志投票完整推演在三节点A、B、C上按输入事件改变角色、任期、投票、日志、matchIndex、commitIndex和累加器,每个事件输出完整状态快照。初始A与B持有任期1、delta=5的索引1,C为空,所有commit为0。A进入任期2并取得B投票后成为领导;给B发送前缀匹配的空追加,明确确认索引1已在A/B多数上。此时commit操作仍不推进,因为没有任期2条目。

随后A追加任期2、delta=7的索引2。先给C发送prev_index=1被拒绝,因为C没有该前缀;改从prev_index=0发送完整后缀后,A/C确认索引2。commit推进到2,A按索引应用5与7得到12。继续给C发空追加传播commit,再给B补索引2,三者最终日志相同且commit=applied=2、value=12;A为leader、B/C为follower,majority=2。程序只在事件明确送达时才改变远端状态,不能把A已提交说成C在接到通知前已经应用。

vote-counterexample.json另给B/C最后日志任期2、索引2而A只有任期1、索引1。A升到任期3并不自动变成最新,B/C都拒绝投票,A最终仍为candidate,仅有自己一票。把候选日志检查删掉就会错误选出缺少新条目的领导;这是规则反例,不是对完整协议的故障注入实验。log_walk.py假定初始日志来自合法历史且初始未提交,没有成员变更、自动重试、部分批次、选举超时或磁盘故障;它帮助逐事件手推核心规则,不是Raft库。

candidate-stepdown.json检查角色变化与前缀校验的先后:三节点初始任期1、空日志。A升任期2并取得B票成为领导;C尚未收到A消息,自行升任期2成为candidate。A追加索引1后向C发送prev_index=1,C缺少该前缀,accepted=false;但同任期合法领导的AppendEntries已足以让C退为follower,不能等前缀匹配成功才退选。预期C仍term=2、log=[]、commit=0、voted_for=C、role=follower;退选不清除同任期已投的一票。所有结果仅静态手推,未执行。

继续阅读