etcd套路(二)etcd核心之raft協議

huxiaobai_001發表於2020-08-23

因為etcd的核心原理在於raft協議,所以弄了這麼一篇博文解釋什麼是raft協議?
Raft協議,確實方便理解!主要分為三個部分:選主,日誌複製,安全性。

選主:

Raft協議是用於維護一組服務節點資料一致性的協議。這一組服務節點構成一個叢集,並且有一個主節點來對外提供服務。當叢集初始化,或者主節點掛掉後,面臨一個選主問題。叢集中每個節點,任意時刻處於Leader, Follower, Candidate這三個角色之一。選舉特點如下:

  • 當叢集初始化時候,每個節點都是Follower角色;

  • 叢集中存在至多1個有效的主節點,通過心跳與其他節點同步資料;

  • 當Follower在一定時間內沒有收到來自主節點的心跳,會將自己角色改變為Candidate,併發起一次選主投票;當收到包括自己在內超過半數節點贊成後,選舉成功;當收到票數不足半數選舉失敗,或者選舉超時。若本輪未選出主節點,將進行下一輪選舉(出現這種情況,是由於多個節點同時選舉,所有節點均為獲得過半選票)。

  • Candidate節點收到來自主節點的資訊後,會立即終止選舉過程,進入Follower角色。

    為了避免陷入選主失敗迴圈,每個節點未收到心跳發起選舉的時間是一定範圍內的隨機值,這樣能夠避免2個節點同時發起選主。

日誌複製

所謂日誌複製,是指主節點將每次操作形成日誌條目,並持久化到本地磁碟,然後通過網路IO傳送給其他節點。其他節點根據日誌的邏輯時鐘(TERM)和日誌編號(INDEX)來判斷是否將該日誌記錄持久化到本地。當主節點收到包括自己在內超過半數節點成功返回,那麼認為該日誌是可提交的(committed),並將日誌輸入到狀態機,將結果返回給客戶端。

這裡需要注意的是,每次選主都會形成一個唯一的TERM編號,相當於邏輯時鐘。每一條日誌都有全域性唯一的編號
主節點通過網路IO向其他節點追加日誌。若某節點收到日誌追加的訊息,首先判斷該日誌的TERM是否過期,以及該日誌條目的INDEX是否比當前以及提交的日誌的INDEX跟早。若已過期,或者比提交的日誌更早,那麼就拒絕追加,並返回該節點當前的已提交的日誌的編號。否則,將日誌追加,並返回成功。

當主節點收到其他節點關於日誌追加的回覆後,若發現有拒絕,則根據該節點返回的已提交日誌編號,發生其編號下一條日誌。

主節點像其他節點同步日誌,還作了擁塞控制。具體地說,主節點發現日誌複製的目標節點拒絕了某次日誌追加訊息,將進入日誌探測階段,一一條傳送日誌,直到目標節點接受日誌,然後進入快速複製階段,可進行批量日誌追加。

按照日誌複製的邏輯,我們可以看到,叢集中慢節點不影響整個叢集的效能。另外一個特點是,資料只從主節點複製到Follower節點,這樣大大簡化了邏輯流程。

安全性

截止此刻,選主以及日誌複製並不能保證節點間資料一致。試想,當一個某個節點掛掉了,一段時間後再次重啟,並當選為主節點。而在其掛掉這段時間內,叢集若有超過半數節點存活,叢集會正常工作,那麼會有日誌提交。這些提交的日誌無法傳遞給掛掉的節點。當掛掉的節點再次當選主節點,它將缺失部分已提交的日誌。在這樣場景下,按Raft協議,它將自己日誌複製給其他節點,會將叢集已經提交的日誌給覆蓋掉。

這顯然是不可接受的。

其他協議解決這個問題的辦法是,新當選的主節點會詢問其他節點,和自己資料對比,確定出叢集已提交資料,然後將缺失的資料同步過來。這個方案有明顯缺陷,增加了叢集恢復服務的時間(叢集在選舉階段不可服務),並且增加了協議的複雜度。

Raft解決的辦法是,在選主邏輯中,對能夠成為主的節點加以限制,確保選出的節點已定包含了叢集已經提交的所有日誌。如果新選出的主節點已經包含了叢集所有提交的日誌,那就不需要從和其他節點比對資料了。簡化了流程,縮短了叢集恢復服務的時間。

這裡存在一個問題,加以這樣限制之後,還能否選出主呢?答案是:只要仍然有超過半數節點存活,這樣的主一定能夠選出。因為已經提交的日誌必然被叢集中超過半數節點持久化,顯然前一個主節點提交的最後一條日誌也被叢集中大部分節點持久化。當主節點掛掉後,叢集中仍有大部分節點存活,那這存活的節點中一定存在一個節點包含了已經提交的日誌了。

至此,關於Raft協議的簡介就全部結束了

本作品採用《CC 協議》,轉載必須註明作者和本文連結
胡軍

相關文章