最終一致性

在全球範圍構建可靠的分佈式系統,需要在一致性和可用性之間進行權衡。

 

最終一致性  Eventually Consistent

 

作者: Werner Vogels

Werner Vogels is vice president and chieftechnology officer at amazon.com, where he is responsible for driving thecompany’s technology vision of continuously enhancing innovation on behalf ofamazon’s customers at a global scale.

 

Amazon雲計算的基礎是一些基礎設施服務,比如Amazon的S3、SimpleDB、和EC2(彈性計算雲)來提供資源,構建互聯網範圍上的計算平臺以及大量豐富的應用。對這些基礎設施的要求是非常嚴格;它們需要在安全性、擴展性、可用性、性能,以及能耗方面獲得很高的分數,它們需要在滿足這些要求的同時不間斷的服務全球數百萬的用戶。

     藏在這些服務背後,是運行在全球範圍上的大規模分佈式系統。全球範圍帶來了新的挑戰,當一個系統需要處理數以萬億的請求時,平時很低概率的事件也必然會出現,必須在設計和構建系統的前期將其考慮進來。考慮到在世界範圍內運行這些系統,我們無處不在地使用複製技術來獲得一致的性能和高可用性。

    儘管複製讓我們接近了我們的目標,但它仍不能以一種透明的方式完美的實現他們;在若干環境下,服務的用戶將會面臨,在服務內部使用複製技術的不足。這個一點在系統提供的數據一致性類型方面就有所體現。特別是許多普遍的大規模分佈式系統在數據複製時提供最終一致性模型。在Amazon設計大規模系統時,我們使用了一系列與大規模數據複製相關的指導原則和抽象概念,集中在對高可用性和數據一致性之間進行權衡。這裏,我介紹一些相關背景,它們啓發我們設計了在全球範圍內可靠運行的分佈式系統。

    歷史的角度

    在理想的世界中,只有一個一致性模型:當一個更新發生,所有觀察者都能看到更新。在1970年代後期,第一次發現這個模型難以實現。關於這個話題最好的“period piece(歷史文章)”文章是“Notes on DistributedDatabases” by Bruce Lindsayet.它奠定了數據庫複製的基本原則,討論了實現一致性的許多技術。這些技術中的大部分試圖透明地實現分佈式,對於用戶,它展現爲一個系統而不是大量的協作系統。那個時期的許多系統都採用這種方法,寧可系統實現失敗,也不願破壞透明性。(批註:由此可見大師級永遠是少數,其他人都是沿着大師級人物給出的方向前進)

在1990年代中期,隨着更大規模的網絡系統出現,之前的實踐被重新審視。那時人們開始考慮,將可用性作爲系統最重要的屬性,但人們仍掙扎於什麼需要被犧牲。Eric Brewer, UC Berkeley的系統教授,同時是Inktomi的帶頭人,在2000年PODC會議上一個主題演講中將不同的權衡方面放在一起。他提出了CAP理論,對於一個數據共享系統:數據一致性、系統可用性、網絡分區容忍性,在任意時刻僅能同時滿足兩點。更加正式的描述在2002年的論文中可以被找到,由Seth Gilbert 和 Nancy Lynch撰寫。

一個系統如果不進行網絡分隔,通常採用事務協議,來同時獲得數據一致性和可用性,。客戶端和服務器通常處於相同環境下,在某些情況下他們作爲一個整體而失效,就這點而言客戶端不會觀察到分隔情況。在較大的分佈式系統中,網絡分隔是必然的;因此,一致性和可用性不可能同時被達到。這意味着有兩種選擇:放鬆一致性將使系統在分隔環境下獲得高可用性;優先考慮一致性,則在某些情況下系統不可用。

對於兩種選擇,客戶端開發人員明確知道系統提供的是那一種。如果系統強調一致性,開發人員則需要處理系統無法訪問的情況,比如寫請求。如果因爲系統不可用而無法寫入,開發人員需要處理被寫入的數據。如果系統強調可用性,它將接受寫入,但在某些情況下讀請求不能獲得最新寫入的結果。開發人員需要決定客戶端是否需要隨時都訪問最新的更新。有很多應用可以容忍輕微的髒數據,在這個模型下他們能很好的工作。

(思考:在構建大型系統時,對每一個子系統都將有很嚴格的響應時間、一致性等指標要求,不然大系統將無法構建。)

在這個原則下(CAP理論),事務系統的一致性屬性被定義爲ACID(atomicity, consistency, isolation, durability)是一種不同類型的一致性保證。在ACID中,一致性保證當一個事務完成時數據庫處於一致的狀態;例如,當從一個賬戶轉錢到另一個賬戶,兩個賬戶的總數是不變的。在基於ACID的系統中,通常由編寫事務的開發人員負責一致性,數據庫的完整性約束能輔助開發。

