1. 程式人生 > >分散式系統上下層概念抽象-(2)

分散式系統上下層概念抽象-(2)

前情回顧

在上一個部落格中已經討論了分散式系統的第一章節,主要涉及了分散式系統的基本概念,基本特性,設計目標,以及設計技巧。簡言之,由於分散式系統的兩個基本限制:資訊的有限速度傳播以及故障的獨立性,導致分散式系統在設計上為了達成可擴充套件性,高效能,高可用,低延遲,高容錯的道路上,要付出很多額外的代價。分散式系統設計問題可以抽象成通用的model來解決,從而能夠在系統設計之初就可以有更好的理解力以及對系統設計各項引數的洞察力。對於系統的資料管理,有兩種常見的技巧,資料劃分和副本機制,遍佈於各種各樣的分散式系統中,這兩個在提高系統的可用性以及效能方面發揮著其無與倫比的優勢,但是不可避免的也帶來了新的問題,例如多副本的資料一致性問題。欲瞭解更多詳情,歡迎戳它:

分散式系統基本概念-(1)

抽象

在本章,我們主要關注各層的抽象。如果你是一個程式設計人員,那麼你對抽象概念一定不陌生。程式設計裡面內部邏輯,通過包裝之後抽象成API給外部呼叫者,思考一下網路的OSI七層模型。我們知道越上層的抽象,越容易理解,它剝離了底層的實現細節。分散式系統這個概念本身就是抽象,它是由多個節點構成,但是我們卻想象它如一個單機系統一樣工作,這是最high-level的抽象,理解上雖然簡單,但卻忽略了很多細節。因此,我們需要一個好的系統抽象能夠在可理解性與細節表現之間進行權衡。

對於抽象一個系統,我們的目標是儘可能將系統中顯得不是那麼重要(essential)的部分從抽象中剝離出去,只留下分散式系統最本質的東東,但是什麼是它的本質,這本身又是另外一個問題。其次,在剝離系統的某一方面的時候,我們可能人為的引入一種錯誤風險,這可能又需要我們向更底層去看,來進一步瞭解真實世界,從而修正我們的抽象。不過不管怎麼樣,只要我們的抽象做到不忽略一些essential的部分,能夠涵蓋大部分的特性,那麼這種抽象一般是applicable,而且還是general。

系統模型

分散式系統的特徵

分散式系統的關鍵特徵就是分散式,也就是說

  1. 在多個節點獨立並行執行
  2. 節點之間的通過網路通訊,網路的連線狀態是不確定的,可能導致message loss
  3. 沒有共享記憶體或者叫shared lock(全域性共享鎖)

也就是說

  1. 每一個節點獨立執行程式;
  2. 每個節點的knowledge是local的,它所知道的global的state可能是過期的,也可能是錯誤的;
  3. 節點故障事件的發生以及恢復是獨立的;
  4. 訊息可能延遲,可能丟失(無法辨別是由於網路故障還是節點故障導致的丟失);
  5. 沒有全域性的同步時鐘(每個節點有自己的時鐘,但是它並不與全域性時鐘完全一致)。

上面說了那麼多條,總結起來就是知識是local的,網路是不可靠的,節點也是不可靠的。

什麼叫System Model

a set of assumptions about the environment and facilities on which a distributed system is
implemented

當我們說系統模型,我們強調的是關於一個系統下的環境等條件的假設,這些假設包括:

  1. 節點
  2. 網路鏈路
  3. 整個系統屬性,包括時鐘以及全域性序

一個可靠的系統意味著更弱的假設,需要更強的演算法來應對系統的各種環境。當然,我們也可以建立一個具有強假設的系統,例如假設系統中節點不會故障,那麼系統就不需要處理node failures,不過這樣的假設是不現實的,從而在這樣假設下的系統模型也就比較難應用到實際產品中。

讓我們來更具體的這些模型假設吧

  1. 節點假設
  • 執行程式的能力
  • 儲存資料到記憶體以及持久儲存資料到硬碟的能力
  • 時鐘,雖然可能並不精準

也就是說,一個節點是在本地執行確定的演算法,並能夠臨時或者持久儲存本地狀態。一個節點的local狀態,計算之後的local狀態以及要傳送的訊息只被local 狀態以及它所接收到的訊息唯一決定。說起來很繞,其實它是在說明這個節點自身不會幹壞事,它會按照給定的程式邏輯正確的確定的執行。

這裡我想簡單擴充套件的來說一下分散式系統的故障模型,具體請參考論文

  • byzantitne failures (拜占庭故障):這是網路中處理起來最困難的模型,在這種情況下,節點可以造假,可以不按照程式邏輯來執行,對它的呼叫操作可以返回正確的,錯誤的,不一致的各種結果。要解決拜占庭錯誤,需要同步網路以及叢集中的小於1/3的造假節點;

