1. 程式人生 > >分布式系統的煩惱------《Designing Data-Intensive Applications》讀書筆記11

分布式系統的煩惱------《Designing Data-Intensive Applications》讀書筆記11

而不是 例如 有一個 客戶端 每天 不可 解決 通信 由於

使用分布式系統與在單機系統中處理問題有很大的區別,分布式系統帶來了更大的處理能力和存儲容量之後,也帶來了很多新的"煩惱"。在這一篇之中,我們將看看分布式系統帶給我們新的挑戰。

1.故障

當我們在使用單機系統時,它通常以一種相當可預測的方式工作:要麽它正常工作,要麽不工作。

而當我們在使用分布式系統時,情況就不同了。在分布式系統中,系統的某些部分可能以某種不可預知的方式被破壞,即使系統的其他部分工作正常。這種故障通常是不確定的:如果你想做涉及多個節點和網絡的東西,可能甚至不知道某個消息是否成功,因為消息穿越網絡所需的時間也是不確定的。

這種故障的不確定性,使得分布式系統的變得復雜而脆弱。一個系統越大,它的組件就越有可能出現故障。在一個有成千上萬個節點的系統中,某些東西總是會出現故障。而錯誤處理策略僅僅是簡單的放棄的話,一個大系統可能會花費大量時間從故障中恢復,而不是做有用的工作。

所以我們需要分布式系統能夠容忍失敗的節點,並且仍然保持整體工作,將容錯機制建立到軟件中。換句話說,分布式系統需要從不可靠的組件中建立一個可靠的系統。

2.不可靠的網絡

分布式系統是一組由網絡連接的機器組成的。網絡是這些機器通信的唯一方式,每臺機器都有自己的內存和磁盤,一臺機器不能訪問另一臺機器的內存或磁盤。在網絡中,一個節點可以向另一個節點發送消息,但是網絡不能保證它何時到達或是否到達,所以網絡是不可靠的。

技術分享圖片
如上圖所示,如果發送的請求並沒有得到響應,則無法區分
(a)請求丟失
(b)遠程節點失效
(c)響應丟失。
處理這個問題的通常方法是超時:一段時間後,發送方放棄等待,並假定響應不會到達。但是,當超時發生時,遠程節點可能已經得到請求並進行了處理。

故障檢測

由於網絡的不確定性使得很難判斷一個節點是否工作。分布式系統當中常用的便是超時檢測的機制。如果超時檢測是檢測故障的方法,那麽超時應該是多長時間呢?不幸的是,沒有簡單的答案。

長的超時時間意味著需要等待一個節點被宣告死亡。短的超時時間會更快地檢測到故障,但是事實上節點並沒有停止工作(例如由於節點或網絡過載)時,會錯誤地檢測一個節點失效。如果節點實際上是活著的,在執行某些操作的時,工作另一個節點接管,則該操作可能最終執行兩次。而且當一個節點失效時,它的責任需要轉移到其他節點,這將額外的負載放到其他節點和網絡上。如果系統已經處於高負載之下,過早檢測節點失效會使問題變得更糟。特別是,它可能發生的是節點實際上沒有時效,但由於過載而響應緩慢,將其負載轉移到其他節點會導致級聯故障。

目前學界和業界的趨勢是:不使用常數配置的超時,而是系統可以連續測量的響應時間和響應時間的抖動,並自動調整超時時間根據所觀察到的響應時間動態分布。如Akka的超時器,Cassandra的動態檢測,TCP的超時重傳。

3.不可靠的時間

在分布式系統中,時間是一件棘手的事情,因為通信不是瞬時的:消息穿越網絡從一臺機器轉到另一臺機器需要時間。消息接收的時間總是比發送的時間晚,但由於網絡中的可變延遲,我們不知道以後會有多少延遲。很難確定多臺機器處理的邏輯與順序。

每臺機器都有自己的時鐘,通常是一個石英晶體振蕩器。這些設備並不完全準確,所以每臺機器都有自己的時間,它可能比其他機器稍快或慢一些。存在同步時鐘的網絡協議:最常用的機制是網絡時間協議(NTP),它允許計算機時鐘根據一組服務器報告的時間進行調整。服務器可以從更精確的時間源獲取時間。

時鐘:

UTC時間以1970年1月1日為開始,根據公歷,忽略閏秒,來計算當前時間。計算機時鐘通常與NTP同步,這意味著一臺機器的時間戳(理想情況下)意味著與另一臺機器上的時間戳相同。

單調的時間:

您可以在一個時間點檢查時鐘的值,然後再一次檢查時鐘。兩個值之間的差異告訴你這兩個檢查之間要花多少時間。在分布式系統中,通過一個單調的時鐘測量時間(如超時)通常是好的,因為它不承擔不同的節點的時鐘之間的同步的細微誤差。

事件的時間戳排序

跨多個節點的事件排序是一個令人頭疼的問題。例如,如果兩個客戶機向分布式數據庫寫入,誰首先到達?哪個是最近寫的? 如下圖所示:
技術分享圖片

寫x = 1的時間戳是42.004秒,但寫x = 2的時間戳42.003秒。當Node 2接收到這兩個事件時,它會錯誤地得出結論:x = 1是最新的值,忽略x=2的寫入。Client B的增量操作將會丟失。這種沖突解決策略被稱為最後寫者勝(LWW),會導致一個具有滯後時鐘的節點無法覆蓋以前用一個快速時鐘寫入的節點的值,直到節點之間的時鐘偏差消失。

所以對於有嚴格時序要求的系統,需要使用邏輯時鐘(比如:Lamport Clock,Lanport老爺子真的是分布式領域的上古神牛啊~~~),這是基於遞增計數器是一個來判斷事件的更叠順序。邏輯時鐘不測量每天的時間或經過的秒數,只有事件的相對順序,也就是判斷一個事件是否發生在另一個事件之前或之後。

4.不可靠的租約

在分布式系統之中,有時需要確保在存儲服務文件只能同時被一個客戶端訪問,因為如果多個客戶端試圖寫它,文件會被損壞。您需要通過在訪問文件之前從鎖服務獲得租約來實現分布式鎖。但是有時這個鎖並非有我們想象的可靠,如下圖所示:
技術分享圖片

如果持有租約的客戶端 1 因為GC等原因暫停太久,而它的租約到期了。另一個客戶端 2 可以獲取租約,並開始向文件寫入數據。當暫停的客戶端1返回時,它仍然認為自己擁有一個有效的租約,並且繼續寫入數據。於是造成了寫入沖突。

柵欄令牌

我們可以使用柵欄令牌的方式,讓不可靠的租約變的更加可靠,如下圖所示:

技術分享圖片

鎖服務器可以在每次授予租約時,返回一個令牌,它是一個在每次授予鎖時增加的數字ID。每次客戶端發出一個寫請求時,必須包含當前的租約令牌。而存儲服務會記錄寫入的租約令牌,成為一個柵欄,舊的令牌寫入將被存儲服務拒絕。

小結:

分布式系統最大的挑戰是我們需要在不可靠的組件與復雜的多節點交互之中建立起一個可靠的系統,所以也需要我們付出更多的努力。我這裏略過了拜占庭問題的講解,通常我們開發的數據系統認為是拜占庭安全的,節點是可以信任的。

分布式系統的煩惱------《Designing Data-Intensive Applications》讀書筆記11