一致性—客戶端和服務器

有兩種方式看待一致性。一種是從開發者/客戶端的角度:他們是如何觀察數據更新的。另一種是從服務器端:更新是如何在系統中流動以及對於更新系統能提供什麼樣的保證。

客戶端觀察到的一致性指的是,何時以及如何能觀察到對存儲系統中數據對象所做的更新。下面的例子說明不同類型的一致性,進程A對一個數據對象進行了更新。

強一致性。當更新完成,後續所有訪問都將獲得更新值。

弱一致性。系統不能保證後續訪問都將獲得更新值。在更新返回前有許多條件需要被滿足。從收到更新到所有觀察者能看到更新的這段時間被稱爲不一致窗口

最終一致性。一種特殊的弱一致;存儲系統保證如果沒有新的更新提交,最終所有的訪問都將獲得最後的更新。如果沒有故障發生,不一致窗口的大小取決於通信延遲,系統負載,以及複製策略中涉及的副本數。最常見實現最終一致性的系統是DNS。對於name更新的傳播依賴,配置模式以及基於時間控制的緩存;最終,所有的節點將會看到更新。

最終一致性模型有很多變種需要重視。

因果一致性。如果進程A告訴進程B它更新了數據,接下來進程B的訪問將會獲得更新數據,進程B的寫操作也將取代原先的寫。進程C與進程A沒有因果關係,則遵循最終一致性原則。

Read-your-wirtes一致性。對於進程A這是一個很重要的模型,在更新了一個數據項後,進程A後續訪問到的都是更新後數據,絕不會看到舊值。這是因果模型的一個特例。

Session一致性。這是Read-your-writes模型的一個現實版本,當一個進程在一個上下文環境中訪問存儲系統。只要Session存在,系統將保證read-your-writes一致性。如果因爲某種故障讓Session中斷,一個新的Session將被創建,同時保證不能重疊Session.

單調讀取一致性。如果一個進程看到對象的一個特定值,那麼後續所有訪問將不會返回任何之前的值。

單調寫一致性。這種情況下,系統保證串行化來自同一個進程的寫操作。衆所周知,系統如果不能保證單調寫一致性,上層的程序將非常難以開發。

這些屬性是可以同時具備的。例如,可以通過保證單調讀和session-level一致性。從實際角度出發,這兩種一致性(單調讀和read-your-writes)在最終一致性系統中是最需要的。

從這些變種中你可以看到,還是有相當多的不同情境存在。它依賴於特定應用是否能處理這些後果。

最終一致性對於極端的分佈式環境下並不是深奧的特性。現代的RDBMs提供的主-備可靠性,通過同步和異步的複製技術實現。在同步模式下,複製更新是事務的一部分。在異步模式中,更新以一種延遲方式到達備份節點,通常通過日誌傳輸。在後者模型中,如果主節點在日誌傳送完成前失效,從遠程備份節點讀取到的將是舊的,不一致的數據。爲了支持更好的擴展讀性能,RDBMSs開始提供從備份中讀取的能力,這是一種提供最終一致性保證的經典方式,其中不一致窗口依賴於日誌傳送的週期。

在服務器端,我們需要深入的觀察更新是如何流經系統的,從而理解是什麼造成了模型的不同,使用系統的開發人員能體會到這一點。讓我們在開始前先創建一些定義:

N=存儲副本數據的節點數。

W=需要接收更新的節點數,在完成更新前。

(註釋:更新完成指將更新寫入N個節點,但系統可以在寫入W個節點後就返回更新完成,剩餘N-W個節點在後續進行同步。)

R=讀操作獲取數據時需要連接的副本數。

(註釋: 讀取數據時從R個節點同時讀取,經過合併去除掉不合理數據再返回給用戶。)

如果W+R>N,寫操作和讀操作請求節點集會存在重疊,從而保證強一致性。在主-備的RDBMS場景中,採用同步複製,N=2,W=2,R=1。無論客戶端從哪一個副本讀取,它總能獲得一致的結果。在異步複製模式下,允許客戶端從備份節點讀取,N=2,W=1,R=1。這時R+W=N,一致性不能獲得保障。

W、R、N的配置是法定人數協議的基礎。當因故障造成系統無法寫入到W個節點時,寫操作失敗,系統不可用。在N=3,W=3而只有兩個節點可用時,那麼系統將寫失敗。提供高性能、高可用性的分佈式存儲系統,通常節點數大於2個。系統如果關注的重點是容錯通常設置N=3(W=2以及R=2)。系統爲了滿足更高的讀取負載,通常保存數據副本的節點數會超過容錯需要的節點數;N可能是幾十甚至幾百個節點,R設置爲1,這樣讀取到一個節點就會返回結果。系統如果關注一致性將會把更新節點數W設置爲N,這可能會降低寫成功的可能性。一個關心容錯而不是一致性的系統通常設置W爲1,獲得最小的持久化開銷,然後依靠週期寫入技術來更新其它節點。

