1. 程式人生 > >分散式系統的一致性原理

分散式系統的一致性原理

對於分散式系統,我們必須深刻理解和牢記一點:分散式系統的不可靠性。

“可靠性”是指系統可以無故障的持續執行,如果一個系統在執行中意外宕機或者無法正常使用,那麼他就是一個不可靠的系統,即使宕機和無法使用的時間很短。我們知道,分散式系統通常是由獨立的伺服器通過網路鬆散耦合組成的,而網路本質上是一個複雜的I/O系統,而通常情況下,I/O發生故障的概率和不可靠性遠遠高於主機的CPU和記憶體,加之網路裝置的引入,也增加了系統大面積癱瘓的可能性。總之,分散式系統中重要的理論和設計都是建立在“分散式系統不可靠”這一前提上的,因為系統不可靠,所以我們需要增加一些額外的複雜設計和功能,來確保由於分散式系統的不可靠導致系統不可用性的概率降到最低。“可用性”是一個計算指標,如果系統在每小時崩潰1ms,那麼他的可用性就超過了5個9,;如果一個系統從來不奔潰,但是每年要停機兩週,那麼他是高度可靠的,但是可用性只有96%;

理解了分散式系統的可靠性原理之後,接下來需要解釋一個東西–一致性原理。分散式叢集的一致性是分散式系統“無法繞開的一塊巨石”,很多重要的分散式系統都涉及一致性問題,而目前解決此問題的幾個一致性演算法也都非常的複雜。

分散式系統中一致性場景描述如下:

N個節點組成一個分散式叢集,要保證所有的節點可以執行相同的命令序列,並達到一致的狀態。即在每個節點都執行了相同的命令序列之後,每個節點的結果都是相同的。實際上,由於分散式系統的不可靠性,所以通常只要保證分散式叢集中一半以上(N/2 + 1)的節點正常並達到一致性即可滿足要求。

如下圖所示,是分散式叢集“一致性”演算法的一個典型案例,來自Kafka。

這裡寫圖片描述

當客戶端向Kafka叢集發起寫Message請求時,叢集的Leader首先會寫一份資料到本地,同時向多個Follower發起遠端寫入請求,而這個過程,可能會有意外情況導致某些Follower節點發生故障無法應答(Ack)。此時,按照“一致性”演算法,如果叢集中有超過一半以上的節點正常應答,則表示此次操作執行成功。上圖中包括Leader在內為兩個節點成功,所以Leader會提交(Commit)Message資料併成功返回給客戶端,否則不會提交資料,此次寫入請求失敗。

由於“一致性”演算法所描述的場景很有代表性,而且分散式系統中幾乎每個涉及資料持久化的系統都會面臨這一複雜問題,加上該演算法本身的複雜性與挑戰性,所以它一直是分散式領域的熱點研究課題之一。

在分散式叢集的每個節點中,我們所探討的一致性一般情況下指的是“最終一致性”。其實最終一致性是降低了標準的一致性,即以“資料一致性存在延遲時間”來換取資料讀寫的高效能。目前最終一致性基本成為越來越多的分散式系統所遵循的一個設計目標,對其場景的完整描述如下:

在分散式資料庫叢集中(讀寫分離的資料庫),假設資料B被更新,則後續對資料B的讀取操作得到的不一定是更新後的值,從資料B被更新到後續讀取到B的最新值會有一段延時,這段延時又叫做“不一致視窗(Inconsistency Window)”,不一致視窗的最大值可以根據以下因素確定:通訊延遲,系統負載、複製方案涉及的副本數量等。而最終一致性則保證不一致視窗的時間是有限的,最終所有的讀取操作都會返回B的最新值。而DNS就是使用最終一致性的成功例子。

參考:架構揭祕從分散式到微服務