區塊鏈快速入門(二)——分布式系統核心技術
一、分布式系統的一致性問題
1、分布式系統的一致性問題
隨著摩爾定律碰到瓶頸,越來越多情況下要依靠可擴展的分布式架構來實現海量處理能力。單點結構演變到分布式結構,首要解決的問題就是數據的一致性。如果分布式集群中多個節點不能保證處理結果的一致性,建立在其上的業務系統將無法正常工作。區塊鏈系統是一個典型的分布式系統,在設計上必然也要考慮一致性問題。
在面向大規模復雜任務場景時,單點的服務往往難以解決可擴展(Scalability)和容錯(Fault-tolerance)兩方面的需求,就需要多臺服務器來組成集群系統,虛擬為更加強大和穩定的“超級服務器”。
集群的規模越大,處理能力越強,管理的復雜度也就越高。目前在運行的大規模集群包括谷歌公司的搜索系統,通過數十萬臺服務器支持了對整個互聯網內容的搜索服務。
一致性(Consistency)在分布式系統領域中是指對於多個服務節點,給定一系列操作,在約定協議的保障下使得多個節點對處理結果達成某種程度的協同。
理想情況(不考慮節點故障)下,如果各個服務節點嚴格遵循相同的處理協議(即構成相同的狀態機邏輯),則在給定相同的初始狀態和輸入序列時,可以確保處理過程中的每個步驟的執行結果都相同。因此,傳統分布式系統中討論一致性,通常是指在外部任意發起請求(如向多個節點發送不同請求)的情況下,確保系統內大部分節點實際處理請求序列的一致,即對請求進行全局排序。
一致性關註的是系統呈現的狀態,並不關註結果是否正確;例如,所有節點都對某請求達成否定狀態也是一種一致性。
2、分布式系統的挑戰
典型的分布式系統中存在如下挑戰:
A、節點之間只能通過消息來交互和同步,而網絡通訊是不可靠的,可能出現任意消息延遲、亂序和錯誤。
B、節點處理請求的時間無法保障,處理的結果可能是錯誤的,甚至節點自身隨時可能發生故障。
C、為了避免沖突,采用同步調用可以簡化設計,但會嚴重降低系統的可擴展性,甚至使其退化為單點系統。
3、分布式系統一致性的要求
分布式系統達成一致的過程應該滿足如下要求:
A、可終止性(Termination)
一致的結果在有限時間內能完成。
B、約同性(Agreement)
不同節點最終完成決策的結果是相同的。為了確保協同性,分布式系統通常會把不同時空發生的多個事件進行全局唯一排序,並且順序必須是所有節點認可的。
決策的結果必須是某個節點提出的提案。
4、分布式系統帶約束的一致性
要實現絕對理想的嚴格一致性(Strict Consistency)代價很大。除非系統不發生任何故障,並且所有節點之間的通信無需任何時間,此時整個系統其實就等價於單點系統。實際上,越強的一致性要求往往意味著帶來越弱的處理性能,以及越差的可擴展性。根據實際需求的不用,可以選擇不同強度的一致性,包括強一致性(Strong Consistency)和弱一致性(Weak Consistency)。
強一致性包括兩類:
A、順序一致性
順序一致性(Sequential Consistency):Leslie Lamport1979年經典論文《How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs》中提出,是一種比較強的約束,保證所有進程看到的全局執行順序(total order)一致,並且每個進程看自身的執行順序(local order)跟實際發生順序一致。例如,某進程先執行A,後執行 B,則實際得到的全局結果中就應該為A在B前面,而不能反過來。同時所有其它進程在全局上也應該看到這個順序。順序一致性實際上限制了各進程內指令的偏序關系,但不在進程間按照物理時間進行全局排序。
B、線性一致性
線性一致性(Linearizability Consistency):Maurice P. Herlihy與Jeannette M.Wing在1990年經典論文《Linearizability: A Correctness Condition for Concurrent Objects》中共同提出,在順序一致性前提下加強了進程間的操作排序,形成唯一的全局順序(系統等價於是順序執行,所有進程看到的所有操作的序列順序都一致,並且跟實際發生順序一致),是很強的原子性保證。但比較難實現,目前基本上要麽依賴於全局的時鐘或鎖,要麽通過一些復雜算法實現,性能通常不高。
實現強一致性往往需要準確的計時設備。高精度的石英鐘的漂移率為10^-7,最準確的原子震蕩時鐘的漂移率為10^-13。Google曾在其分布式數據庫Spanner 中采用基於原子時鐘和GPS的TrueTime方案,能夠將不同數據中心的時間偏差控制在10ms以內。在不考慮成本的前提下,TrueTime方案簡單、粗暴,但有效。
強一致的系統往往比較難實現,而且很多場景下對一致性的需求並沒有那麽強。因此,可以適當放寬對一致性的要求,降低系統實現的難度。例如在一定約束下實現所謂最終一致性(Eventual Consistency),即總會存在一個時刻(而不是立刻),讓系統達到一致的狀態。
例如電商購物時將某物品放入購物車,但可能在最終付款時才提示物品已經售罄。實際上,大部分的Web 系統為了保持服務的穩定,實現的都是最終一致性。
弱一致性相對於強一致性,是在某些方面弱化的一致性,如最終一致性。
二、分布式共識算法簡介
1、分布式共識簡介
共識(Consensus)通常會與一致性(Consistency)術語放在一起討論。嚴謹地講,兩者的含義並不完全相同。
一致性的含義比共識寬泛,在不同場景(基於事務的數據庫、分布式系統等)下意義不同。具體到分布式系統場景下,一致性指的是多個副本對外呈現的狀態。如順序一致性、線性一致性,描述了多節點對數據狀態的共同維護能力。而共識,則特指在分布式系統中多個節點之間對某個事情(例如多個事務請求的執行順序)達成一致看法的過程。因此,達成某種共識並不意味著就保障了一致性。
實踐中,要保障系統滿足不同程度的一致性,往往需要通過共識算法來達成。
共識算法解決的是分布式系統中大部分節點對某個提案(Proposal)達成一致意見的過程。提案的含義在分布式系統中十分寬泛,如多個事件發生的順序、某個鍵對應的值等等。任何可以達成一致的信息都是一個提案。對於分布式系統,各個節點通常都是相同的確定性狀態機模型(又稱為狀態機復制問題,State-Machine Replication),從相同初始狀態開始接收相同順序的指令,則可以保證相同的結果狀態。因此,分布式系統中多個節點達成共識的關鍵是對多個事件的順序進行共識,即排序。
2、分布式共識的挑戰
分布式系統達成共識都要解決兩個基本的問題:
A、如何提出一個待共識的提案,如通過令牌傳遞、隨機選取、權重比較、求解難題等。
B、如何讓多個節點對提案達成共識(同意或拒絕),如投票、規則驗證等。
在實際應用的分布式系統中,不同節點之間通信存在延遲(光速物理限制、通信處理延遲),並且任意環節都可能存在故障(系統規模越大,發生故障可能性越高)。如通信網絡會發生中斷、節點會發生故障、甚至存在被***的節點故意偽造消息,破壞正常的共識過程。
通常,把出現故障(Crash或Fail-stop,即不響應)但不會偽造信息的情況稱為“非拜占庭錯誤(Non-Byzantine Fault)”或“故障錯誤(Crash Fault)”;偽造信息惡意響應的情況稱為“拜占庭錯誤”(Byzantine Fault),對應節點為拜占庭節點。拜占庭錯誤場景中因為存在搗亂者更難達成共識。
3、常見分布式共識算法
根據解決的場景是否允許拜占庭錯誤情況,共識算法可以分為CFT(CrashFault Tolerance)和BFT(Byzantine Fault Tolerance)兩類。
對於非拜占庭錯誤的情況,經典的共識算法包括Paxos(1990年)、Raft(2014年)及其變種等。CFT類容錯算法通常性能比較好,處理較快,容忍不超過一半的故障節點。
對於要能容忍拜占庭錯誤的情況,包括PBFT(Practical Byzantine Fault Tolerance,1999年)為代表的確定性系列算法、PoW(1997年)為代表的概率算法等。確定性算法一旦達成共識就不可逆轉,即共識是最終結果;而概率類算法的共識結果則是臨時的,隨著時間推移或某種強化,共識結果被推翻的概率越來越小,最終成為事實上結果。拜占庭類容錯算法通常性能較差,容忍不超過1/3的故障節點。
此外,XFT(Cross Fault Tolerance,2015年)等最近提出的改進算法可以提供類似CFT的處理響應速度,並能在大多數節點正常工作時提供BFT保障。
Algorand算法(2017年)基於PBFT進行改進,通過引入可驗證隨機函數解決了提案選擇的問題,理論上可以在容忍拜占庭錯誤的前提下實現更好的性能(1000+TPS)。
實踐中,通常客戶端要拿到共識結果需要自行驗證,典型地,可以訪問足夠多個服務節點來比對結果,確保獲取結果的準確性。
三、FLP不可能原理
1、FLP原理簡介
FLP不可能原理:在網絡可靠,但允許節點失效(即便只有一個)的最小化異步模型系統中,不存在一個可以解決一致性問題的確定性共識算法。
FLP不可能原理在1985年由Fischer,Lynch和Patterson三位科學家在《Impossibility of Distributed Consensus with One Faulty Process》論文中提出並證明。
FLP不可能原理表明,不要浪費時間,去試圖為異步分布式系統設計面向任意場景的共識算法。
2、分布式系統的同步與異步
分布式系統中同步和異步的定義如下:
同步是指系統中的各個節點的時鐘誤差存在上限,並且消息傳遞必須在一定時間內完成,否則認為失敗;同時各個節點完成處理消息的時間是一定的。因此同步系統中可以很容易地判斷消息是否丟失。
異步是指系統中各個節點可能存在較大的時鐘差異,同時消息傳輸時間是任意長的;各節點對消息進行處理的時間也可能是任意長的。因此,無法判斷某個消息遲遲沒有被響應的原因(節點故障或傳輸故障)。
現實生活中的分布式系統通常都是異步系統。
3、FLP原理的意義
FLP不可能原理實際上說明對於允許節點失效情況下,純粹異步系統無法確保共識在有限時間內完成。即便對於非拜占庭錯誤的前提下,包括Paxos、Raft等算法也都存在無法達成共識的極端情況,只是在工程實踐中出現的概率很小。
FLP不可能原理並不意味著研究共識算法沒有意義。學術研究通常考慮地是數學和物理意義上理想化的情形,很多時候現實世界要穩定得多;工程實現上某次共識失敗,再嘗試幾次,很大可能就成功。
四、CAP原理
1、CAP原理簡介
CAP原理最早出現在2000年,由加州大學伯克利分校的Eric Brewer教授在ACM組織的Principles of Distributed Computing(PODC)研討會上提出猜想,後來麻省理工學院的Nancy Lynch等學者進行了理論證明。
CAP原理被認為是分布式系統領域的重要原理之一,深刻影響了分布式計算與系統設計的發展。
CAP原理:分布式系統無法同時確保一致性(Consistency)、可用性(Availability)和分區容忍性(Partition),設計中往往需要弱化對某個特性的需求。
一致性(Consistency):任何事務應該都是原子的,所有副本上的狀態都是事務成功提交後的結果,並保持強一致。
可用性(Availability):系統(非失敗節點)能在有限時間內完成對操作請求的應答。
分區容忍性(Partition):系統中的網絡可能發生分區故障(成為多個子網,甚至出現節點上線和下線),即節點之間的通信無法保障。而網絡故障不應該影響到系統正常服務。
CAP原理認為,分布式系統最多只能保證三項特性中的兩項特性。當網絡可能出現分區時,系統是無法同時保證一致性和可用性的。要麽,節點收到請求後因為沒有得到其它節點的確認而不應答(犧牲可用性),要麽節點只能應答非一致的結果(犧牲一致性)。
由於大部分時候網絡被認為是可靠的,因此系統可以提供一致可靠的服務;當網絡不可靠時,系統要麽犧牲掉一致性(多數場景下),要麽犧牲掉可用性。
網絡分區是可能存在的,出現分區情況後很可能會導致發生腦裂,多個新出現的主節點可能會嘗試關閉其它主節點。
2、CAP原理應用場景
CAP三種特性不可同時得到保障,因此設計系統時候必然要弱化對某個特性的支持。根據CAP原理可以定義三種應用場景:
A、弱化一致性
對結果一致性不敏感的應用,可以允許在新版本上線後過一段時間才最終更新成功,期間不保證一致性。例如網站靜態頁面內容、實時性較弱的查詢類數據庫等,簡單分布式同步協議如Gossip,以及CouchDB、Cassandra數據庫等都弱化了一致性。
B、弱化可用性
對結果一致性很敏感的應用,例如銀行取款機,當系統故障時候會拒絕服務。MongoDB、Redis、MapReduce等都弱化了可用性。
Paxos、Raft等共識算法主要處理對於一致性敏感的情況。在Paxos類算法中,可能存在著無法提供可用結果的情形,同時允許少數節點離線。
C、弱化分區容忍性
現實中,網絡分區出現概率較小,但很難完全避免。
兩階段的提交算法,某些關系型數據庫以及ZooKeeper 主要考慮了這種設計。
實踐中,網絡可以通過雙通道等機制增強可靠性,實現高穩定的網絡通信。
五、ACID原則與多階段提交
1、ACID原則簡介
ACID,即Atomicity(原子性)、Consistency(一致性)、Isolation(隔離性)、
Durability(持久性)四種特性的縮寫。
ACID 是一種比較出名的描述一致性的原則,通常出現在分布式數據庫等基於事務過程的系統中。
ACID 原則描述了分布式數據庫需要滿足的一致性需,同時允許付出可用性的代價。
Atomicity:每次事務是原子的,事務包含的所有操作要麽全部成功,要麽全部不執行。一旦有操作失敗,則需要回退狀態到執行事務前。
Consistency:數據庫的狀態在事務執行前後的狀態是一致的和完整的,無中間狀態。即只能處於成功事務提交後的狀態。
Isolation:各種事務可以並發執行,但彼此之間互相不影響。按照標準SQL規範,從弱到強可以分為未授權讀取、授權讀取、可重復讀取和串行化四種隔離等級。
Durability:狀態的改變是持久的,不會失效。一旦某個事務提交,則它造成的狀態變更就是永久性的。
與ACID 相對的一個原則是eBay技術專家Dan Pritchett 提出的BASE(Basic Availability,Soft-state,Eventual Consistency)原則。BASE原則面向大型高可用分布式系統,主張犧牲掉對強一致性的追求,而實現最終一致性,來換取一定的可用性。
ACID和BASE兩種原則實際是對 CAP原理三種特性的不同取舍。
對於分布式事務一致性的研究成果包括著名的兩階段提交算法(Two-phaseCommit,2PC)和三階段提交算法(Three-phase Commit,3PC)。
2、兩階段提交算法
兩階段提交算法最早由Jim Gray於1979年在論文《Notes on Database Operating Systems》中提出。其基本思想十分簡單,既然在分布式場景下,直接提交事務可能出現各種故障和沖突,那麽可將其分解為預提交和正式提交兩個階段,規避沖突的風險。
預提交:協調者(Coordinator)發起提交某個事務的申請,各參與執行者
(Participant)需要嘗試進行提交並反饋是否能完成。
正式提交:協調者如果得到所有執行者的成功答復,則發出正式提交請求。如果成功完成,則算法執行成功。
在此過程中任何步驟出現問題(例如預提交階段有執行者回復預計無法完成提交),則需要回退。
兩階段提交算法因為簡單容易實現的優點,在關系型數據庫等系統中被廣泛應用。兩階段提交算法的缺點是整個過程需要同步阻塞導致性能通常較差;同時存在單點問題,較壞情況下可能一直無法完成提交;可能產生數據不一致的情況(例如協調者和執行者在第二個階段出現故障)。
3、三階段提交算法
三階段提交針對兩階段提交算法第一階段中可能阻塞部分執行者的情況進行了優化,即將預提交階段進一步拆成兩個步驟:嘗試預提交和預提交。
完整過程如下:
嘗試預提交:協調者詢問執行者是否能進行某個事務的提交。執行者需要返回答復,但無需執行提交,可以避免出現部分執行者被無效阻塞住的情況。
預提交:協調者檢查收集到的答復,如果全部為,,則發起提交事務請求。各參與執行者(Participant)需要嘗試進行提交並反饋是否能完成。
正式提交:協調者如果得到所有執行者的成功答復,則發出正式提交請求。如果成功完成,則算法執行成功。
無論兩階段提交還是三階段提交,都只是一定程度上緩解了提交沖突的問題,並無法一定保證系統的一致性。多階段提交首個有效算法是Paxos算法。
六、可靠性指標
1、可靠性指標簡介
可靠性(Availability,可用性)是描述系統可以提供服務能力的重要指標。高可靠的分布式系統通常需要各種復雜的機制來進行保障。
通常情況下,服務的可用性可以用服務承諾(Service Level Agreement,SLA)、服務指標(Service Level Indicator,SLI)、服務目標(Service Level Objective,SLO)等方面進行衡量。每年允許服務出現不可用時間的可靠性指標參考值如下:
通常,單點的服務器系統至少應能滿足兩個9;普通企業信息系統三個9就足夠;系統能達到四個9已經是領先水平(參考AWS等雲計算平臺);電信級的應用一般需要能達到五個9,一年裏面最多允許出現五分鐘左右的服務不可用;六個9以及以上的系統較為少見,要實現往往意味著極高的代價。
2、兩個核心時間
一般地,描述系統出現故障的可能性和故障出現後的恢復能力,有兩個基礎的指標:MTBF和 MTTR。
MTBF(Mean Time Between Failures),即平均故障間隔時間,是系統可以無故障運行的預期時間。
MTTR(Mean Time To Repair),即平均修復時間,是發生故障後系統可以恢復到正常運行的預期時間。
MTBF衡量了系統發生故障的頻率,如果一個系統的MTBF很短,則意味著系統可用性低;而MTTR則反映了系統碰到故障後服務的恢復能力,如果系統的 MTTR 過長,則說明系統一旦發生故障需要較長時間才能恢復服務。
一個高可用的系統應該是具有盡量長的MTBF和盡量短的MTTR。
3、提高可靠性
由兩種方法可以提高可靠性:一是讓系統中的單個組件都變得更可靠;二是消滅單點。
依靠單點實現的可靠性畢竟有限,要想進一步的提升系統的可靠性,就只好消滅單點,通過主從、多活等模式讓多個節點集體完成原先單點的工作(分布式),可以從概率意義上改善服務對外整體的可靠性。
區塊鏈快速入門(二)——分布式系統核心技術