在上一篇文章http://www.reibang.com/p/b0cdaa64688e說到了如果follower長時間收不到leader的心跳酌毡,就會發(fā)起leader選舉循帐。具體的過程是怎么樣的呢碧查?
發(fā)起請求:
public static final String API_VOTE = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/vote";
其他節(jié)點收到選舉請求
收到請求的處理過程是:
如果對方的term比自己小,voteFor為自己版确,然后返回結果梢灭。意思是我自己更適合做leader,這一票我投給自己幕侠。
如果對方的term比自己大,設置voteFor為對方碍彭,然后返回結果晤硕,意思是就按你說的做,這一票就投給你了庇忌。
發(fā)起投票的節(jié)點收集到回應之后就開始處理了:
把所有的節(jié)點投票信息放到TreeBag舞箍,這個可以看成是個按value排序的有序map。排第一的就是得票最多的節(jié)點
public int majorityCount() {
return peers.size() / 2 + 1;
}
超過半數(shù)皆疹,表示選舉新的leader成功疏橄。
我們發(fā)現(xiàn)這的leader成功,并不會通知其他節(jié)點修改leader略就。最后是怎么變成一致的呢捎迫?
假如一個節(jié)點選舉自己成功,他會認為自己是leader表牢,就會定時發(fā)送心跳給其他的節(jié)點窄绒,這個時候其他節(jié)點的leader還是舊的,收到心跳會報錯的崔兴。
所以其他節(jié)點都經(jīng)歷一次選舉:
因為已經(jīng)選舉成功過彰导,所以local.voteFor都有值,為上一次選舉成功的節(jié)點敲茄,所以其他節(jié)點選舉的結果都會統(tǒng)一了位谋。
看起來是不是很簡單啊。堰燎。掏父。
但是這里有個關鍵邏輯就是term的比較,這個是決定了所有的邏輯的爽待。
每次發(fā)布新的內容的時候损同,term都會增加。而且follower的term也會增加鸟款,最終會同步為leader的term膏燃。
舉個例子
假如5個節(jié)點
節(jié)點1的term為4 為leader
節(jié)點2的term為4
節(jié)點3的term為4
節(jié)點4的term為3
節(jié)點5的term為3
節(jié)點1這個leader掛的情況下,
假如節(jié)點2開始選舉何什,它的term是最高的组哩,選舉自己是可以成功的。
同樣,節(jié)點3也是可以選舉成功的伶贰。這個就看節(jié)點2蛛砰,3誰先開始選舉了,誰先黍衙,誰就是新的leader泥畅。
假如節(jié)點2和節(jié)點3同時選舉呢,節(jié)點2得到自己和節(jié)點4的票琅翻,節(jié)點3得到自己和節(jié)點5的票位仁。這個時候兩邊都不能成功。所以等待下一輪方椎,因為下一次開始的時間是隨機的聂抢,所以同時的概率很小。誰先棠众,誰就是新的leader了琳疏。
假如所有的節(jié)點的term相同,其實是選舉不出leader的闸拿,因為都只有自己一票空盼。這個是怎么解決的呢?
每次發(fā)起投票的時候都會給自己的term加1 胸墙,是這里制造term的差異的:
收到投票請求的時候我注,如果對方的term比自己的大,為什么要放棄這一輪的發(fā)起選舉
local.resetLeaderDue();
這個是為了減少選舉沖突迟隅。對方比自己的term大1但骨,自己不放棄這一輪選舉的話,自己發(fā)起選舉智袭,term會加1奔缠,其實term就一樣大了,可能的結果就是兩個都選舉不成功吼野。
為什么每次發(fā)布新的內容校哎,term都會加100呢
local.term.addAndGet(PUBLISH_TERM_INCREASE_COUNT);
public static final int PUBLISH_TERM_INCREASE_COUNT = 100;
上面也看到了,每次發(fā)起投票都term都會加1瞳步,如果發(fā)布內容也是加一的話闷哆,內容落后的節(jié)點第二次發(fā)起投票的時候就是加2了,term居然高過內容最新的節(jié)點单起。這個時候就不對了抱怔。
100其實就是允許重新發(fā)起投票的次數(shù),這個數(shù)字越大越安全嘀倒,100這個數(shù)字已經(jīng)足夠大了屈留,100輪投票都產(chǎn)生不了leader局冰,這個概率可以忽略不計了。
問題1
假如一個節(jié)點只是和leader不通灌危,和其他節(jié)點都是通的康二。剛開始的時候,他的term其實是最新的勇蝙,所以它是可以成功選自己為leader的沫勿。
這個時候看起來就會有兩個leader,其他節(jié)點認為舊的leader是ok的味混,所以不會重新投票選舉藕帜。但是其他節(jié)點會受到這兩個leader的心跳,只是對于第二個心跳會報錯而已惜傲。。這種情況確實有點蛋疼贝攒,不過理論上很少發(fā)生這種情況的盗誊。
問題2
選舉發(fā)生沖突,都失敗的時候隘弊,等待下一輪選舉的時間是15~20秒哈踱,感覺這個時間等得太久了。
而且隨機的區(qū)間就是0-5000 ms梨熙,這個命中比較接近的數(shù)字還不小开镣,搞不好下一輪還沖突。那就一共等30多秒了咽扇。邪财。
public void resetLeaderDue() {
leaderDueMs = GlobalExecutor.LEADER_TIMEOUT_MS + RandomUtils.nextLong(0, GlobalExecutor.RAMDOM_MS);
}
public static final long LEADER_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(15L);
public static final long RAMDOM_MS = TimeUnit.SECONDS.toMillis(5L);