分佈式一致性是一個很「古典」的話題,即在分佈式系統中,如何保證系統內的各個節點之間數據的一致性或可以就某個提案達成一致。這個問題想必對於不少技術同窗而言並不陌生,幾乎在全部的分佈式系統中都會遇到,好比hdfs、mq、zookeeper、kafka、redis、elasticsearch等。然而這個問題卻歷久彌新,隨着分佈式網絡的蓬勃發展與複雜化,對於該問題解法的探索也一直在進行中。html
而近年來,隨着區塊鏈技術的興起,特別是開放網絡中的公有鏈與有權限網絡中的聯盟鏈的蓬勃發展,一致性問題再次獲得關注,並重新的視角來審視該問題。node
本文將從傳統的分佈式一致性問題提及,再次重溫咱們須要面對的問題挑戰、已有的理論研究、以及相應的一致性算法,並簡要分析這些一致性算法的適用性與侷限性,以及這些傳統一致性算法與嶄新的區塊鏈技術的結合。另外,將從區塊鏈中一致性問題的全新視角「人的可信」出發,重點闡述公有鏈領域中的共識算法與機制。所以,本文圍繞「一致性」技術問題,重點從技術視角闡述傳統計算機科學中的分佈式一致性算法與區塊鏈中的共識機制的關聯,以及公有鏈對於一致性問題的從新思考。mysql
要清楚理解分佈式一致性,首先須要對分佈式網絡的特性有清晰的認識。那麼分佈式網絡具備哪些特色呢?或者通俗理解,在分佈式網絡中,可能遇到哪些問題呢?git
故障錯誤(Crash Fault)很好理解,就是說分佈式網絡中:github
這些問題,其實就是咱們在分佈式環境中最常實際遇到的問題,這些問題實質上都是因爲分佈式系統中的物理硬件的不可靠、不穩定所帶來的必然風險,好比:網絡(信道)不多是永遠穩定可靠的、物理機磁盤或CPU等不多是永遠良好的。故障錯誤能夠說是分佈式系統中必須考慮並解決的最基本、最多見的一類錯誤。redis
上文的故障錯誤,仍然基於一個很簡單的假設:節點要麼不正常工做或響應,要麼能正常工做或響應,但不能口是心非、陽奉陰違、表裏不一,便可以不幹事、但不能幹壞事。一旦網絡中存在做惡節點,可能會隨意篡改或僞造數據,那麼一致性問題的難度就大幅增長。咱們常把這類存在「搗亂者」,可能會篡改或僞造數據或響應信息的錯誤,稱之爲拜占庭錯誤(Byzantine Fault),而前面所說的故障類錯誤也稱之爲非拜占庭錯誤。算法
拜占庭這一稱呼,源於Lamport最初的論文,能夠說是分佈式領域最複雜、最嚴格的容錯模型。簡而言之,n個將軍準備一塊兒進攻某個城堡,每一個將軍均可以選擇進攻或是撤退,但全部將軍必須行動一致才能成功。各個將軍之間相隔很遠,不能直接通信,必須經過信使來傳遞消息。可是信使並不可靠,信使可能過了好久才送到消息、可能一直也沒有把消息送到、甚至可能會故意篡改消息;而將軍也並不可靠,裏面可能存在叛徒,並不按照提案來行動。顯然,這個故事中的信使用來表明分佈式網絡中的不可靠信道,而將軍就是各個不可靠的節點。sql
如何在充滿風險與不肯定的分佈式網絡中,尋找到某種肯定性與一致性,使得整個分佈式網絡輸出穩定可靠的一致性結果,就是分佈式一致性算法要解決的核心問題。顯而易見,解決故障類錯誤更容易一些,一般把這類一致性算法叫作故障容錯算法(Crash Fault Tolerance)或者非拜占庭容錯算法。而拜占庭類錯誤,由於有惡意篡改的可能性存在,複雜性更高、解決難度更大,一般把解決這類問題的算法稱做拜占庭容錯算法(Byzantine Fault Tolerance)。數據庫
那麼咱們忍不住要問,兩類容錯算法的界限在哪裏?或者說兩類錯誤都在什麼樣的場景下出現?惡意篡改這種狀況真的須要考慮嗎?問題的答案可能取決於咱們所處的網絡環境與業務場景。安全
一般而言,若是系統處於可信的內部網絡環境中,只須要考慮故障容錯(CFT)可能就足夠了。好比咱們常常見到的公司內的分佈式存儲、消息隊列、分佈式服務等各類分佈式組件,其實只須要考慮故障容錯就足夠了。由於公司內整個網絡是封閉的,又有多重防火牆的保護,外界很難接入或攻擊;各個節點是由公司統一部署的,機器或運行的軟件遭到篡改的可能性極小;此時的分佈式網絡環境相對「單純」,咱們惟一的敵人只是:通訊網絡與機器硬件。咱們須要考慮的是網絡的延遲、不穩定,以及機器隨時可能出現的宕機、故障。
而拜占庭類錯誤(BFT),是把整個分佈式網絡放到了更大的環境中去看,除了物理硬件以外,還考慮了一些「人」的因素。畢竟,機器是不會做惡的,做惡的只有人。假如咱們所處的分佈式網絡是較爲開放的網絡,好比行業內幾十上百家公司組成的聯盟網絡;或者是徹底開放的網絡,好比任何人均可以隨意接入到網絡中;而節點機器和上面部署的軟件也是由各個公司或我的本身提供和部署的,那麼若是利益足夠大,極可能會有人對網絡中的某個節點發起DDoS攻擊、故意篡改軟件代碼改變其執行邏輯、甚至可能故意篡改磁盤上持久化的數據。顯然,咱們此時面臨的挑戰更大了,咱們除了要考慮通訊網絡和機器硬件的不可靠以外,還必需要考慮和應對系統中的「搗亂者」。
這些實踐中遇到的問題,也引起了諸多計算科學家進行了很是多的理論研究。這些理論研究對於工程技術人員而言或許過於抽象繁瑣,有些甚至是無趣的數學問題,但這些理論對於指導咱們解決這些問題意義重大。這些理論至關因而告訴了咱們這類問題解法的理論極限,以及哪些方向能夠探索、哪些方向是死路一條。站在前人的肩膀上,纔不至於花畢生精力去研製「永動機」。這些理論你們應該都有所瞭解,這裏只簡單回顧。
早在1985年,Fisher、Lynch、Paterson三位科學家就發表了關於分佈式一致性問題的不可能定理:在徹底異步的分佈式網絡中,故障容錯問題沒法被解決。( We have shown that a natural and important problem of fault-tolerant cooperative computing cannot be solved in a totally asynchronous model of computation. )說得更直白點:在異步網絡中,不可能存在可以容忍節點故障的一致性算法,哪怕只有一個節點故障。而且這裏並無考慮拜占庭錯誤,而是假設網絡很是穩定、全部的消息都能被正確傳遞、而且僅被傳遞一次,即使如此都不可能找到能容忍哪怕只有一個節點失效的一致性協議,可見該結論有多強。( In this paper, we show the surprising result that no completely asynchronous consensus protocol can tolerate even a single unannounced process death. We do not consider Byzantine failures, and we assume that the message system is reliableit delivers all messages correctly and exactly once. )
固然了,這只是理論上的。它的意義在於告訴咱們此類問題的理論極限,並不意味着此類問題在實踐中也不可能被「解決」。若是咱們願意放寬限制、作出犧牲,在工程上是能夠找到切實可行的解法的。
FLP不可能定理的最大適用前提是異步網絡模型。何爲同步、異步模型呢?
所幸的是,咱們所處於的真實的網絡世界更接近同步模型,在不少場景上,咱們均可以經過經驗或採樣肯定最大超時時間。舉個通俗點的例子:你給朋友快遞了一本書,朋友過了3天還沒收到,此時朋友很難判斷究竟是快遞延遲了,仍是快遞出問題送丟了。可是若是過了一個月,朋友仍沒收到書,基本就能夠判定快遞送丟了。而背後的推論就是基於經驗或統計:一般快遞都能在1-2周內送達。顯然,異步模型實際上是反映了節點間通信的最差狀況、極端狀況,異步模型包含了同步模型,即能在異步模型上有效的一致性協議,在同步模型上也一樣有效。而同步模型是對異步模型作了修正和約束,從而使得更接近真實世界,也使得在實踐中一致性問題有可能獲得有效解。
另外,即使是在異步網絡模型下,FLP也並不意味着一致性永遠沒法達成,只是說沒法保證在有界的時間(in bounded time)內達成。在實踐上,若是放寬對bounded time的限制,仍然是有可能找到實踐中的解法的。
而根據DLS的研究,一致性算法按照網絡模型能夠分爲三大類:
從另外一個角度來理解,FLP實際上考慮了分佈式系統的3個屬性:安全(safety)、活性(liveness)、容錯:
FLP不可能定理其實意味着在異步網絡中,不可能存在同時知足這三者的分佈式一致性協議。由於分佈式環境中,節點故障幾乎是必然的,所以容錯是必需要考慮的因素,因此FLP不可能定理就意味着一致性協議在能作到容錯的狀況下,沒辦法同時作到安全性與系統活性。一般在實踐中,咱們能夠作出部分犧牲,好比犧牲一部分安全性,意味着系統總能很快達成結論,但結論的可靠性不足;或者犧牲一部分系統活性,意味着系統達成的結論很是可靠,但可能長時間、甚至永遠都在爭論中,沒法達成結論。所幸的是,不少時候現實世界的魯棒性很強,使一致性協議失效的倒黴事件發生的機率也極可能極低。
另外,FLP並未排除Las Vegas類隨機算法,許多一致性算法採用了這種隨機性來規避FLP不可能定理對於肯定性異步網絡的限制。此類非肯定性一致性算法涉及Las Vegas規則:網絡最終必定能達成一致,可是達成一致所須要的時間多是無界的。此類算法每輪共識決策都有必定的機率,而且系統在T秒內可以達成一致的機率P隨着時間T的增長而指數增加並趨近於1。事實上,該方法被許多成功的一致性算法所採用,是在FLP不可能定理籠罩下的安全地帶(escape hatch),後面將會講到比特幣的共識機制就是採用了這樣的方法。
衆所周知、大名鼎鼎的CAP原理,從另外一個維度,簡單明瞭、直截了當地告訴咱們:可用性、一致性與網絡分區容錯性這三者不可能同時實現,而只能實現任意其中的兩個。( "Of three properties of shared-data systems (data consistency, system availability and tolerance to network partitions) one can only achieve two at any given time".) CAP與FLP看起來有類似之處,其實兩者並不盡相同,兩者是從不一樣的維度思考問題,另外即便是很類似的概念,內涵也並不徹底同樣。好比:
理論上,只能從CAP三者中選擇二者,然而,這種選擇的邊界並不是是非此即彼的(not binary),不少時候混合考慮不一樣程度的各個因素,結果多是更好的。( The whole spectrum in between is useful; mixing different levels of Availability and Consistency usually yields a better result.)
在實踐中,咱們一般須要根據實際業務場景作折中權衡。好比:
固然,這些並非定論,各個系統都在各自不斷的進化完善中,今天的結論明天可能就會被打破。更好的系統必定是不斷探索適合本身的場景,找到更佳的平衡點。
面對分佈式環境中各類真實、複雜的問題與挑戰,基於理論上的指引,各類應對現實問題的解法也被提出。咱們這裏不探究各種算法的實現細節與具體差別,僅作大致介紹,以便放到更大的維度,從總體上作比較。
最大名鼎鼎的分佈式一致性算法當屬Lamport提出的paxos算法,雖然其複雜性也一樣「臭名昭著」。Lamport開創性地提出了一種在工程實踐上切實可行的、可以最大程度地保證分佈式系統一致性的機制。paxos被普遍應用在諸多分佈式系統中,如Chubby、Zookeeper等。在basic paxos(單一法令,即每次僅對一個值進行決策)中有兩種角色:proposer能夠處理客戶端請求、主動提出某個議案值;acceptor被動響應proposer發出的信息、對提案進行投票、持久化存儲決策過程當中的值和狀態。(爲簡化模型,能夠忽略learner角色,不影響模型決策。)
如圖所示,共識決策過程採用了兩階段提交:
Paxos之因此在實踐中可行,其實也作了諸多假設和約束。從處理的問題上來看,Paxos僅能處理故障容錯,並不難處理拜占庭錯誤,因此屬於非拜占庭容錯算法。從FLP的視角,Paxos作到了故障容錯和安全性,但放棄了liveness(safe but not live),也就是說該算法可能永遠沒法結束,或者說永遠沒法達成共識,雖然這種可能性極小。從CAP的視角,Paxos只保證了CP,即作到了分區容錯性和一致性,但弱化了可用性。有時爲了加強paxos系統的可用性,能夠考慮增長learner角色的數目。
即使並不完美,Paxos在實踐中仍然是可靠、有效且久經考驗的。Paxos本質上是異步系統的分佈式一致性協議,而且在該領域具備支配地位。Chubby之父甚至聲稱世界上只有一種一致性算法,那就是paxos( there is only one consensus protocol, and that’s Paxos),其餘一致性算法都是paxos的broken version。Paxos之因此在實踐中有效是由於可能影響paxos系統liveness和可用性的條件並不容易被觸發,即使真的出現,所帶來的代價也可能並不是是難以接受的。
有感於Paxos的晦澀難懂,Ongaro在2014年提出了更容易理解的Raft算法。Raft把易於理解、易於工程實現提到了很高的重要級別,甚至是raft的初心和存在理由,於是在不影響功能性的前提下,儘量多地作了易於理解的精細設計。
Raft算法是leader-based的非對稱模型,系統中的任意一個節點在任意時刻,只能處於leader、follower、candidate這3種狀態之一。初始狀態全部節點都是follower狀態,follower想變成leader必須先成爲candidate,而後發起選舉投票;若是投票不足,則回到follower狀態;若是投票過半,則成爲leader;成爲leader後出現故障,若故障恢復後已有新leader,則自動下臺,迴歸follower狀態。
Raft還引入了term的概念用於及時識別過時信息,相似於zookeeper中的epoch;term值單向遞增,每一個term內至多一個leader;若不一樣term的信息出現衝突,則以term值較大的信息爲準。
Raft還採用了心跳包和超時時間,leader爲了保持本身的權威,必須不停地向集羣中的其餘節點發送心跳包;一旦某個follow在超過了指定時間(election timeout)仍沒有收到心跳包,則就認爲leader已經掛掉,本身進入candidate狀態,開始競選leader。
不難發現,raft的leader選舉是經過heartbeat和隨機timeout時間來實現的;而日誌複製(log replication)階段是以強leadership來實現的:leader接收client的command,append到自身log中,並將log複製到其餘follower;而raft對安全性的保證是經過只有leader能夠決定是否commit來實現的。
詳細的競選、複製等過程,這裏再也不贅述,有興趣的同窗能夠參考筆者以前的文章(https://yq.aliyun.com/articles/675031 )。值得一提的是,raft中的leader選舉過程和leader任期內的正常運做過程都比較簡單,複雜的實際上是leader的變動過程。
然而,雖然raft的原理機制與paxos不盡相同,但兩者所解決的問題,以及所採起的折中權衡策略,能夠認爲是相似的。也就是說raft仍然只能解決故障錯誤,仍然強調了故障容錯與安全性、一致性,弱化了liveness和可用性。
自從1982年Lamport提出拜占庭將軍問題以後,雖然有諸多關於拜占庭容錯解決方案的討論,但長期以來,此類問題的解決方案都效率低下、運行緩慢、複雜度太高,直到1999年Castro和Liskov提出實用拜占庭容錯算法(Practical Byzantine Fault Tolerance),首次將此類算法的複雜度從指數級降到了多項式級,TPS能夠達到幾千,也使得節點故意做惡類問題在實踐中找到了可行的解法。能夠證實,若是系統內做惡節點數目不超過總節點數目的1/3,PBFT算法就能生效。
在PBFT中,全部的節點被順序編號,其中1個是leader,其他的都是backup。系統內的全部節點間都互相通信,依據多數原則達成一致。PBFT中的每輪共識都被稱爲一個view,而在不一樣的view之間,leader都會發生變化;若是超過給定的時間,leader沒有廣播出消息,則leader就會經過view change協議被替換掉。經過這種replica timeout機制,保證了crashed或malicious leader會被檢測出來,從而經過從新選舉新的leader,而進入到新的view中。
如圖所示,從客戶端發起請求到收到回覆結果,能夠分爲5個階段,而共識過程採用了3階段協議。下面簡要敘述5個階段的大體過程:
PBFT基於異步網絡模型作到了安全性,但須要依賴消息超時時間來作週期性的同步。由於採用了leader-based方案,消息同步過程很快,也作到了徹底的順序寫入。可是leader的從新選舉過程很困難,某些惡意leader能夠在臨近timeout窗口期時才發送消息,這樣會致使系統嚴重緩慢。而利用這一不利特色,能夠攻擊網絡使正確的leader看起來也出問題,從而致使無窮無盡的leader選舉過程。
PBFT與Paxos、Raft相比,所能處理應對的問題更爲完備,除了能應對故障崩潰類錯誤以外,還能處理存在「搗亂者」的惡意篡改類拜占庭錯誤。然而,從所採起的折中權衡策略來看,PBFT仍然與Paxos、Raft很相似。從FLP的視角來看,PBFT一樣更關注容錯性和安全性,而弱化了liveness。從CAP的角度,PBFT一樣強調網絡分區容錯與一致性,而弱化了可用性。
即使如此,只要故障或做惡節點不超過總節點數的1/3,PBFT在實踐中仍是有效可行的。而拜占庭容錯算法(BFT)也不止PBFT一種,BFT類算法也在不斷進化,如Lamport就提出過改進版的Paxos算法BFT Paxos以處理拜占庭錯誤,近來也有人結合PBFT與Raft提出了 BFT Raft 算法。但從問題領域與原理機制上來講,仍然與原有的思路和框架較爲相似,再也不一一贅述。
從Paxos、Raft到PBFT,再到目前層出不窮的Paxos變種、Raft變種、BFT類混合新算法,分佈式一致性算法在不斷髮展、完善、進化。甚至各大公司也在結合本身的業務實際,研發各類適合本身場景的分佈式一致性算法。這些算法雖然並不完美,但都在適合本身場景的業務實踐中發揮着重大做用。那麼這些算法的適用場景究竟是什麼?自身又有哪些侷限性呢?
對於Paxos、Raft這類非BFT算法而言,只能處理機器硬件故障,而沒法處理存在做惡節點的狀況。顯然,這類非BFT算法只能運行在很是可信的網絡環境中,好比公司內部網絡中,在這樣的較爲封閉的網絡中,訪問須要嚴格受權,從而保證各個節點的身份是已知的、可信的,基本排除了節點做惡的可能性,這類算法纔能有效運行。
而BFT類算法,對於網絡環境的要求再也不那麼苛刻,即便存在做惡節點,只要做惡節點數目不超過總節點數的1/3,整個系統依然是安全的。但問題就在於,你怎麼知道網絡中到底有多少做惡節點?做惡節點佔總節點的比例到底有多高?顯然,若是網絡的接入是須要權限控制的,那麼這個問題就相對容易解決。好比10家業務關聯公司組成的聯盟網絡,只有這10家受權的公司才能訪問,即使裏面有個別公司(少於3家)蓄意做惡、妄圖篡改數據,整個系統仍然是安全可靠的。在這種permissoned網絡中,隱含着對於網絡中可能做惡節點數目的預估,即使真的做惡了,也能方便快速地定位出其真實身份,間接提升了網絡的安全性。
然而,在permissonless(開放權限、無權限控制)的公有網絡中,BFT類算法極可能會有問題。由於,若是分佈式網絡是開放的,誰都能進進出出,而接入網絡系統的成本又很低,那麼沒人知道網絡中到底可能有多少做惡節點,即使真有做惡,也很難定位出真實身份。好比,一種比較典型的女巫攻擊(Sybil attack)場景,做惡者能夠經過大量僞造身份來控制集羣中的大量節點,從而控制整個分佈式網絡。
另外,BFT類算法最大的侷限性還在於僅能協調少許的節點,如幾個到幾十個,若節點數目成千上萬,整個系統的性能將會很是低下,甚至可能沒法達成共識,從而影響系統的liveness和可用性。想必你們已經注意到,在PBFT的三階段協議中,都須要多點廣播(multicast):在pre-prepare階段,主節點向全部備節點廣播;在prepare節點,備節點向其餘全部節點廣播;在commit階段,各個節點向其餘全部節點廣播。因而可知,通信次數的數量級是節點數目的平方,當節點數目龐大時,這種兩兩廣播的機制將會是災難,系統幾乎不可能在較短期內達成一致。
綜上可知,這些傳統的分佈式一致性算法,不管是Paxos、Raft,仍是PBFT,一般適用於存在權限控制的、節點數目較少的、較爲可信的分佈式網絡環境中。
事實上,這些傳統的一致性算法在區塊鏈時代也煥發了新的活力,獲得了進一步的認識和使用。在網絡環境較爲可信的聯盟鏈場景中,這些一致性算法獲得了大量的應用。聯盟鏈因以下特色而被業內看好其應用前景:
在當前階段,聯盟鏈不失爲快速落地、解決行業痛點的不錯選擇,也是對區塊鏈後續發展的積極探索。由於聯盟鏈須要受權才能參與,這其實至關於已經提早創建了至關程度的信任,網絡環境較爲可信,網絡中的惡意行爲和攻擊行爲發生的可能性都很是低,而且即使發生也很容易快速追責。所以在這樣的場景下,傳統的一致性算法也能夠獲得應用。好比:
那麼咱們忍不住要問,若是網絡是徹底開放的、無需權限許可的(permissionless),誰均可以隨時進出,那麼整個系統還能在有限的時間內達成一致嗎?若是網絡中的節點數目再也不是幾十個,而是一萬個,那麼又該如何協調這些數量龐大的節點呢?
在回答這些問題以前,其實更應該反問:爲何須要網絡是徹底開放、無需許可的?什麼場景會須要一萬個節點?這究竟是僞需求,仍是真實存在的場景?這個問題的答案直接關係到區塊鏈中公有鏈的存在乎義,而要回答這個問題,咱們須要回到分佈式系統的初心和目的。
咱們爲何須要分佈式系統?顯然,這個問題不難回答,一般的理解,分佈式系統能夠加強容錯能力(Fault tolerance),畢竟系統依賴衆多不一樣的節點,而衆多節點同時失敗的可能性遠低於一個節點發生故障的可能性;另外,分佈式系統還能夠抵禦攻擊(Attack resistance),畢竟攻擊或摧毀衆多節點的難度遠大於攻擊單點的難度。
然而,以上這些依然是侷限在物理硬件的維度,都是用來下降機器物理硬件發生故障的可能性,而沒有考慮「人」的因素。若是一個系統足夠重要,好比電子貨幣系統等,除了考慮機器故障以外,更多須要考慮的是人的因素。部署節點的人會不會故意做惡呢?如何防止系統內不一樣節點間的腐敗串通呢?
以下圖所示,以太坊創始人Vitalik Buterin曾經深刻地探討過去中心化的含義。若是說傳統的分佈式系統作到了architectural decentralization(系統有多少物理機器構成?系統可以容忍最多多少臺機器同時故障?),考慮的是fault tolerance和attack resistance;那麼如今咱們須要考慮的是如何作到political decentralization,如何可以collusion resistance? 到底有多少人或組織最終控制了系統內的節點?如何防止這些人之間的腐敗串通?若是說傳統的分佈式系統考慮的問題是網絡或機器硬件的可信,那如今咱們想考慮的是「人的可信」:是否存在這樣的技術手段來防範人的做惡?如何確保重要網絡中的大部分節點不被一我的或一個組織惡意控制?
值得一提的是,這個問題的必要性依然充滿爭議,不少人根本未曾想過、或者認爲根本沒有必要考慮人的腐敗串通,也可能認爲對於這個問題技術也無能爲力,畢竟這與咱們生活的真實世界相去甚遠。咱們生活在一箇中心化平臺擁有極高聲譽、提供信用背書、控制一切規則流程的世界,好比極少有人擔憂銀行會故意作假帳,侵吞你在銀行的資產,畢竟你們廣泛認爲銀行是值得信賴的。若是認爲銀行都不可信,那極可能一切商業活動都沒法開展。
然而,咱們只是「假設」銀行是可信的,在「信任」與「懷疑」之間,咱們只是被迫選擇了信任,畢竟不信任銀行,商業活動沒法開展,經濟也將停滯。然而實際上,並無切實可行的措施來向全部人「證實」銀行是可信的。
若是你認爲這個問題是必要的、有意義的,那麼可否找到一種解決方案,可讓這個世界變得更可信,讓你再也不須要「被迫相信」某個陌生人,而是提供一種「證實」,足以確保與你交易的某個陌生人是可信的?Don’t Trust, Please Verify. 你不須要相信我,你也沒必要相信我,你只須要去驗證我。
若是要解決這個問題,全部人的身份應該是對等的,每一個人均可以平等、自由地參與決策過程,每一個人均可以自由地進出「議會」,這事實上是一種技術上的democracy,隱含的技術要素是:網絡必須是permissonless的,誰均可以隨時加入隨時離開;節點之間必須是對等的,能夠直接通信;無任何中間人,無任何中心權威存在,徹底的點對點(peer to peer);每一個節點都有但願成爲記帳者。
由於網絡無權限控制,徹底的開放、透明、民主,因此參與的節點數目極可能很是衆多,節點做惡的可能性也很高。那如何在這種permissionless的、節點數目衆多、存在較大做惡可能的分佈式網絡環境中,經過某種機制協調節點間的行爲,保證整個系統的一致性呢?顯然,如前所述的一致性算法並不能作到這一點,咱們須要尋求新的解法。
另外,去中心化多是區塊鏈領域最充滿爭議的詞彙。一些人認爲去中心化是區塊鏈的價值觀和公有鏈的靈魂與存在前提,應該儘量地保證系統的去中心化程度;而另外一些人認爲徹底的去中心化過於理想、不太可能實現,應該結合實際場景,在兼顧效率的狀況下考慮弱中心化或多中心化。這裏拋開價值判斷,單純從技術角度理性分析,去中心化程度越高確實系統的安全性會越高,因此在公有鏈的系統設計中確實應該儘量地保證系統的去中心化程度。不過,結合Vitalik Buterin對於去中心化含義的詮釋,在追求去中心化的過程當中,咱們不該該停留在單純的表面上看起來的去中心化,而應該綜合考慮去中心化的各個維度,結合實際狀況,作出必要的trade-off。
對開放網絡中的分佈式一致性問題比較創新的解法當屬比特幣中的Proof-of-work(PoW、工做量證實)機制。
2008年10月31日,中本聰發表了比特幣白皮書《Bitcoin: A Peer-to-Peer Electronic Cash System》,天才般地爲此類問題提供了創造性的解決思路,使得協調複雜網絡環境中的成千上萬節點成爲可能。事實上,中本聰並非爲了解決這個技術問題而發表了比特幣白皮書。相反,中本聰想象的更加宏大,他創造性地發明了比特幣這種徹底點對點的電子現金系統,以消除傳統支付中須要依賴的可信第三方中間人,而在實現的過程當中剛好依賴並解決了開放網絡中衆多節點間的一致性問題。也能夠說,比特幣所解決的最核心問題是點對點網絡中電子貨幣的雙花問題。然而,比特幣的實現機制毫不僅僅是分佈式網絡技術問題,還結合了密碼學、經濟學、博弈論等思想,並以一種非肯定性的機率方式實現了節點間的一致性。所以,單純地稱爲算法已不太能準確表達其含義,可能叫做共識機制(consensus mechanism)更爲恰當,由於其實現的確依賴了一整套的完整策略與制度。這裏咱們不過多闡述比特幣的思想意義與實現細節,而僅聚焦在其共識機制的實現上。
比特幣其實是電子簽名鏈,幣的owner能夠經過對前一個交易的哈希值和下一個owner的公鑰進行簽名,並將簽名添加到幣的末尾,從而實現轉帳。接受者經過校驗簽名來驗證幣的owner構成的鏈。然而,問題是幣的接受者沒有辦法確保幣的owner沒有進行雙花(double-spend),即有可能某個幣的owner將同一個幣前後轉給了兩我的。所以咱們須要一種機制來讓接收者確保幣的前一個owner並無在此以前將幣轉給其餘人,爲了確保這一點,惟一的辦法就是讓全部人知曉全部的交易。而在無可信第三方的狀況下,想實現這一點,全部的交易必須廣播給全部人。所以咱們須要一個系統,其中的全部參與者對他們接收幣的順序達成一致,造成惟一的順序記錄歷史。不難發現,這其實就是分佈式一致性問題。
而比特幣提供的方案就是須要一個由全部節點組成的時間戳服務器(timestamp server),時間戳服務器能夠對交易區塊的哈希加蓋時間戳,並將該哈希廣播出去。每個時間戳都在其哈希中包含了前一個時間戳,從而造成一條鏈,而每個新的時間戳都是對其以前全部時間戳的確保與強化。爲了在點對點的網絡中實現分佈式的時間戳服務器,比特幣採用了工做量證實機制(proof-of-work,PoW)。PoW涉及在作哈希運算時,須要尋找某個值,使得整體哈希值的開頭前幾位都爲零,而所須要的平均工做量隨着零位數目的增多而指數增長。另外,該哈希沒有任何規律,爲了保證開頭前幾位爲零,只能經過暴力的方法不斷地隨機試錯。一旦消耗了足夠的CPU的算力,找到了符合條件的哈希值,則該區塊就沒法變動,除非再耗費CPU重作一遍。
另外,PoW也解決了大多數決策問題。在比特幣中,最長的那條鏈就表明了大多數的決策。由於若是誠實的節點控制了大部分的算力,則誠實的鏈就會快速增加並超過其餘鏈。若是想篡改某個過去的區塊,攻擊者必須重作相應的區塊和其後面全部區塊的PoW任務,而後追趕並趕超誠實的節點。這種難度是很是巨大的,從數學上不難證實,隨着後續節點數目的增多,較慢的攻擊者想追遇上來的機率指數降低,通常認爲通過6個區塊以後,想追遇上來幾乎是不可能的。另外,PoW任務的難度並非固定的,而是用移動平均的方法動態調整的,這主要是考慮到硬件運算速率的提升和挖礦人數的增減變化,算的快就加大難度、算的慢就減少難度,經過動態調節難度使得比特幣的出塊時間大體穩定在10分鐘左右。
整個網絡的運行過程以下:
關於交易、挖礦等細節,這裏不過多闡述,有興趣的同窗能夠參考筆者以前的入門介紹文章。簡而言之,在比特幣中老是以最長鏈的信息爲準,若某個節點發現了比本身更長的鏈會自動切換到最長的鏈工做。
咱們忍不住要問,既然PoW成本如此之高,那如何激勵你們貢獻算力、成爲節點,以保證整個比特幣網絡的安全呢?比特幣中提供了兩種激勵策略:
這些激勵策略也隱含地鼓勵了節點保持誠實,若某個貪婪的攻擊者真的擁有了過半的CPU算力,他不得不作出選擇:究竟是篡改交易記錄,把他已經花出去的比特幣再轉回來呢?仍是老老實實地挖礦賺錢新幣和手續費呢?極可能,老老實實地挖礦是更有利的,畢竟能賺到的幣比其餘全部節點加起來都要多;而破壞比特幣體系也將會破壞自身財富的有效性,畢竟若比特幣再也不可靠,其價值也會迅速崩潰。這裏多提一點,攻擊者並不像通常人想象的那樣能夠隨心所欲、任意篡改或僞造交易記錄,他能作的只多是將其最近花出去的比特幣偷回來。
比特幣在沒有任何組織或團體維護的狀況下,僅僅依靠社區志願者自發維護,穩定運行了10年之久,期間從未發生太重大問題,這不能不說是個奇蹟,也足以證實了比特幣背後共識機制的有效性。咱們忍不住要問,爲何比特幣可以作到?爲何比特幣背後的共識機制可以如此有效?bitnodes數據顯示目前比特幣節點數目超過1萬(比特幣節點類型較多,不一樣口徑數量可能不一致,這裏僅考慮全節點)。爲何比特幣可以在permissionless的網絡環境中,協調上萬的節點保持一致性?
筆者粗淺的認爲,可能有如下幾個緣由:
顯然,比特幣的共識機制再也不拘泥於分佈式算法層面,而是包含了更多經濟學、博弈論、機率論等思想,所以可能叫做共識機制更爲恰當。不過,咱們仍然能夠將比特幣的PoW共識機制放到一致性問題的框架內來思考,從FLP和CAP的角度來看:
綜合來看,不難看出,比特幣的PoW共識機制在FLP和CAP的限制下,作到了比較好的折中權衡,在實踐中確實提供了開放複雜網絡中分佈式一致性問題的可行解法,比特幣近十年來的穩定可靠運行也有力地證實了這一點。
另外,比特幣的PoW算法也被Miller等人(https://socrates1024.s3.amazonaws.com/consensus.pdf:Anonymous Byzantine Consensus from Moderately-Hard Puzzles: A Model for Bitcoin)嚴謹地分析並證實:
可見,PoW算法不只在實踐中可靠,在理論上也能經受考驗。PoW算法採用了同步模型與隨機機率來規避FLP的肯定性異步模型不可能定理。而PoW獨立於網絡大小的可擴展性,與PBFT算法O(n2)複雜度相比優點巨大:節點越多,系統效率並未下降,而系統卻更安全。
咱們忍不住要問,PoW機制到底有何神奇之處呢?
其實,你們可能也意識到了,PoW的思想並不高深,事實上也並不是是中本聰獨創。早在1993年這一思想就被提出用於對抗垃圾郵件(Pricing via Processing or Combatting Junk Mail),但直到中本聰創造比特幣以前,這一思想都還沒有獲得普遍應用。PoW思想的精髓就在於故意製造障礙、增長參與者的成本,以儘可能下降參與者的惡意企圖。好比要求請求者作些額外的工做以檢測DDoS攻擊、垃圾郵件等,也好比最多見的登陸網站須要輸入驗證碼,也是爲了增長登陸成本,防止網站被攻擊。這類任務最核心的特徵是非對稱:對於服務請求者來講,完成任務必須有必定難度;而對服務提供者來講,驗證任務必須很簡單快速。對於比特幣PoW而言,顯然符合非對稱性:不斷試錯,尋找使哈希符合條件的nonce(隨機數)須要消耗大量算力,而驗證尋找到的nonce是否符合條件只須要作一次簡單的哈希運算驗證便可。
比特幣的PoW本質上是one-CPU-one-vote,一個CPU投一票。爲何選擇CPU,而不是IP地址呢?這仍然是基於任務難度考慮,如果one-IP-one-vote,則系統能夠被擁有大量IP地址的人(如ip供應商)輕易控制。相對而言,至少在當時(還沒有出現ASIC和FPGA)CPU仍然是比較昂貴的硬件,想擁有大量的算力(CPU+電力)並不容易。固然,這其實也隱含地爲比特幣的價值提供了現實錨定:虛擬的貨幣體系經過算力找到了現實物理世界的價值錨定,雖然在不少人看來這種算力的消耗是毫無心義、浪費能源的。
也有不少人提出如何下降比特幣的挖礦成本,固然這種思考嘗試有其積極意義,這種工做量證實的成本須要適宜:難度過大、成本太高確實浪費能源較多,不過比特幣網絡的安全性也獲得了提升;難度太小、成本太低則會起不到防攻擊的目的,進而也會下降比特幣網絡的安全性。這實際上是一個須要作tradeoff的問題,也是一個偏主觀的價值判斷,取決於大衆對比特幣的認識和定位。價值判斷老是充滿了主觀偏見,目前對於比特幣的爭論如此之大,其實也正是由於社會大衆還沒有達成共識,還沒有構建出對於比特幣將來共同一致的想象。
簡言之,比特幣的PoW是一整套的機制,包含了技術上的權衡、經濟和博弈的考量,這一整套的策略和機制共同保障了比特幣網絡的安全可靠。
凡事沒有完美,PoW機制也不可例外地存在侷限,其實從你們對比特幣的諸多批評也可見一二,一般地你們認爲PoW機制存在如下侷限性:
在這些新的解決思路中,無疑最引人注目的就是Proof-of-stake(PoS、權益證實),一樣面對開放複雜網絡中的一致性問題,提出了全新的解決方案。
2011年在bitcointalk論壇一個名爲QuantumMechanic的用戶率先提出了proof-of-stake的思想,然後不斷髮展完善,獲得愈來愈多人的信賴。
PoS的基本思想大體以下:
不難發現,PoS也是採用了經濟和博弈的思想,經過激勵策略和懲罰機制來確保了網絡的安全可靠。
PoS協議仍然符合傳統的拜占庭容錯算法研究的結論。目前圍繞PoS的研究能夠分爲兩條主線:一條圍繞同步網絡模型、一條圍繞部分異步網絡模型。而基於鏈的PoS算法幾乎老是依賴於同步網絡模型,而且其有效性與安全性能夠像PoW算法同樣被嚴格證實。
另外,從CAP的角度來看,基於鏈的PoS算法與PoW算法相似,也是儘量地作到了容錯性,另外在可用性與一致性之間,更多地保證了可用性。
若是說傳統的一致性算法(Paxos、Raft和PBFT)實現的是肯定性的最終性(finality)或一致性,那麼PoS與PoW相似,轉而尋求機率性的最終一致性。從傳統CAP的視角,這實際上是對一致性的弱化,然而從實踐可行性的視角來看,也是一種全新的思惟和突破。
而從PoS的設計策略來看,也能夠分爲兩大陣營:
PoS的思想並不複雜,而其中比較容易被詬病的偏偏就是這種與現實世界相似的按出資比例獲取收益的制度。你們對現實世界的馬太效應已經很是警戒,這種制度顯然容易帶來富者越富、窮者越窮的結果:擁有更多代幣的人,將會有更多機會成爲validator,從而參與網絡並得到更多收益。
然而,對這一問題的見解爭議很大,不少人提出了徹底不一樣的見解,認爲PoS相比PoW更公平、更有助於對抗中心化趨勢。理由主要是:PoW挖礦依賴現實世界的物理硬件和電力資源,而這很容易帶來規模經濟(Economies of scale)優點。購買10000臺礦機的公司相比購買1臺礦機的我的更有議價權,甚至能夠自主研發成本更低的礦機;而擁有10000臺礦機的礦場,對電費的議價權也更高,甚至能夠搬遷到電費便宜的國家和地區的電站旁邊,甚至能夠自建成本更低的電站。由此帶來的後果就是越龐大的組織的綜合挖礦成本越低,而這正是現實世界真實已經發生的事實。相比之下,PoS不須要依賴現實硬件,不存在規模經濟優點,在不考慮價格操縱的狀況下,買1個幣的價格和買10000個幣的價格是線性增長的,從這個角度理解,PoS可能更公平,更有助於去中心化。
對PoS的另外一個擔心是其安全性,畢竟PoS再也不像PoW那樣作複雜的CPU運算以證實本身。在PoW中,若想發動攻擊,須要控制51%的算力(近來也有研究發現只需25%算力即有可能攻擊成功),這也就意味着須要擁有大部分的礦機和算力資源。而在PoS中,若想控制整個體系,須要擁有51%的代幣。究竟哪一個更安全?其實也不太好講,不過能夠從現實世界的例子來看,若是比特幣算法切換爲PoS,則控制比特幣體系須要大約比特幣市值的一半,大概是400~1600億美金(比特幣價格區間5000~20000美金),顯然這一數字遠遠高於礦機成本,想擁有這麼大資金量發動攻擊幾乎是不可能的,從這個角度來說,PoS可能更安全。
除此以外,PoS由於部署成本很低(對硬件要求很低),在真實世界中會致使代幣很是容易分叉,從而產生一堆山寨幣,而PoW不存在這個問題。由於PoW依賴硬件挖礦,若想把比特幣的某個參數改改,這很容易;但真想跑起來,則須要大量算力的支持,須要爭取大量miner的支持,好比bitcoin cash從bitcoin中分叉出來就歷經波折。而PoS徹底沒這個顧慮,隨便某我的均可如下載開源代碼、隨意改下,拉幾個節點就能夠聲稱本身創造了一種全新的代幣,好比從EOS(代幣名)中能夠輕易分叉出幾十上百個山寨兄弟幣,每一個都聲稱本身很獨特。這確實是事實,不過也不太容易說孰好孰壞。
PoS機制中最關鍵的當屬下一個區塊validator或creator的選擇機制,究竟誰來作這個幸運兒?前文所說的根據帳戶資金按比例按機率選擇實際上是最簡單的一種方式,這種方式確實容易致使有錢人得到一勞永逸的收益,從而損害網絡中其餘參與者的積極性。目前有不少種思路來改善這一問題,其中比較有意思的是coin age-based方法,在選擇creator的時候,除了考慮資金量,還會考慮coin age(幣齡)。所謂的coin age指的是幣在某個帳戶上的停留時間,好比1個幣轉入指定帳戶通過10天,能夠認爲幣齡是10,而每次幣發生變更幣齡都會從0開始從新計算。經過這樣,能夠限制大資金量節點頻繁成爲creator,好比能夠設定幣齡達到30纔有機會成爲creator,而成爲creator以後幣齡當即清零。這實際上是限制了大參與者的利益,爲其餘中小參與者提供了更多的參與機會。
基於PoS改進的比較有名的方案當屬Delegated Proof-of-Stake(DPoS),其中採用了代理人委託機制。在DPoS中再也不是全部節點都有可能成爲creator,而是節點間相互投票,只有得票最高的一些節點纔可能參與區塊創造過程。具體以下:
不難發現,DPoS經過引入投票機制,儘量地保證了節點的普遍參與;而對validator數目的限制(通常是21-101個),儘量地提升了系統的運行效率。雖然充滿很大爭議,DPoS仍然不失爲一種可行的解法,愈來愈多的區塊鏈系統也在嘗試對其進行改進和探索。
在公有鏈中,衆多項目都採用了PoS機制,比較有名的有:
其實,PoS機制的興起除了其自己具有的低成本、高效率、去中心化等特色以外,還在於它打開了一扇新的大門——基於博弈論機制來設計如何下降中心化風險的一系列技術,如何預防中心化壟斷巨頭的造成,以及在已有巨頭的狀況下如何防範它們損害網絡( Proof of stake opens the door to a wider array of techniques that use game-theoretic mechanism design in order to better discourage centralized cartels from forming and, if they do form, from acting in ways that are harmful to the network)。
而隨着近年來區塊鏈(特別是公有鏈)的蓬勃發展,其餘各類Proof of機制也層出不窮。從這裏面的諸多機制中均可以看到PoS思想的影子,即如何從經濟角度和博弈視角來設計制度儘量地保證去中心化、安全性與高效率。下面對這些機制作簡要說明:
不難發現,雖然這些Proof-of機制層出不窮、不盡相同,但其要解決的核心本質問題是相同的,即:讓誰來成爲可以記帳的幸運兒?這些Proof-of機制只不過是採起了各類不一樣的策略來制定遊戲規則,讓各個節點儘量公平地證實本身,從中公平地選出幸運兒。全部這些策略,包括基於CPU算力、持有代幣數量、存儲空間大小、隨機等待時間、銷燬代幣數量、節點活躍度、節點貢獻度等,都是在特定的場景下對於開放網絡中一致性問題的探索。
從PoW到PoS,再到Proof of "Everything you can think",對於permissionless網絡中的一致性問題一直在探索中。「一致性」的內涵也在發生變化,從傳統的如何防範網絡與機器硬件的故障,保證網絡節點間的數據一致性,到開放網絡中,如何防範網絡中人的做惡,保證網絡中節點數據間的真實一致。能夠說是從硬件的可信,邁進了「人的可信」,公有鏈技術也被視爲「信任的機器」。不過顯然,人的可信問題過於複雜,甚至也超越了單純的技術範疇。目前階段所能作到的也遠遠未能保證「人的可信」,更多的仍停留在人對於機器的信任、人對於「協議」的信任。不過可喜的是,咱們終於邁出了這一步,開始直面這個棘手的問題,探索創新性的解法。
這個世界充滿了不肯定性,計算機科學也同樣。從計算機出現開始,咱們就不得不面對機器硬件的不肯定性:意外故障可能帶來的問題。從互聯網興起開始,咱們就不得不面對網絡的不肯定性:通信消息可能的延遲、亂序、丟失。而應對不肯定性問題最天然的解法就是冗餘,經過大量節點來實現系統總體的安全性,避免單點故障,加強容錯能力和抵禦攻擊的能力。正是基於此,才帶來了大型分佈式網絡的蓬勃發展,而如何在不肯定的網絡和節點間尋找到某種肯定性,協調衆多節點間的一致性,正是分佈式一致性算法須要解決的問題。可以應對故障類錯誤的CFT算法包括最經典的Paxos算法和更簡單的Raft算法,能夠在網絡中正常節點超過一半的狀況下保證算法的有效性。這類算法一般應用在環境可信的封閉網絡中,協調幾個到幾十個節點間的一致性,如公司內部的分佈式存儲、分佈式服務協議、分佈式消息系統等。另外,也能夠應用於由少數機構組成的須要受權才能訪問的聯盟鏈網絡中。
然而,不肯定的不止是網絡與機器自己,還有控制網絡中各個節點的人的行爲。如何在可能存在搗亂者惡意篡改數據或攻擊網絡的狀況下,保證分佈式網絡的一致性,正是拜占庭容錯類算法BFT須要考慮的問題。BFT類算法中最多見的就是PBFT算法,能夠在網絡中正常節點超過1/3的狀況下保證算法的有效性。即使如此,PBFT對於網絡中惡意行爲的應對能力仍然是有限的,另外其性能也會隨着網絡中節點數目的增多而顯著降低。這些侷限性也致使PBFT算法僅能用於環境較爲可信的、有權限控制的網絡中,協調幾個到幾十個節點間的一致性,好比聯盟鏈場景中。
而在無權限控制的permissionless開放網絡中,不肯定性更加嚴峻,特別是網絡節點背後的人的行爲的不肯定性。如何防止網絡中的控制人之間經過腐敗串通組成寡頭,從而控制網絡中的過半節點,達到控制、損害、攻擊網絡的目的,便是開放網絡須要考慮的問題。從這一角度看,開放網絡中的一致性還隱含了安全性的前提:即不只要求節點間可以達成共識,還要求該共識確實是由節點衆多控制人真實表達而造成的。而爲了達到這種一致性與安全性,不只須要實現物理硬件節點在結構上的decentralization,還須要儘量地保證節點背後實際控制人的decentralization。爲了實現這一點,須要保證任何人均可以隨時部署運行網絡協議而成爲網絡中的節點、能夠隨時進出網絡;節點之間點對點通信,無任何中心化控制節點;節點的角色是徹底對等的,按照規則有公平的可能性參與記帳。而如何協調開放網絡中數量龐大的上萬個節點間的行爲,保證網絡的一致性與安全性,便是公有鏈共識機制要解決的問題。其中,最典型的當屬比特幣獨創的基於工做量證實的PoW共識機制,以及隨後興起的基於權益證實的PoS共識機制。這些共識機制再也不侷限於技術上的一致性自己,而是更多地引入了經濟學和博弈論的思想,從經濟和博弈的角度儘量保證網絡的一致性與安全性。
從傳統的封閉分佈式網絡環境中的一致性,到有權限控制的聯盟鏈場景中的一致性,再到無權限控制的公有鏈開放網絡環境中的共識機制,面對的問題愈來愈複雜,應對的挑戰也愈來愈嚴峻。從單純的技術視角來看,其中對於consensus的研究是一脈相承的,這些一致性算法或共識機制一樣也都受到傳統分佈式一致性理論研究中FLP impossibility和CAP theorem的制約。Paxos、Raft和PBFT都強調了fault tolerance與safety/consistency,而弱化了liveness與availability。而PoW與PoS則採用了全新的視角來考慮該問題,儘量地保證了fault tolerance,以及liveness與availability,放棄了對於安全性與一致性肯定性的追求,而僅僅以機率性的方式追求最終的safety與consistency。
另外,對於consensus的思考,也在不斷深刻,從單純的節點間的數據一致性,到強調節點背後的人之間的共識與認同;從保證網絡與硬件的可信,到儘量地確保組成網絡的節點背後的人的可信。雖然人與人之間的可信很是複雜,也超越了單純的技術範疇,可喜的是咱們已經走在路上,而目前在該領域正在進行的創新性的積極探索,也必將讓世界變得更加可信。
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。