Raft 算法初识

About Raft
Raft是一个实现分布式一致性的协议。
定义节点的三种状态:


image.png

Term 选举轮次

1、leader选举(Leader Election)

首先,所有的节点均从follower state(图1-1) 开始:

Raft 算法初识_第1张图片
图1-1

如果 followers在心跳时间内没接收到leader发送的心跳消息,它会变成candidate状态。

Raft 算法初识_第2张图片
图1-2

如图1-2的节点a(最快变成)变成了candidate状态。

然后节点a会向集群中所有节点(节点b和c)发起投票,图1-3中的绿色实点。

Raft 算法初识_第3张图片
图1-3

然后节点b和c回复节点a的投票,图1-4中的绿色虚点

Raft 算法初识_第4张图片
图1-4

如果candidate(图1-4中的节点a)收到了过半节点的回复,则节点a就变成了leader,图1-5中的节点a

Raft 算法初识_第5张图片
图1-5

这个处理过程就是Leader选举。接下来,系统中所有的变更都要leader节点发起处理。并通过日志entry的形式假追加到节点的日志文件尾部。

Detail:
在raft算法中,有两个超时配置项控制着leader选举,第一个是选举超时时间>(election timeout),该配置项意味着follower会等待leader选举的时间段,如果在这>个时间段内,还没有leader被选举出来,那么该follower会变成candidate状态,这个>选举超时时间一般会在150ms 和 300ms区间范围内的一个随机数。

情况一:
Raft 算法初识_第6张图片
图1-6

如图1-6所示,节点b会首先到达选举超时时间,那么它会先变成candidate。变成candidate后,该节点先回把自己的term 加1;然后为自己投票,所以Vote Count也变成了1,重置选举超时时间如图1-7所示。

Raft 算法初识_第7张图片
图1-7

接着,节点b会向集群所有节点发起投票请求(1的绿求),当follower节点收到投票请求后,会更新自己的term(与节点b一样),然后更新投票为节点B并且重置选举超时时间,向candidate(节点b)响应ack(3中的绿圈),当节b收到过半响应后,就把自己变成leader状态,图1-8的展示过程。
1 2 3 4

Raft 算法初识_第8张图片
图1-8

节点b变成leader后,开始向集群的follower节点发送日志追加消息,并且开始向集群内的follower发送心跳消息,然后follower响应心跳,如图1-9。此处的心跳消息就是控制着leader选举的第二个超时配置项,换言之,当leader选举出来后,如果follower在心跳时间内还没收到消息,follower会在次变成candidate,重新发起leader选举。

Raft 算法初识_第9张图片
图1-9

情况1.1,此时follower节点时因为原来的节点B确实挂了,follower节点确实无法再收到心跳请求。这是节点A成立leader节点(1-10.1),此时自己的term加一变成2,在向集群所有节点发送心跳消息(包括已挂节点,1-10.2中的实心红点),当然如果follower收到心跳消息后,发现自己的term比leader小,那么会马上更新自己的term,这里节点c更新自己的term为2,并回复心跳消息(1-10.3)
1 2 3

Raft 算法初识_第10张图片
1-10

顺便说一下,过半机制就可以保证每一轮leader选举,就只有一个节点可以成为leader。

情况二:

刚刚的情况一是刚好只有一个节点变成candidate,那么如果同时有两个节点变成candidate,会怎么处理呢?
1 2 3 4 5

Raft 算法初识_第11张图片
1-11

如图1-11,在过了选举超时时间后,集群中的节点B和节点C同时变成了candidate后(1-11.2),各自为自己投票后,并且同时向集群内所有节点发起投票(1-11.3),然后节点A会为节点B投票,节点,节点D会为节点C投票。这里,follower的投票策略为,假如follower已近为节点X投票,并且节点X的term为n,那么,follower就不会接受term <=n的其他投票。这时候,节点B和节点C都获取了两票投票,由于没获取过半的投票赞成,所以两者只能重置自己的选举超时时间。最后节点C最先过了选举超时时间,然后,然后更新自己的term并重新发起投票,这时,由于没有竞选者,就成了master节点(1-11.5)。


2、日志复制(Log Replication)

Raft 算法初识_第12张图片
图2-1

如上图的2-1,一个客户端向leader节点a发起事务请求set 5,leader节点收到请求后,会追加log entry到本地日志中,但不会立刻commit(更新节点状态)。

Raft 算法初识_第13张图片
图2-2

Leader节点会向集群中所有节点发起事务请求set 5,follower节点收到请求后,会追加log entry到本地日志中,然后向leader节点发送ack(图2-3中的红点)

Raft 算法初识_第14张图片
图2-3

Leader节点会一直等待follower的ack响应,直到有过半的ack后,leader会commit状态,把自己的状态变成5(图2-4中的节点a)

Raft 算法初识_第15张图片
图2-4

接着Leader节点会向集群中所有的follower节点发送commit请求(图2-5的红色请求),然后,follower接受到commit请求后,会更新自己的状态为5,并相应客户端。此时,系统中的集群就变成一致性状态了,这个处理流程称为日志复制。

Raft 算法初识_第16张图片
图2-5

特殊情况(网络分区),如图2-6所示:

集群网络健康时,节点B成为leader节点;可是,当集群运行一段时间后,网络出现了分区现象,节点B(leader)节点仅可以和节点A互相通讯;而节点C、D、E可以互相通讯,并且节点D变成了leader节点(因为获得了过半赞成),这时,一个集群内就会有两个leader节点(B、D)。

Raft 算法初识_第17张图片
图2-6

此时,有两个客户端c1 和c2,c1向master节点D发起事务请求,获得过半处理后,会响应c1成功;c2向master节点B发起事务请求,由于无法获得过半请求,B节点和A节点仅仅会记录c2的事务请求,但不会commit。

当网络恢复正常后,节点D可以和节点B、A通讯了,并且发现节点D的Term比自己高,那么会回滚刚刚记录c2的请求事务;并同步节点D最新的日志,同时更新自己的term。

动画请看:
http://thesecretlivesofdata.com/raft/

你可能感兴趣的:(Raft 算法初识)