关于Raft算法的共识性算法考究

前言

18年写过一个Raft的实现, 开源在https://github.com/srctar/raft。时隔两年, 回顾一下。

Raft算法为主从结构, 其分布式一致性来源于集群的写全委托给LeaderLeader进程自身保证顺序与一致性, 并发起投票要求Follower追加写, 一旦过半赞成写请求(同时附加写的动作), 则该写完成。
.
需要注意的是, 集群的写是线性一致性/强一致性的, 同时基于Follower转发的集群的读也是现行一致性/强一致性的。并非ZAB的顺序一致性

这两天想到一个问题, raft算法的成员共识性问题。我之前的理解是:

Raft有共识性问题。 当未实现所有日志提交的Follower,之后被选举为新的leader之后, 源于raft日志的leader覆盖规则, 将导致数据丢失。

↑↑上面这个想法是错误的↑↑Raft算法的安全性保证(阻止不包含最新Term和日志编号的Follower成为Leader、复制旧Leader数据)达成共识,确保了成员数据的一致性(相应的,ZAB使用主从相互拷贝的形式,达成集群共识)。


关于Raft, 我对其做了一个Java版的实现, 地址在: https://github.com/srctar/raft。 欢迎阅读。
目前实现了 raft 协议的下述功能:

  • 集群选举.
  • 数据一致性.
  • 集群配置(集群节点信息, 以及集群的数目)更改.
  • 紧急提交.
  • 日志压缩.

Raft算法选举

选举流程参考网站:http://thesecretlivesofdata.com/raft/
本文的部分图片以及理论基础参考: https://blog.csdn.net/luoyhang003/article/details/61915666
如下Gif:

在这里插入图片描述
选举主要注意两点:

  1. 心跳超时(不管是初始态还是运行态);
  2. 只要当前机器尚未投票(包括自己), 就一定投票给申请投票者,同时重置心跳准备再次超时。

由于是多线程操作, 时序图与流程图皆不好画, 请参阅文字:

Raft为集群状态定义为: ELECTION(选举态), PROCESSING(运行态)
.
每个Raft节点有三个状态:FOLLOWERLEADERCANDIDATE(选举者)

  1. 独立线程心跳超时(一般是100ms);
    a. 独立线程可以位于FOLLOWER, 也可以位于刚启动的集群节点,还可以位于宕机、网络中断的节点。
    b. LEADER节点无该独立线程(它负责给别的节点发心跳)。
    c. -
  2. 该线程休眠 150~300ms高于心跳超时时间100ms
    a.此操作非常重要,用以防止选票分散,进而导致长期超时
    b.休眠中的线程可以接受投票。
    c. -
  3. 投自己一票,并向集群中的节点申请投票。
    a. 节点处于集群选举中ELECTION,且未给任何节点投票,节点默认接受投票申请。
    b. -
  4. 当某节点收到过半赞许,节点立马转化为 LEADER。 关闭心跳线程, 同时给其它节点发送心跳。
    a. 节点处于运行态 PROCESSING, 且自身是LEADER显然,一定有个老leader网断了,然后又网好了。 只要对方的Term大于自己, 那自己立马转化为FOLLOWER
    b. -
  5. 选举态的节点收到心跳, 转化为FOLLOWER, 同时重设心跳线程。
    a. 注意, 节点处于选举态 ELECTION, 需要心跳发送者的Term高于自己,否则返回拒绝(APPEND_ENTRIES_DENY)
    b. 节点处于运行态 PROCESSING, 需要匹配心跳者是否是集群LEADER。是则重置心跳线程, 否则直接拒绝。
    c. -

如上选举算法设计, 合理的确保下如下表格中的case, 能快速选上leader、且非过半宕机时,集群可用:

Case担忧点解决方案
正常启动选Leader选不上重选/启动时参与选举有线程休眠时间150~300ms, 此时接受投票一定赞同,确保选举
不过半的Follower宕机/失联可用性可用, Leader不宕机,不影响选举, 不过半宕机,不影响数据投票
过半Follower宕机可用性Leader不宕机,还能接受数据, 过半宕机,影响数据投票, 集群不可用
不过半宕机, 包含Leader可用性可用, 心跳超时再选举, 通常一轮就能选出新Leader,集群正常服务
不过半宕机, 包含Leader可用性不可用, 选不出Leader
Leader失联集群状态其他机器依旧能选上新Leader, 期序Term累加,旧Leader恢复之后接受心跳转为Follower
Leader宕机集群状态其他机器依旧能选上新Leader, 重启之后接受心跳转为Follower

Raft算法数据一致性

此处讲解的一致性, 分为两点:

  1. Raft 集群正常运行态的数据一致性;
  2. Raft 集群宕机恢复后的数据一致性。

正常运行态的强一致性

正常运行态, Raft的写满足强一致性/线性一致性在这里插入图片描述
但是读也能满足到线性一致性。


Raft协议定义, 读由Follower转发给Leader, 因此能够保证最新commited读, 这种Case下,也无须关心过半不赞同的回滚策略。数据不提交即可。

但是针对这个算法, 也有优化, 例如对比FollowerLeadercommitIndex, 一致的话由Follower读, 也是线性一致的。

Raft集群的数据共识(集群恢复时)

本节讲的是集群某些机器宕机, 数据也没有来得及同步的情况下, 集群如何保证的数据一致性。
↓↓↓↓↓↓↓↓注意下面例子,Raft是解决了的, 实际并不存在↓↓↓↓↓↓↓↓

极端情况,新Leader上位,集群状态却如下图:

如上图,相对于新的leader:

  1. a、b 丢失了部分数据
  2. c、d 多出来部分数据
  3. e、f 既丢失, 又多出来了数据

毕竟Raft的同步逻辑,过半提交则为提交, 之后Leader一直重试保证数据一致。
像b, 网络不佳,就是没同步上;
像d, 它就是上一个leader,自身提交前,还没来得及集群同步,网断了;

那类似这种情况, Raft集群的数据共识是怎么达成的呢? 如下方案:

  1. 选举限制。 除了匹配Term外, 还匹配日志版本, 大于等于自身日志版本的投票才会被授予。以此确保多数赞成的数据是最新的。
  2. 尝试复制老旧Leader上已提交(过半赞成)的日志,因为已提交, 则至少当前被复制条目以及之前的日志都是可以被提交的。

如上操作确保了只有持有最新日志的节点才能成为Leader, 且它将会尝试复制老旧Leader的日志数据。
此项操作通过排序和重发布确保数据的有序性, 但是会一定程度的增加系统复杂度。

Raft算法的其他集群变更、日志压缩功能

这部分功能没有实现, 具体可参阅 https://blog.csdn.net/luoyhang003/article/details/61915666

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值