最近一年左右在研究系統架構和分散式系統,今天跟大家一起分享討論。文章簡單分享幾種分散式系統的一致性演演算法,常見的有 Paxos、Raft、ZAB。
首先簡單說一下分散式系統。這是一個比較寬泛的概念。他的產生和出現是為了應對和解決以往系統的問題。
我的簡單理解是一套互相連線共同向外提供服務的系統,系統內部節點間透過某種方式進行通訊。常見的大的如電商網站,小的如一個資料庫叢集,快取叢集等。
在分散式系統出現之前使用的單機系統,一旦伺服器的作業系統、硬碟、網路等出現問題,就可能會出現服務中斷,資料丟失等問題。 另外,單機的效能再高,儲存能力再擴充套件,也是有限的,而分散式系統可以包含大量的伺服器用來分散頻寬、儲存和計算壓力。 第三,由於跨較遠區域甚至跨國的網路延遲有時還是客觀的,所以伺服器集中在一個地方很難向較大範圍提供較好的服務和體驗。
同時由於不完美的執行環境,他本身需要解決一些問題。
如:系統中使用的每個節點都可能出現單點故障突然不工作了,節點間會有或大或小、忽大忽小的網路延遲,節點間的網路也有可能出問題。 從技術角度看,可能發生的問題基本上認為早晚會發生。說到底很多問題就是機率和成本收益的平衡。 因此,一個分散式系統要正常提供對外的服務,它的設計本身就要考慮到這些問題的解決。 在演演算法層面就是由分散式系統的一致性演演算法來輔助解決和應對這些問題,確保系統盡可能的對外正常的提供服務。
這裡說盡可能的意思是分散式系統不能確保永遠完全沒有問題,尤其是一些極端情況。 比如一個3個節點的資料庫叢集,單節點掛掉的機率較小,3個節點同時掛掉的機率極小極小,不過也存在這種可能,不過機率很小,一般不考慮。 或者機房停電,光纜被挖段,如果幾個節點都在一個機房,那就不能工作了。 今天講的一致性演演算法主要解決的是從系統的角度分析一個分散式系統內部節點本身和節點間出現問題的解決。 跟這些外部問題關聯較小,那些場景要同時藉助其他手段來緩解和解決。
比較容易理解的常見的實際問題: 一個系統包含5個節點,由於網路原因其中3個節點和另2個節點失去了聯絡,這時候系統應該怎麼處理,是否還可以繼續提供服務。
如果繼續提供服務,他們之間的資料就是不一致的,後面節點間的網路恢復後,怎麼解決資料不一致的問題。
節點間的網路延遲、磁碟讀寫、CPU處理能力不同,儲存到這個系統中的資料在哪些情況下可以認為儲存成功了,還要以一種效率較高的方式來實現。
把節點分兩種,Leader(主)和Follower(從)。 有一個主節點,所有寫操作全部透過節點進行處理,如果一個從節點收到了一個寫操作請求,就會轉給主節點處理。 其他節點都是從節點,可以透過從節點進行讀操作。 主節點透過選舉得出,主節點失蹤後,其他從節點自動開始選舉新的主節點。
註意, 這裡寫操作可以認為是儲存或修改現有資料。讀操作可以認為是讀一個現存的資料出來。讀操作相對簡單一些,這裡主要講寫操作, 其流程為:
-
客戶向主節點請求寫資料X;
-
主節點為該資料生成一個唯一的遞增Id,叫ZXIDX(Id);
-
主節點把X(Id)發給所有的從節點,跟他們確認能不能正常把資料記錄下來,這個操作叫 Propose 提議;
-
超過一半的節點向主節點回覆沒問題,這個回覆操作叫 ACK 應答;
-
節點收到一半以上從節點的肯定答覆後,給所有的從節點傳送確認提交請求,表示你們可以把這個資料儲存下來了,同時自己也正式儲存這個資料,這個過程叫 Commit 提交。
現在問題來了,如果沒有超過一半的從節點給主節點回覆ACK。那麼主節點就不能確認該訊息可以成功記錄下來。 為啥一定要收到超過一半的從節點的答覆?答案是為了確保資料的一致性。 一般分散式一致性演演算法可以確保在部分節點掛掉的情況下保持資料的一致性,在大部分節點都同時掛掉的情況不能確保。比如:一共5個節點,2個掛掉沒問題,其中可以包括主節點,如果3個掛掉了,就不能確保了。 一般出現這種情況時,比如5個節點只剩了2個,這兩個節點就不再提供服務了。
比如一個銀行的存款系統:3個節點在上海,2個節點在廣州。一個賬號Adun,有1K的錢在裡面。5個節點都包含這個資料。 這時上海廣州之間的網路掛了。我連到上海的節點把錢轉給一個人,然後連到廣州的節點把裡面的1K錢轉給另一個人。 他們之間是斷開的,如果同時提供轉賬服務,就出現了資料一致性的問題。 而如果只有3個節點的上海提供服務就沒有這個問題了。 另一個問題是,他們之間的網路恢復後,以誰的資料為準呢?所以大部分的分散式一致性演演算法都是採用大多數認同的方式。 當然,在寫資料的時候如果強制確認所有節點都寫入了新資料會更安全和一致,但是系統的可用性和效能就大大降低了,只要有一個節點掛了,系統就不工作了。
我們分析下子節點掛掉的情況。 先看節點掛掉數佔比情況分析: 少於一半的子節點掛掉沒有任何影響。達到一半的子節點掛掉系統不能提供服務,一般這種情況機率很小。
一個子節點掛掉一段時間後又恢復了之後, 先透過主節點同步新的資料,因為自己掛了一段時間,很可能沒有最新的資料。資料同步之後正式成為工作的子節點開始工作。 新增一個新的子節點到一個現有的叢集,也是這個過程。
如果是主節點掛掉,情況會複雜一點。 主節點掛掉後,叢集暫時不提供寫服務,開始新的主節點選舉。選舉規則如下:
-
發訊息到每一個自己還能連上的節點:包含自己的節點編號叫 myid 和 自己儲存的資料的最大的 ZXID。
-
誰的ZXID最大,誰就是新的主節點。為什麼吶?因為這表示他的資料最新。儘量確保資料一致性。
-
ZXID相同的時候,誰的myid最大誰是新的主節點;
-
收到其他節點的資料後,跟自己的判斷,如果對方比自己的大,就認同對方為主節點;
-
得到一半以上(註意這裡又是一半以上),節點認同的候選的節點成為新的主節點。
新的主節點選舉出來之後,進入叢集的資料同步節點,先檢查叢集內部哪些節點的資料比自己舊,把資料同步過去。 然後開始向外部提供服務。 在新的主節點選出來之前,叢集不能提供寫服務。 這裡的步驟有好幾步,在正常的伺服器環境下,這個過程是很快的,幾十到幾百毫秒。
回到剛才的上海和廣州的場景。 廣州的發現上海的節點失蹤了,這時候開始選舉新的主節點,但是它們只有2個節點,選不出來主節點,也不提供服務。上海的繼續服務。網路恢復後,把資料同步到廣州節點然後繼續工作。
這是 ZAB 協議的主要資訊。還有很多細節,感興趣的話可以去看看。不過一般分散式系統的一致性演演算法都有點複雜。ZAB是為了支撐ZooKeeper服務設計出來的,ZooKeeper是給其他服務提供叢集管理服務的,所以他本身要足夠健壯。ZAB協議的全稱就是Zookeeper Atomic Broadcast,即 ZooKeeper原子性廣播協議。
下麵再簡單介紹幾句Raft演演算法。 Raft演演算法很多地方跟ZAB很像,也分主節點和從節點,主節點選舉的地方有一點差別。
-
發現主節點失蹤一段時間後,所有從節點向其他從節點發訊息,讓他們選自己為新的主節點;
-
還沒參加選舉的節點如果收到其他節點的選舉請求,就選舉自己收到的第一個節點,後面誰再請求自己支援選舉,就告訴他們我已經支援另一個節點了;
-
如果一個節點發現另一個節點得到的支援比自己多,也就開始無條件支援那個節點選舉,同時讓支援自己的節點也去支援它
-
如果一輪沒選出來得到大多數節點支援的主節點,就開始下一輪選舉,直到一個節點得到了大部分節點支援,成為新的主節點。
還有一個叫Paxos的一致性演演算法,更複雜,慚愧我目前還不敢確保完全理解,Paxos演演算法還衍生出來好幾種變體,經典的Paxos演演算法不分主節點和從節點。
其實現在大部分的一致性演演算法都是起源於或參考了Paxos演演算法,有人說只有Paxos才是真正的一致性演演算法。
A:一般分散式一致性演演算法可以確保在部分節點掛掉的情況下保持資料的一致性,在大部分節點都同時掛掉的情況不能確保。比如一共5個節點,2個掛掉沒問題,其中可以包括主節點,如果3個掛掉了,就不能確保了。一般出現這種情況時,比如5個節點只剩了2個,這兩個節點就不再提供服務了。
Q:在主節點失去心跳到選舉新的主節點作為寫入,這期間的資料怎麼保證最終一致?那還是這個問題。
A:主節點失聯的時候不能寫資料。如果此時主節點上有沒有提交的資料它就掛了,那麼客戶端就不能得到這個訊息成功寫入的響應。因此係統本身的資料是一致的。主節點上沒提交的資料在從節點上也是未提交,因此沒提交資料的ZXID不算數。嚴格的講這段時間系統是不可寫的。
A:這個要看具體情況了,跟伺服器,網路,機房環境,系統本身開發的怎麼樣,壓力這些都有關係;節點掛掉才會進行選舉,不過具有主節點的系統,主節點的壓力也會比較大,協議的具體實現互相差別也很大,涉及到開發細節的話還有很多引數要考慮,比如心跳間隔,節點數量等。
Kubernetes應用實戰培訓將於2018年10月12日在深圳開課,3天時間帶你係統學習Kubernetes。本次培訓包括:容器基礎、Docker基礎、Docker進階、Kubernetes架構及部署、Kubernetes常用物件、Kubernetes網路、儲存、服務發現、Kubernetes的排程和服務質量保證、監控和日誌、Helm、專案實踐等,點選下方圖片檢視詳情。
長按二維碼向我轉賬
您的支援是我們持續發展的動力
受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。
微信掃一掃
使用小程式