分布式中 幽灵复现是指在不同的时间点读取同一份数据可能出现前后不一致的问题,其本质还是分布式一致性没有得到保障
现象
有三台节点 a b c,初始日志复制如下[数值表示term 数值下标表示index]
a 1 1
b 1 1
c 1 1
假设 a写入日志
a 1 1 1 【1】 【1】 【1】三条term为1 ,index为0,1,2
假设日志内容是 add [x=1] [y=2] [z=3]
b 1 1
c 1 1
此时a挂掉,b成为leader
b 1 1
c 1 1
此时读取数据为x=1 y=2 z 的日志由于a挂掉读取不到
假设此时b挂掉 a再次选举 a的index和term决定a可以成为leader
此时读取数据为x=1 y=2 z=3
出现幽灵复现 即在第二轮没有读到的数据在第三轮读到
raft解决方案
不同的一致性算法有不同的解决方案
raft如下解决
1 每次选举term++,随后追加当前term的NOOP日志
2 commitIndex 只有term相同的时候才可以提交
3 日志服从leader节点可以回退
假设初始a,b,c如下,【假设a是leader】
a 1 2
b 1 2
c 1 2
A 以下情形 【不可以存在,index=2 ,term=3 的日志如果没有过半 a无法提交commitindex 就不会出现
index=3,term=3的日志】
a 1 2 3 3
b 1 2
c 1 2
B1
a 1 2 (3) (3)
b 1 2 3
c 1 2
B2 a挂掉b 此时只能是b选择leader 日志一致
a 1 2
b 1 2 3
c 1 2
B11
a 1 2 (2) (2)
b 1 2 2
c 1 2
B2 a挂掉 c选择leader 追加noop,b的index=2 term 不同于leader 开始backoff 最终日志一致
假设没有term约束 那么b,c在index = 2 的term则会不一致
a 1 2
b 1 2 2
c 1 2 【3】noop
案例多多,最终相关结论如下
新leader必须追加noop日志解决幽灵复现,同时新leader认为所有follower的节点nextindex和noop之前相同,但还没有感知到matchindex matchindex全部为0
追加日志必须 previndex >= last prevterm 和lastterm相同
commitindex leader 必须term相同 newcommitindex> commitindex
如果日志匹配不上follower需要回退,leader会回退nextindex重新发起日志直到匹配成功后确定backoffsetindex
append必须比较term和previndex 【这点可以类比区块链】