如何配置N,W和R取決於常見的應用是什麼,以及什麼路徑需要優化。R=1,N=W爲讀應用進行優化,W=1,R=N爲了更快的寫進行優化。當然在後一種情況下,當故障發生時持久化不能保證,如果W<(N+1)/2,因爲寫操作未重疊,可能會出現衝突寫。

(註釋:如果W<(N+1)/2,兩個客戶端的寫請求集合就有可能不重疊,如果兩個客戶端修改同一個對象,每個客戶端的修改都是有效的,但系統中保存的結果卻是衝突的。)

弱/最終一致性在W+R<=N時就會採用,這意味着讀集合與寫集合沒有重疊。如果不是專門配置或基於失敗案例,這裏並沒有特別的意義將R設置爲1以外的值。W+R<=N通常發生在兩種十分常見的場景:前面提到的爲了獲得讀請求的伸縮性進行大規模複製;以及對於數據訪問非常複雜的情況。在簡單的Key-value模型中,通過比較版本來決定寫入系統的最後更新非常容易,但對於返回對象集合的系統很難決定最新的集合應該是什麼。這大多數這樣的系統,寫集合通常小於副本節點,然後以惰性方式將更新應用到其他副本節點。所有副本節點獲得更新的週期就是前面提到的不一致窗口。如果W+R<=N,系統從節點讀取數據是脆弱的,因爲節點可能還沒有收到更新。

是否是read-your-write, session, 以及單調一致,取決於客戶端對於服務器的“粘性”,以及他們之間執行的分佈式協議。如果每次訪問同一個服務器,相對來講比較容易獲得read-your-writes和單調讀一致性。這使得負載均衡和容錯稍微難以管理,但這是一個簡單的方案。使用session,具有一定粘性,讓一致性非常明顯,提供了一個清晰的一致性級別,客戶端可進行推理。

有時客戶端實現了read-your-writes和單調讀一致性。通過增加寫入時版本信息,客戶端可以丟棄先於最近可見版本的讀取值。

分區發生指,系統中一些節點無法連接其它節點,同時這兩部分節點都可以被客戶端訪問。如果你用經典的多數法定人方法,有W副本節點的分區可以繼續進行更新,而其他分佈則不可用。這對於讀集合一樣。考慮讀寫集合的重疊,定義W,R時需要避免最小的不可用集合。分區並不頻繁發生,但確實發生數據中心之間、以及數據中心內部。

在一些應用中,任何一個分區的不可用都是不可接受的,對於需要訪問分區來獲得進展的客戶端來說非常重要。這種情況下,兩邊分配一組新的存儲節點來接收數據,分區癒合時執行合併操作。例如,在Amazon的購物車中,用戶使用一個write-always系統;當分區發生時,客戶能繼續將物品放入購物車中,即使原來的購物車在其它分區。一旦分區癒合,購物車應用將合併購物車。

Amazon’s Dynamo

考慮了所有這些屬性,並在一個應用架構下可顯示控制這些屬性的系統是Amazon的Dynamo,一個key-value存儲系統,在構成Amazon電子商務平臺服務的內部使用,同時也作爲Amazon的一個Web服務。Dynamo的設計目標之一就是,讓在Dynamo(通常會跨多個數據中心)上創建存儲實例的應用服務擁有者,能在一個合理的成本點上獲得一致性、持久化、可用性以及性能的一個平衡。

總結

在大規模可靠地分佈式系統中,出於兩個原因數據不一致必須被接收:在高併發環境下優化讀寫性能;儘管節點啓動並在運行,但分區問題仍是一個主要的模型,對系統不可用負有一定的責任。不一致性是否能被接收依賴於客戶端的應用。在任何情況下,開發人員必須清楚存儲系統提供的一致性保證,在開發應用時必須將一致性考慮進來。

這有大量方法來改善最終一致性模型,比如session級的一致性和單調讀,這對於開發人員來說提供了更好的工具。很多時候,應用使用提供最終一致性的存儲系統沒有任何問題。在web應用中有一個非常流行的例子,我們都知道用戶可接受的一致性。在這個場景下,不一致窗口一定要小於用戶對返回下一個頁面的期望時間。這是下一次讀請求前,更新傳播到整個系統的時間。

本文的目標是提高對工程系統複雜性的認識。這樣的系統需要在全球範圍運行,需要仔細的調優來保證他們能提供上層應用需要的持久化、可用性、以及性能。系統設計人員可用的一個工具是不一致窗口的長度,在這個過程中,系統的客戶端可能被暴露給真實的大系統工程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章