引用一段話:Lamport對拜占庭將軍問題的研究表明,當n>3m時,即叛徒的個數m小於將軍總數n的1/3時,通過口頭同步通訊(假設通訊是可靠的),可以構造同時滿足IC1和IC2的解決方案,即將軍們可以達成一致的命令。但如果通訊是可認證、防篡改偽造的(如採用PKI認證,訊息簽名等),則在任意多的叛徒(至少得有兩個忠誠將軍)的情況下都可以找到解決方案。

  • crash-recovery failures: 它相比於拜占庭加入了一層限制,要求節點必須按照程式邏輯正確的執行,不會瞎胡鬧。這其實就是對應於上面的“節點假設”,但是有一點是它不能保證訊息返回的時間,可能因為故障重啟,網路中斷以及非同步網路導致延遲很高。對於crash會分為兩種情況,一種是健忘(amnesia)和非健忘(omission),這其實對應於是否能夠持久化本地狀態,以恢復執行的能力。如果是非健忘的,那麼crash重啟之後,依然能夠恢復以前的狀態,繼續執行;
  • omission failures:相比於crash-recovery模型,增加了再一層限制,必須是非健忘的。也就是說,必須能夠在crash之後恢復上次的狀態;
  • crash-stop failures:也叫作crash failure或者fail-stop failure,從字面上理解,如果發生故障就直接stop。它要求發生故障(節點故障或者網路故障)之後就停止一切響應請求。
  1. 鏈路假設
  • 常見的分散式系統對鏈路有以下假設:任意兩點可達,訊息FIFO,傳送的訊息可能丟失;
  • 也有一些演算法假設鏈路是可靠,訊息從不丟失,延遲是有限的;
  • 網路分割槽故障是很特別的一種,節點OK,但是節點之間的鏈路斷了,不同分割槽內的server都能夠服務請求,可能導致不一致
  1. 時序假設
    節點本身的distribution使得每個節點按照自己的方式來執行,這是無法避免的。在對待時序的問題上,主要有兩種角度:
  • Synchronous system model (同步系統模型)
    網路傳輸時延有上界,精確的時鐘控制,程式以round的方式進行,執行的步調一致。傳送的訊息能夠確定在限制的上界內收到,如果不能收到,那麼一定是丟了,不會延遲到第二個round。這種模型不是真實世界的模型。
  • Asynchronous system model (非同步系統模型)
    程式執行時間不可預料,傳輸時延不可預料,時鐘漂移不可預料。在非同步網路中,判定異常原因是很困難的,例如訊息的丟失可能是由於網路時延,節點計算的慢,網路故障,節點故障等任何一個原因導致。這種模型更符合現實世界。

Consensus問題

Consensus問題是分散式系統的基本問題,描述的是多個節點針對某個value達成一致,有幾大要素:

  1. Agreement: 所有的正常節點都必須同意同一個value;
  2. Integrity:所有的節點最多隻認可一個value,而且如果一個value被認可,那麼這個value已經被propose過;
  3. Termination:所有的節點最終會達成決定,不會無限制下去;
  4. Validity:如果所有的節點都propose value V,那麼所有的節點都認可V。

關於這個方面的研究,有兩個最重要的結論:

  1. FLP不可能(需要更詳細的閱讀)
    FLP在學術上的影響力更大一些。它假定在非同步系統模型中,採用crash-recovery的故障模型,且網路是可靠的(不丟包),延遲無邊界,最多一個節點故障,那麼不存在一種確定性的演算法來解決consensus問題。FLP給非同步系統模型下的consensus問題的答案加了一個強約束:如果假定latency無上界,演算法設計者必須在safety和liveness做出權衡。
  2. CAP不可能
  • Consistency:所有節點在任何時刻看到都是相同的資料
  • Availability:對於外部的請求,系統一定能夠響應。
  • Partition Tolerance:網路分割槽故障或者節點系統依然可以對外提供服務

只有3箇中間的兩個可以同時滿足,如果只考慮兩個的話,對應三種系統設計,如下面的大餅圖聽說是:

  • CA(一致性和可用性):假定沒有分割槽故障,可以使用一種嚴格full quorum協議,必須寫全部成功才算成功,例如2PC兩階段提交協議;
  • CP(一致性和分割槽容錯):犧牲可用性,可以使用一種majority的quorum協議,例如Paxos;
  • AP(可用性和分割槽容錯):不要求強一致性,例如Dynamo使用了衝突解決的方案。

CA和CP都提供了強一致性的解決方案,不同點是CA系統不能容忍任何的節點錯誤,而CP系統能在2f+1個節點下最多容忍f個錯誤,也就是說需要多數派的節點,原因很簡單:

  • CA系統無法區分node failure和network failure(網路分割槽),如果出現了網路分割槽,那麼寫操作就可能發生在不同的分割槽從而導致資料分叉,發生不一致;
  • CP系統解決網路分割槽的方案是讓多數派主導寫操作,讓少數派的分割槽節點不可用,從而在確保資料一致的同時,還保證系統的部分可用(多數派所在的分割槽依然可用,但是少數派就不再可用了)。

總結來說CP系統將network partition融入到系統模型中,並且使用了多數派演算法(例如Paxos,raft,viewstamped Replication)來區分網路分割槽。早期的系統規模較小(例如關係型資料系統),不考慮網路分割槽(CA),以較小代價獲得高可用以及強一致。現代分散式系統規模更大,甚至於跨地區部署,網路分割槽成為常態,因此基本都把網路分割槽納入考慮範圍。如果要求系統強一致,那就必須犧牲一部分的可用性,因為如果讓兩個分割槽的伺服器都來服務客戶端請求,那麼資料分叉就無法避免。

現實情況下,我們一方面可以通過強化假設(例如假設沒有網路分割槽),另一方面通過弱化保證(例如弱一致性)來獲得較好的系統性能。強一致性與高效能不可兼得,為了確保強一致性,系統的nodes需要啟動consensus協議,通訊並對每個寫操作達成協議,帶來很大的系統延遲。強一致與高可用不可兼得,當資料經過跨區域的散佈,且中間的鏈路中斷,我們依然希望兩個分割槽都能對外提供服務,這意味著網路發生了分叉,當分叉在可控範圍的時候,我們傾向於容忍分叉,維持高可用。

關於safety和liveness

safety,例如同一時刻,只有一個程序能夠進入互斥臨界區

something bad will never happen

liveness:例如gossip協議具有最終一致性

something good will must happen (do not know when)

一致性模型

強一致性模型

  • 線性一致性
    系統的所有操作的執行順序遵循全域性時鐘的步調,完全像單機一樣。
  • 順序一致性
    所有的操作看起來像遵循一個時鐘,以原子的方式執行,但是這個時鐘不需要與全域性時鐘一致,只要所有的節點執行的步調一致即可。其實就是說,只要你能找到一種順序(不一定等於操作發生的絕對時間),滿足各個client和server的執行過程,那麼這就是順序一致的。
    在這裡插入圖片描述
    P1和P2代表兩個不同的程序與server的互動結果,試問上述兩種情形,能否滿足順序一致性?我們發現針對這兩種情況都可以找到滿足上述約束的執行順序,即:P1 x.write(2) -> P1 x.write(3) -> P2 x.write(5) -> P1 x.read(5),這表明其執行結果滿足順序一致性。請參見文章 一致性模型

如何區分呢?只有在確定知道每個操作的確切時間的情況下,才可以區分上述的兩種模型;如果僅關注客戶端與server的互動情況,上述兩種模型表現完全相同。

弱一致性模型

對於弱一致性模型,並沒有統一的定義,不強也就是弱。這就不得不提最終一致性。

最終一致性:if you stop changing values, then after some undefined amount of time all replicas will agree on the same value

也就是資料的不一致只會持續一個有限的時間,資料最終一定會一致,至於這個時間持續多久,並沒有保證,這其實就是前面說的liveness的保證,something good will must be happen!
關於最終一致性,有兩個關注點:

  1. 什麼時候到達最終? 系統多久趨向一致,需要有個嚴格的上界或者指導意義的上界。
  2. 如何達成一致?對於一個分散式檔案系統,請求任何檔案都返回File Not Found,也是一種最終一致性:所有的副本都agree同一個值,雖然是無意義的值。因此,系統設計者需要考慮最終到達的情形,例如只有latest udpate會被記為最終結果。

進一步的閱讀

這些論文往往才是精華,但精華往往是最難得到的。

  • Brewer’s Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant
    Web Services - Gilbert & Lynch, 2002
  • Impossibility of distributed consensus with one faulty process - Fischer, Lynch and
    Patterson, 1985
  • Perspectives on the CAP Theorem - Gilbert & Lynch, 2012
  • CAP Twelve Years Later: How the “Rules” Have Changed - Brewer, 2012
  • Uniform consensus is harder than consensus - Charron-Bost & Schiper, 2000
  • Replicated Data Consistency Explained Through Baseball - Terry, 2011
  • Life Beyond Distributed Transactions: an Apostate’s Opinion - Helland, 2007
  • If you have too much data, then ‘good enough’ is good enough - Helland, 2011
  • Building on Quicksand - Helland & Campbell, 2009