常見共識算法

參考鏈接:http://www.javashuo.com/article/p-tbaopaai-dq.html             html

參考鏈接:https://blog.csdn.net/cnh294141800/article/details/53768464/node

共識的概念:

區塊鏈架構是一種分佈式的架構。其部署模式有公共鏈、聯盟鏈、私有鏈三種,對應的是去中心化分佈式系統、部分去中心化分佈式系統和弱中心分佈式系統。算法

  在分佈式系統中,多個主機經過異步通訊方式組成網絡集羣。在這樣的一個異步系統中,須要主機之間進行狀態複製,以保證每一個主機達成一致的狀態。然而異步系統中,可能出現沒法通訊的故障主機,主機的性能降低,網絡擁塞等狀況,這些可能致使錯誤信息在系統內傳播。所以須要在默認不可靠的異步網絡中定義容錯協議,以確保各主機達成安全可靠的狀態共識。數組

  所謂共識,簡單理解就是指你們都達成一致的意思。其實在現實生活中,有不少須要達成共識的場景,好比開會討論,雙方或多方簽定一份合做協議等。而在區塊鏈系統中,每一個節點必需要作的事情就是讓本身的帳本跟其餘節點的帳本保持一致。若是是在傳統的軟件結構中,這幾乎就不是問題,由於有一箇中心服務器存在,也就是所謂的主庫,其餘的從庫向主庫看齊就好了。在實際生活中,不少事情人們也都是按照這種思路來的,好比企業老闆發佈一個通知,員工照着作。可是區塊鏈是一個分佈式的對等網絡結構,在這個結構中沒有哪一個節點是「老大」,一切都要商量着來。promise

  因此在區塊鏈系統中,如何讓每一個節點經過一個規則將各自的數據保持一致是一個很核心的問題,這個問題的解決方案就是制定一套共識算法,實現不一樣節點上帳本數據的一致性和正確性。這就須要借鑑已有的在分佈式系統中實現狀態共識的算法,肯定網絡中選擇記帳節點的機制,以及如何保障帳本數據在全網中保持正確、一致。安全

  共識算法其實就是一個規則,每一個節點都按照這個規則去確認各自的數據。咱們暫且拋開算法的原理,先來想想在生活中咱們會如何解決這樣一個問題:假設一羣人開會,這羣人中沒有領導或者說老大,你們各抒己見,那麼最後如何統一出一個決定出來呢?實際處理的時候,咱們通常會在某一個時間段中選出一我的,那我的負責彙總你們的內容,而後發佈完整的意見,其餘人投票表決。每一個人都有機會來作彙總發表,最後誰的支持者多就以誰的最終意見爲準。這種思路其實就算是一種共識算法了。然而在實際過程當中,若是人數很少而且數量是肯定的,還好處理;若是人數不少且數量也不固定,那就很難經過這種方式投票決定了,效率過低。咱們須要經過一種機制篩選出最有表明性的人,在共識算法中就是篩選出具備表明性的節點。服務器

  那如何篩選呢?其實就是設置一組條件,給一組指標讓你們來完成,誰能更好地完成指標,誰就能有機會被選上。在區塊鏈系統中,存在着多種這樣的篩選方案,即各類共識算法。網絡

各類不一樣的算法,其實就是不一樣的遊戲玩法。架構



CFT:Crash Fault Tolerance

  即故障/崩潰容錯,是非拜占庭問題的容錯技術。併發



BFT:Byzantine Fault Tolerance

拜占庭將軍問題:http://www.javashuo.com/article/p-noemjrkw-cs.html

拜占庭假設是對現實世界的模型化,因爲硬件錯誤、網絡擁塞或中斷以及遭到惡意攻擊等緣由,計算機和網絡可能出現不可預料的行爲。拜占庭容錯技術就是用來處理這些異常行爲的。

在分佈式系統中,特別是在區塊鏈網絡環境中,也和拜占庭將軍的環境相似,有運行正常的服務器(相似忠誠的拜占庭將軍),有故障的服務器,還有破壞者的服務器(相似叛變的拜占庭將軍)。共識算法的核心是在正常的節點間造成對網絡狀態的共識。一般,這些發生故障的節點被稱爲拜占庭節點,而正常的節點即爲非拜占庭節點

  • 拜占庭容錯系統是一個擁有n臺節點的系統,整個系統對於每個請求,知足如下條件:
  1. 全部非拜占庭節點使用相同的輸入信息,產生一樣的結果;

  2. 若是輸入的信息正確,那麼全部非拜占庭節點必須接收這個信息,並計算相應的結果。

  • 拜占庭系統廣泛採用的假設條件包括:
  1. 拜占庭節點的行爲能夠是任意的,拜占庭節點之間能夠共謀;

  2. 節點之間的錯誤是不相關的;

  3. 節點之間經過異步網絡鏈接,網絡中的消息可能丟失、亂序並延時到達,但大部分協議假設消息在有限的時間裏能傳達到目的地;

  4. 服務器之間傳遞的信息,第三方能夠嗅探到,可是不能篡改、僞造信息的內容和驗證信息的完整性。

原始的拜占庭容錯系統因爲須要展現其理論上的可行性而缺少實用性。另外,還須要額外的時鐘同步機制支持算法的複雜度也是隨節點增長而指數級增長


PBFT:Practical Byzantine Fault Tolerance

  實用拜占庭容錯系統(PBFT)下降了拜占庭協議的運行復雜度,從指數級別下降到多項式級別(Polynomial),使拜占庭協議在分佈式系統中應用成爲可能。

  PBFT是一種狀態機副本複製算法,即服務做爲狀態機進行建模,狀態機在分佈式系統的不一樣節點進行副本複製。每一個狀態機的副本都保存了服務的狀態,同時也實現了服務的操做。將全部的副本組成的集合使用大寫字母R表示,使用0到|R|-1的整數表示每個副本。爲了描述方便,一般假設故障節點數爲m個,整個服務節點數爲|R|=3m+1個,這裏m是有可能失效的副本的最大個數。儘管能夠存在多於3m+1個副本,可是額外的副本除了下降性能以外不能提升可靠性。

  PBFT要求共同維護一個狀態,全部節點採起的行動一致。爲此,須要運行三類基本協議:包括一致性協議、檢查點協議和視圖更換協議。咱們主要關注支持系統平常運行的一致性協議。一致性協議至少包含若干個階段:請求(request)、序號分配(pre-prepare)和響應(reply)。根據協議設計的不一樣,可能包含相互交互(prepare),序號確認(commit)等階段。

PBFT協議通訊模式

  上圖爲PBFT協議通訊模式,每個客戶端的請求須要通過5個階段,經過採用兩次兩兩交互的方式在服務器達成一致以後再執行客戶端的請求。因爲客戶端不能從服務器端得到任何服務器運行狀態的信息,PBFT中主節點是否發生錯誤只能由服務器監測。若是服務器在一段時間內都不能完成客戶端的請求,則會觸發視圖更換協議。其中C爲客戶端,N0~N3表示服務節點,特別的,N0爲主節點,N3爲故障節點。整個協議的基本過程以下:

  1. 客戶端發送請求,激活主節點的服務操做。

  2. 當主節點接收請求後,啓動三階段的協議以向各從節點廣播請求。

    2.1 序號分配階段:主節點給請求賦值一個序列號n,廣播序號分配消息和客戶端的請求消息m,並將構造PRE-PREPARE消息發送給各從節點

    2.2 交互階段:從節點接收PRE-PREPARE消息,並向其餘服務節點廣播PREPARE消息;

    2.3 序號確認階段:各節點對視圖內的請求和次序進行驗證後,廣播COMMIT消息,執行收到的客戶端的請求並給客戶端以響應。

  1. 客戶端等待來自不一樣節點的響應,如有 m+1 個響應相同,則該響應即爲運算的結果。

 

PBFT在不少場景都有應用,在區塊鏈場景中,通常適合於對強一致性有要求的私有鏈和聯盟鏈場景。例如,在IBM主導的區塊鏈超級帳本項目中,PBFT是一個可選的共識協議。在Hyperledger的Fabric項目中,共識模塊被設計成可插拔的模塊,支持像PBFT、Raft等共識算法。


POW:Proof of Work

從去中心化帳本系統的角度看,每一個加入這個系統的節點都要保存一份完整的帳本,但每一個節點卻不能同時記帳。由於節點處於不一樣的環境,接收到不一樣的信息,若是同時記帳的話,必然會致使帳本的不一致,形成混亂。所以,須要有共識來達成哪一個節點有權記帳。比特幣區塊鏈經過競爭記帳的方式解決去中心化記帳系統的一致性問題, 即以每一個節點的計算能力即「算力」來競爭記帳權的機制。 

在比特幣系統中,大約每10分鐘進行一輪算力競賽,競賽的勝利者,就得到一次記帳的權力,並向其餘節點同步新增帳本信息。然而,在一個去中心化的系統中,誰有權斷定競爭的結果呢?比特幣系統是經過一個稱爲「工做量證實」(Proof of Work,PoW)的機制完成的。

  簡單地說,PoW就是一份確認工做端作過必定量工做的證實。PoW系統的主要特徵是計算的不對稱性——工做端須要作必定難度的工做得出一個結果,驗證方卻很容易經過結果來檢查工做端是否是作了相應的工做。

  舉個例子,給定字符串「blockchain」,咱們給出的工做量要求是,能夠在這個字符串後面鏈接一個稱爲nonce的整數值串,對鏈接後的字符串進行SHA256哈希運算,若是獲得的哈希結果(以十六進制的形式表示)是以若干個0開頭的,則驗證經過。爲了達到這個工做量證實的目標,咱們須要不停地遞增nonce值,對獲得的新字符串進行SHA256哈希運算。按照這個規則,須要通過2688次計算才能找到前3位均爲0的哈希值,而要找到前6位均爲0的哈希值,則需進行620969次計算。

 1 blockchain1 → 4bfb943cba9fb9926df93f33c17d64b378d56714e8a29c6ba8bdc9690cea8e27  
 2 blockchain2 → 01181212a283e760929f6b1628d903127c65e6fb5a9ad7fe94b790e699269221 ……
 3 blockchain515 → 0074448bea8027bebd6333d3aa12fd11641e051911c5bab661a9b849b83958a7……
 4 blockchain2688 → 0009b257eb8cf9eba179ab2be74d446fa1c59f0adfa8814260f52ae0016dd50f……
 5 blockchain48851: 00000b3d96b4db1a976d3a69829aabef8bafa35ab5871e084211a16d3a4f385c……
 6 blockchain6200969: 000000db7fa334aef754b51792cff6c880cd286c5f490d5cf73f658d9576d424

  經過上面這個計算特定SHA256運算結果的示例,咱們對PoW機制有了一個初步的理解。對於特定字符串後接隨機nonce值所構成的串,要找到這樣的nonce值,知足前n位均爲0的SHA256值,須要屢次進行哈希值的計算。通常來講,n值越大,須要完成的哈希計算量也越大。因爲哈希值的僞隨機特性,要尋找4個前導0的哈希值,預期大概要進行216次嘗試,這個數學指望的計算次數,就是所要求的「工做量」。

  比特幣網絡中任何一個節點,若是想生成一個新的區塊並寫入區塊鏈,必須解出比特幣網絡出的PoW問題。這道題關鍵的3個要素是工做量證實函數、區塊及難度值。工做量證實函數是這道題的計算方法,區塊決定了這道題的輸入數據,難度值決定了這道題所須要的計算量。

  1.工做量證實函數 及 區塊數據計算過程

  比特幣系統中使用的工做量證實函數就是SHA256

  比特幣區塊結構以下圖所示:

  比特幣的區塊由區塊頭及該區塊所包含的交易列表組成。區塊頭的大小爲80字節,由4字節的版本號、32字節的上一個區塊的哈希值、32字節的Merkle根哈希值、4字節的時間戳(當前時間)、4字節的當前難度值、4字節的隨機數組成。區塊包含的交易列表則附加在區塊頭後面,其中的第一筆交易是coinbase交易,這是一筆爲了讓礦工得到獎勵及手續費的特殊交易

  擁有80字節固定長度的區塊頭,就是用於比特幣工做量證實的輸入字符串。所以,爲了使區塊頭能體現區塊所包含的全部交易,在區塊的構造過程當中,須要將該區塊要包含的交易列表,經過Merkle樹算法生成Merkle根哈希值,並以此做爲交易列表的哈希值存到區塊頭中。其中Merkle樹的算法圖解以下圖所示。

  

  上圖展現了一個具備4個交易記錄的Merkle樹的根哈希值的計算過程。首先以這4個交易做爲葉子結點構造一棵徹底二叉樹,而後經過哈希值的計算,將這棵二叉樹轉化爲Merkle樹。

首先對4個交易記錄:Txa~Txd,分別計算各自的哈希值HA~HD,而後計算兩個中間節點的哈希值HAB=Hash(HA+HB) 和 HCD=Hash(HC+HD),最後計算出根節點的哈希值HABCD=Hash(HAB+HCD)。

  構造出來的簡化的區塊鏈結構如上圖所示。We find that: 全部在給定時間範圍內須要記錄的交易信息被構形成一個Merkle樹,區塊中包含了指向這個Merkle樹的哈希指針,關聯了與該區塊相關的交易數據。同時,區塊中也包含了指向前一區塊的哈希指針,使得記錄了不一樣交易的單個區塊被關聯起來,造成區塊鏈。

  2.挖礦難度

  難度值是比特幣系統中的節點在生成區塊時的重要參考指標,它決定了節點大約須要通過多少次哈希運算才能產生一個合法的區塊。比特幣的區塊大約每10分鐘生成一個,若是要在不一樣的全網算力條件下,新區塊的產生都基本保持這個速率,難度值必須根據全網算力的變化進行調整。簡單地說,難度值被設定在不管節點計算能力如何,新區塊產生速率都保持在每10分鐘一個。

  難度的調整是在每一個完整節點中獨立自動發生的。每2016個區塊,全部節點都會按統一的公式自動調整難度,這個公式是由最新2016個區塊的花費時長與指望時長(指望時長爲20160分鐘,即兩週,是按每10分鐘一個區塊的產生速率計算出的總時長)比較得出的,根據實際時長與指望時長的比值,進行相應調整(或變難或變易)。也就是說,若是區塊產生的速率比10分鐘快則增長難度,比10分鐘慢則下降難度。 

這個公式能夠總結爲:新難度值=舊難度值×(過去2016個區塊花費時長/20160分鐘)

比特幣工做量證實的目標值(Target)的計算公式:目標值=最大目標值/難度值

其中最大目標值爲一個恆定值:0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

  目標值的大小與難度值成反比。比特幣工做量證實的達成就是礦工計算出來的區塊哈希值必須小於目標值。

  3.PoW過程 

  比特幣PoW的過程,能夠簡單理解成就是將不一樣的nonce值做爲輸入,嘗試進行SHA256哈希運算,找出知足給定數量前導0的哈希值的過程。而要求的前導0的個數越多,表明難度越大。比特幣節點求解工做量證實問題的步驟大體概括以下:

  1)生成鑄幣交易,並與其餘全部準備打包進區塊的交易組成交易列表,經過Merkle樹算法生成Merkle根哈希;

  2)把Merkle根哈希及其餘相關字段組裝成區塊頭,將區塊頭的80字節數據做爲工做量證實的輸入;

  3)不停地變動區塊頭中的隨機數,即nonce的數值,並對每次變動後的區塊頭作雙重SHA256運算(即SHA256(SHA256(Block_Header))),將結果值與當前網絡的目標值作對比,若是小於目標值,則解題成功,工做量證實完成。

比特幣的工做量證實,就是俗稱「挖礦」所作的主要工做。

  4.PoW可否解決拜占庭將軍問題 

  關於比特幣PoW共識機制可否解決拜占庭將軍問題一直在業界有爭議。2015年,Juan Garay對比特幣的PoW共識算法進行了正式的分析,得出的結論是比特幣的PoW共識算法是一種機率性的拜占庭協議(Probabilistic BA)。Garay對比特幣共識協議的兩個重要屬性分析以下。

  1)一致性(Agreement)

  在不誠實節點總算力小於50%的狀況下,同時每輪同步區塊生成的概率不多的狀況下,誠實的節點具備相同的區塊的機率很高。用數學的嚴格語言說應該是:當任意兩個誠實節點的本地鏈條截取K個節點,兩條剩下的鏈條的頭區塊不相同的機率隨着K的增長呈指數型遞減。

  2)正確性(Validity)

  大多數的區塊必須由誠實節點提供。嚴格來講,當不誠實算力很是小的時候,才能使大多數區塊由誠實節點提供。

  所以能夠看到,當不誠實的算力小於網絡總算力的50%時,同時挖礦難度比較高,在大約10分鐘出一個區塊狀況下,比特幣網絡達到一致性的概念會隨確認區塊的數目增多而呈指數型增長。但當不誠實算力具必定規模,甚至不用接近50%的時候,比特幣的共識算法並不能保證正確性,也就是,不能保證大多數的區塊由誠實節點來提供。

  所以,咱們能夠看到,比特幣的共識算法不適合於私有鏈和聯盟鏈。其緣由首先是它是一個最終一致性共識算法,不是一個強一致性共識算法。第二個緣由是其共識效率低。提供共識效率又會犧牲共識協議的安全性。另外,比特幣經過巧妙的礦工獎勵機制來提高網絡的安全性。礦工挖礦得到比特幣獎勵以及記帳所得的交易費用使得礦工更但願維護網絡的正常運行,而任何破壞網絡的非誠信行爲都會損害礦工自身的利益。所以,即便有些比特幣礦池具有強大的算力,它們都沒有做惡的動機,反而有動力維護比特幣的正常運行,由於這和它們的切實利益相關。

  PoW機制存在明顯的弊端。一方面,PoW的前提是,節點和算力是均勻分佈的,由於經過CPU的計算能力來進行投票,擁有錢包(節點)數和算力值應該是大體匹配的,然而隨着人們將CPU挖礦逐漸升級到GPU、FPGA,直至ASIC礦機挖礦,節點數和算力值也漸漸失配。另外一方面,PoW太浪費了。比特幣網絡每秒可完成數百萬億次SHA256計算,但這些計算除了使惡意攻擊者不能輕易地假裝成幾百萬個節點和打垮比特幣網絡,並無更多實際的科學價值。固然,相對於容許世界上任何一我的在瞬間就能經過去中心化和半匿名的全球貨幣網絡,給其餘人幾乎沒有手續費地轉帳所帶來的巨大好處,它的浪費也許只算是很小的代價。

  有鑑於此,人們提出了權益證實(Proof of Stake,PoS)。


POS:Proof of Stake

PoS股權證實相似於財產儲存在銀行,這種模式會根據你持有數字貨幣的量和時間,分配給你相應的利息。   簡單來講,就是一個根據你持有貨幣的量和時間,給你發利息的一個制度,在股權證實PoS模式下,有一個名詞叫幣齡,每一個幣天天產生1幣齡,好比你持有100個幣,總共持有了30天,那麼,此時你的幣齡就爲3000。這個時候,若是你發現了一個PoS區塊,你的幣齡就會被清空爲0。你每被清空365幣齡,你將會從區塊中得到0.05個幣的利息(假定利息可理解爲年利率5%),那麼在這個案例中,利息 = 3000 * 5% / 365 = 0.41個幣,這下就頗有意思了,持幣有利息。

  點點幣(Peercoin)是首先採用權益證實的貨幣,點點幣在SHA256的哈希運算的難度方面引入了幣齡的概念,使得難度與交易輸入的幣齡成反比。在點點幣中,幣齡被定義爲幣的數量與幣所擁有的天數的乘積,這使得幣齡可以反映交易時刻用戶所擁有的貨幣數量。實際上,點點幣的權益證實機制結合了隨機化與幣齡的概念,未使用至少30天的幣能夠參與競爭下一區塊,越久和越大的幣集有更大的可能去簽名下一區塊。

  然而,一旦幣的權益被用於簽名一個區塊,則幣齡將清爲零,這樣必須等待至少30日才能簽署另外一區塊。同時,爲防止很是老或很是大的權益控制區塊鏈,尋找下一區塊的最大機率在90天后達到最大值,這一過程保護了網絡,並隨着時間逐漸生成新的幣而無需消耗大量的計算能力。點點幣的開發者聲稱這將使得惡意攻擊變得困難,由於沒有中心化的挖礦池需求,並且購買半數以上的幣的開銷彷佛超過得到51%的工做量證實的哈希計算能力。

  權益證實必須採用某種方法定義任意區塊鏈中的下一合法區塊,依據帳戶結餘來選擇將致使中心化,例如單個首富成員可能會擁有長久的優點。爲此,人們還設計了其餘不一樣的方法來選擇下一合法區塊。

  PoS機制雖然考慮到了PoW的不足,但依據權益結餘來選擇,會致使首富帳戶的權力更大,有可能支配記帳權。股份受權證實機制(Delegated Proof of Stake,DPoS)的出現正是基於解決PoW機制和PoS機制的這類不足。


DPOS:Delegated Proof of Stake

比特股(Bitshare)是一類採用DPoS機制的密碼貨幣,它指望經過引入一個技術民主層來減小中心化的負面影響。

  比特股的DPoS機制,中文名叫作股份受權證實機制(又稱受託人機制),它的原理是讓每個持有比特股的人進行投票,由此產生101位表明 , 咱們能夠將其理解爲101個超級節點或者礦池,而這101個超級節點彼此的權利是徹底相等的。從某種角度來看,DPOS有點像是議會制度或人民表明大會制度。若是表明不能履行他們的職責(當輪到他們時,沒能生成區塊),他們會被除名,網絡會選出新的超級節點來取代他們。

DPOS的出現最主要仍是由於礦機的產生,大量的算力在不瞭解也不關心比特幣的人身上,相似演唱會的黃牛,大量囤票而絲絕不關心演唱會的內容。

  比特股引入了見證人這個概念,見證人能夠生成區塊,每個持有比特股的人均可以投票選舉見證人。獲得總贊成票數中的前N個(N一般定義爲101)候選者能夠當選爲見證人,當選見證人的個數(N)需知足:至少一半的參與投票者相信N已經充分地去中心化。

  見證人的候選名單每一個維護週期(1天)更新一次。見證人隨機排列,每一個見證人按序有2秒的權限時間生成區塊,若見證人在給定的時間片不能生成區塊,區塊生成權限交給下一個時間片對應的見證人。DPoS的這種設計使得區塊的生成更爲快速,也更加節能。

  DPoS充分利用了持股人的投票,以公平民主的方式達成共識。他們投票選出的N個見證人,能夠視爲N個礦池,而這N個礦池彼此的權利是徹底相等的。持股人能夠隨時經過投票更換這些見證人(礦池),只要他們提供的算力不穩定,計算機宕機,或者試圖利用手中的權力做惡。

比特股還設計了另一類競選,表明競選。選出的表明擁有提出改變網絡參數的特權,包括交易費用、區塊大小、見證人費用和區塊區間。若大多數表明贊成所提出的改變,持股人有兩週的審查期,這期間能夠罷免表明並廢止所提出的改變。這一設計確保表明技術上沒有直接修改參數的權利以及全部網絡參數的改變最終需獲得持股人的贊成。


Raft協議:

(Raft分佈式共識算法可視化/動畫教程:http://thesecretlivesofdata.com/raft/)

在這些分佈式系統的實用場景下,其假設條件不須要考慮拜占庭故障,而只是處理通常的死機故障。在這種狀況下,採用Paxos等協議會更加高效。Paxos是Lamport設計的保持分佈式系統一致性的協議。但因爲Paxos很是複雜,比較難以理解,所以後來出現了各類不一樣的實現和變種。Raft是由Stanford提出的一種更易理解的一致性算法,意在取代目前廣爲使用的Paxos算法。目前,在各類主流語言中都有了一些開源實現,好比本文中將使用的基於JGroups的Raft協議實現。

  Raft最初是一個用於管理複製日誌的共識算法,它是一個爲真實世界應用創建的協議,主要注重協議的落地性和可理解性。Raft是在非拜占庭故障下達成共識的強一致協議。

  在區塊鏈系統中,使用Raft實現記帳共識的過程能夠描述以下:首先選舉一個leader,接着賦予leader徹底的權力管理記帳。leader從客戶端接收記帳請求,完成記帳操做,生成區塊,並複製到其餘記帳節點。leader簡化了記帳操做的管理。例如,leader可以決定是否接受新的交易記錄項而無需考慮其餘的記帳節點,leader可能失效或與其餘節點失去聯繫,這時,系統就會選出新的leader。

在Raft中,每一個結點會處於下面三種狀態中的一種:

  • follower:全部結點都以follower的狀態開始。若是沒收到leader消息則會變成candidate狀態

  • candidate:會向其餘結點「拉選票」,若是獲得大部分的票則成爲leader。這個過程就叫作Leader選舉(Leader Election)

  • leader:全部對系統的修改都會先通過leader。每一個修改都會寫一條日誌(log entry)。leader收到修改請求後的過程以下,這個過程叫作日誌複製(Log Replication):

    • 複製日誌到全部follower結點(replicate entry)

    • 大部分結點響應時才提交日誌

    • 通知全部follower結點日誌已提交

    • 全部follower也提交日誌

    • 如今整個系統處於一致的狀態

Raft階段主要分爲兩個,首先是leader選舉過程,而後在選舉出來的leader基礎上進行正常操做,好比日誌複製、記帳等。

 

1.Leader Election/領導人選舉

  當follower在選舉超時時間內未收到leader的心跳消息,則轉換爲candidate狀態。爲了不選舉衝突,這個超時時間是一個150~300ms之間的隨機數

通常而言,在Raft系統中:

1)任何一個服務器均可以成爲一個候選者candidate,它向其餘服務器follower發出要求選舉本身的請求。

2)其餘服務器贊成了,發出OK。注意,<u>若是在這個過程當中,有一個follower宕機,沒有收到請求選舉的要求,此時候選者能夠本身選本身,只要達到N/2+1的大多數票,候選人仍是能夠成爲leader的</u>。

3)這樣這個候選者就成爲了leader領導人,它能夠向選民也就是follower發出指令,好比進行記帳。

4)之後經過心跳進行記帳的通知。

5)一旦這個leader崩潰了,那麼follower中有一個成爲候選者,併發出邀票選舉。

6)follower贊成後,其成爲leader,繼續承擔記帳等指導工做。

 

2.Log Replication/日誌複製

Raft的記帳過程按如下步驟完成:

1)假設leader領導人已經選出,這時客戶端發出增長一個日誌的要求;

2)leader要求follower聽從他的指令,都將這個新的日誌內容追加到他們各自日誌中;

3)大多數follower服務器將交易記錄寫入帳本後,確認追加成功,發出確認成功信息;

4)在下一個心跳中,leader會通知全部follower更新確認的項目。

對於每一個新的交易記錄,重複上述過程。

  在這一過程當中,若發生網絡通訊故障,使得leader不能訪問大多數follower了,那麼leader只能正常更新它能訪問的那些follower服務器。而大多數的服務器follower由於沒有了leader,他們將從新選舉一個候選者做爲leader,而後這個leader做爲表明與外界打交道。若是外界要求其添加新的交易記錄,這個新的leader就按上述步驟通知大多數follower。當網絡通訊恢復,原先的leader就變成follower,在失聯階段,這個老leader的任何更新都不能算確認,必須所有回滾,接收新的leader的新的更新。


Ripple共識算法:

Ripple(瑞波)是一種基於互聯網的開源支付協議,能夠實現去中心化的貨幣兌換、支付與清算功能。在Ripple的網絡中,交易由客戶端(應用)發起,通過追蹤節點(tracking node)或驗證節點(validating node)把交易廣播到整個網絡中。追蹤節點的主要功能是分發交易信息以及響應客戶端的帳本請求。驗證節點除包含追蹤節點的全部功能外,還可以經過共識協議,在帳本中增長新的帳本實例數據。  

  Ripple的共識達成發生在驗證節點之間,每一個驗證節點都預先配置了一份可信任節點名單,稱爲UNL(Unique Node List)。在名單上的節點可對交易達成進行投票。每隔幾秒,Ripple網絡將進行以下共識過程:

1)每一個驗證節點會不斷收到從網絡發送過來的交易,經過與本地帳本數據驗證後,不合法的交易直接丟棄,合法的交易將彙總成交易候選集(candidate set)。交易候選集裏面還包括以前共識過程沒法確認而遺留下來的交易。

2)每一個驗證節點把本身的交易候選集做爲提案發送給其餘驗證節點。

3)驗證節點在收到其餘節點發來的提案後,若是不是來自UNL上的節點,則忽略該提案;若是是來自UNL上的節點,就會對比提案中的交易和本地的交易候選集,若是有相同的交易,該交易就得到一票。在必定時間內,當交易得到超過50%的票數時,則該交易進入下一輪。沒有超過50%的交易,將留待下一次共識過程去確認。  

4)驗證節點把超過50%票數的交易做爲提案發給其餘節點,同時提升所需票數的閾值到60%,重複步驟3)、步驟4),直到閾值達到80%。

5)驗證節點把通過80%UNL節點確認的交易正式寫入本地的帳本數據中,稱爲最後關閉帳本(Last Closed Ledger),即帳本最後(最新)的狀態

Ripple共識過程節點交互示意圖:

Ripple共識算法流程:

  在Ripple的共識算法中,參與投票的節點身份是事先知道的。所以,算法的效率比PoW等匿名共識算法要高效,交易的確認時間只需幾秒鐘。固然,這點也決定了該共識算法只適合於許可鏈(Permissioned chain)的場景。Ripple共識算法的拜占庭容錯(BFT)能力爲 (n-1)/5,便可以容忍整個網絡中20%的節點出現拜占庭錯誤而不影響正確的共識。


Paxos算法:

Paxos算法的目的是爲了解決分佈式環境下的一致性問題。

多個節點併發操縱數據,如何保證在讀寫過程當中數據的一致性,而且解決方案要能適應分佈式環境下的不可靠性(系統如何就一個值達到統一)

Paxos的兩個組件:

Proposer

提議發起者,處理客戶端請求,將客戶端的請求發送到集羣中,以便決定這個值是否能夠被批准。

Acceptor

提議批准者,負責處理接收到的提議,他們的回覆就是一次投票。會存儲一些狀態來決定是否接收一個值

Paxos有兩個原則:

  1. 安全原則---保證不能作錯的事

  • 針對某個實例的表決只能有一個值被批准,不能出現一個被批准的值被另外一個值覆蓋的狀況;(假設有一個值被多數Acceptor批准了,那麼這個值就只能被學習)

  • 每一個節點只能學習到已經被批准的值,不能學習沒有被批准的值。

  1. 存活原則---只要有多數服務器存活而且彼此間能夠通訊,最終都要作到的下列事情:

  • 最終會批准某個被提議的值;

  • 一個值被批准了,其餘服務器最終會學習到這個值。

 

Paxos具體流程圖

第一階段(Prepare)

  1. 獲取一個proposal number, n;

  2. 提議者向全部節點廣播prepare(n)請求;

  3. 接收者(Acceptors比較善變,若是還沒最終承認一個值,它就會不斷認同提案號最大的那個方案)比較n和minProposal,若是n>minProposal,表示有更新的提議minProposal=n;若是此時該接受者並無承認一個最終值,那麼承認這個提案,返回OK。若是此時已經有一個accptedValue, 將返回(acceptedProposal,acceptedValue);

  4. 提議者接收到過半數請求後,若是發現有acceptedValue返回,表示有承認的提議,保存最高acceptedProposal編號的acceptedValue到本地

 

第二階段 (Accept)

  1. 廣播accept(n,value)到全部節點;

  2. 接收者比較n和minProposal,若是n>=minProposal,則acceptedProposal=minProposal=n,acceptedValue=value,本地持久化後,返回;

    不然,拒絕而且返回minProposal。

  1. 提議者接收到過半數請求後,若是發現有返回值>n,表示有更新的提議,跳轉1(從新發起提議);不然value達成一致。

 

Paxos提案ID生成算法

在Google的Chubby論文中給出了這樣一種方法:假設有n個proposer,每一個編號爲ir(0<=ir<n),proposal編號的任何值s都應該大於它已知的最大值,而且知足:
 ​
  s %n = ir    =>     s = m*n + ir
 ​
 proposer已知的最大值來自兩部分:proposer本身對編號自增後的值和接收到acceptor的拒絕後所獲得的值。
例: 以3個proposer P一、P二、P3爲例,開始m=0,編號分別爲0,1,2。

1) P1提交的時候發現了P2已經提交,P2編號爲1 >P1的0,所以P1從新計算編號:new P1 = 1*3+1 = 4;

2) P3以編號2提交,發現小於P1的4,所以P3從新編號:new P3 = 1*3+2 = 5。

  

Paxos原理

任意兩個法定集合,一定存在一個公共的成員。該性質是Paxos有效的基本保障

 

活鎖

  當某一proposer提交的proposal被拒絕時,多是由於acceptor 承諾返回了更大編號的proposal,所以proposer提升編號繼續提交。 若是2個proposer都發現本身的編號太低轉而提出更高編號的proposal,會致使死循環,這種狀況也稱爲活鎖。
  好比說當此時的 proposer1提案是3, proposer2提案是4, 但acceptor承諾的編號是5,那麼此時proposer1,proposer2 都將提升編號假設分別爲6,7,並試圖與accceptor鏈接,假設7被接受了,那麼提案5和提案6就要從新編號提交,從而不斷死循環。

 

異常狀況——持久存儲

  在算法執行的過程當中會產生不少的異常狀況:proposer宕機,acceptor在接收proposal後宕機,proposer接收消息後宕機,acceptor在accept後宕機,learn宕機,存儲失敗,等等。
 ​
  爲保證paxos算法的正確性,proposer、aceptor、learn都實現持久存儲,以作到server恢復後仍能正確參與paxos處理。
 ​
 propose存儲已提交的最大proposal編號、決議編號(instance id)。
 ​
 acceptor存儲已承諾(promise)的最大編號、已接受(accept)的最大編號和value、決議編號。
 ​
 learn存儲已學習過的決議和編號

 

具體實例:

假設的3軍問題

1) 1支紅軍在山谷裏紮營,在周圍的山坡上駐紮着3支藍軍;

2) 紅軍比任意1支藍軍都要強大;若是1支藍軍單獨做戰,紅軍勝;若是2支或以上藍軍同時進攻,藍軍勝;

3) 三支藍軍須要同步他們的進攻時間;但他們唯一的通訊媒介是派通訊兵步行進入山谷,在那裏他們可能被俘虜,從而將信息丟失;或者爲了不被俘虜,可能在山谷停留很長時間;

4) 每支軍隊有1個參謀負責提議進攻時間;每支軍隊也有1個將軍批准參謀提出的進攻時間;很明顯,1個參謀提出的進攻時間須要得到至少2個將軍的批准纔有意義;

5) 問題:是否存在一個協議,可以使得藍軍同步他們的進攻時間?

 

接下來以兩個假設的場景來演繹BasicPaxos;參謀和將軍須要遵循一些基本的規則:

1) 參謀以兩階段提交(prepare/commit)的方式來發起提議,在prepare階段須要給出一個編號;

2) 在prepare階段產生衝突,將軍以編號大小來裁決,編號大的參謀勝出;

3) 參謀在prepare階段若是收到了將軍返回的已接受進攻時間,在commit階段必須使用這個返回的進攻時間;

 

兩個參謀前後提議的場景

1) 參謀1發起提議,派通訊兵帶信給3個將軍,內容爲(編號1);

2) 3個將軍收到參謀1的提議,因爲以前尚未保存任何編號,所以把(編號1)保存下來,避免遺忘;同時讓通訊兵帶信回去,內容爲(ok);

3) 參謀1收到至少2個將軍的回覆,再次派通訊兵帶信給3個將軍,內容爲(編號1,進攻時間1);

4) 3個將軍收到參謀1的時間,把(編號1,進攻時間1)保存下來,避免遺忘;同時讓通訊兵帶信回去,內容爲(Accepted);

5) 參謀1收到至少2個將軍的(Accepted)內容,確認進攻時間已經被你們接收;

6) 參謀2發起提議,派通訊兵帶信給3個將軍,內容爲(編號2);

7) 3個將軍收到參謀2的提議,因爲(編號2)比(編號1)大,所以把(編號2)保存下來,避免遺忘;又因爲以前已經接受參謀1的提議,所以讓通訊兵帶信回去,內容爲(編號1,進攻時間1);

8) 參謀2收到至少2個將軍的回覆,因爲回覆中帶來了已接受的參謀1的提議內容,參謀2所以再也不提出新的進攻時間,接受參謀1提出的時間。

 

兩個參謀交叉提議的場景

1) 參謀1發起提議,派通訊兵帶信給3個將軍,內容爲(編號1);

2) 3個將軍的狀況以下:

a) 將軍1和將軍2收到參謀1的提議,將軍1和將軍2把(編號1)記錄下來,若是有其餘參謀提出更小的編號,將被拒絕;同時讓通訊兵帶信回去,內容爲(ok);

b) 負責通知將軍3的通訊兵被抓,所以將軍3沒收到參謀1的提議;

 

3) 參謀2在同一時間也發起了提議,派通訊兵帶信給3個將軍,內容爲(編號2);

4) 3個將軍的狀況以下

a) 將軍2和將軍3收到參謀2的提議,將軍2和將軍3把(編號2)記錄下來,若是有其餘參謀提出更小的編號,將被拒絕;同時讓通訊兵帶信回去,內容爲(ok);

b) 負責通知將軍1的通訊兵被抓,所以將軍1沒收到參謀2的提議;

 

5) 參謀1收到至少2個將軍的回覆,再次派通訊兵帶信給有答覆的2個將軍,內容爲(編號1,進攻時間1);

6) 2個將軍的狀況以下:

a) 將軍1收到了(編號1,進攻時間1),和本身保存的編號相同,所以把(編號1,進攻時間1)保存下來;同時讓通訊兵帶信回去,內容爲(Accepted);

b) 將軍2收到了(編號1,進攻時間1),因爲(編號1)小於已經保存的(編號2),所以讓通訊兵帶信回去,內容爲(Rejected,編號2);

 

7) 參謀2收到至少2個將軍的回覆,再次派通訊兵帶信給有答覆的2個將軍,內容爲(編號2,進攻時間2);

8) 將軍2和將軍3收到了(編號2,進攻時間2),和本身保存的編號相同,所以把(編號2,進攻時間2)保存下來,同時讓通訊兵帶信回去,內容爲(Accepted);

9) 參謀2收到至少2個將軍的(Accepted)內容,確認進攻時間已經被多數派接受;

10) 參謀1只收到了1個將軍的(Accepted)內容,同時收到一個(Rejected,編號2);參謀1從新發起提議,派通訊兵帶信給3個將軍,內容爲(編號3);

11) 3個將軍的狀況以下:

a) 將軍1收到參謀1的提議,因爲(編號3)大於以前保存的(編號1),所以把(編號3)保存下來;因爲將軍1已經接受參謀1前一次的提議,所以讓通訊兵帶信回去,內容爲(編號1,進攻時間1);

b) 將軍2收到參謀1的提議,因爲(編號3)大於以前保存的(編號2),所以把(編號3)保存下來;因爲將軍2已經接受參謀2的提議,所以讓通訊兵帶信回去,內容爲(編號2,進攻時間2);

c) 負責通知將軍3的通訊兵被抓,所以將軍3沒收到參謀1的提議;

12) 參謀1收到了至少2個將軍的回覆,比較兩個回覆的編號大小,選擇大編號對應的進攻時間做爲最新的提議;參謀1再次派通訊兵帶信給有答覆的2個將軍,內容爲(編號3,進攻時間2);

13) 將軍1和將軍2收到了(編號3,進攻時間2),和本身保存的編號相同,所以保存(編號3,進攻時間2),同時讓通訊兵帶信回去,內容爲(Accepted);

14) 參謀1收到了至少2個將軍的(accepted)內容,確認進攻時間已經被多數派接受。 


小蟻共識機制:

小蟻共識機制經過股權持有人投票選舉,來決定記帳人及其數量;被選出的記帳人完成每一個區塊內容的共識,決定其中所應包含的交易。

蟻記帳機制稱爲中性記帳。PoW/PoS/DPoS解決誰有記帳權的問題,而中性記帳則側重於解決如何限制記帳人權力的問題。在中性記帳的共識機制下,記帳人只有權力選擇是否參與的權力,而不能改變交易數據,不能人爲排除某筆交易,也不能人爲對交易進行排序

小蟻的中性記帳區塊鏈能夠作到:

  • 每15秒產生一個區塊,優化後有望達到小於5秒;

  • 單個記帳人不能拒絕包含某筆交易進入當前區塊;

  • 每一個確認由全體記帳人蔘與,一個確認就是徹底確認;

  • 結合超導機制,記帳人不能經過構造交易來搶先成交牟利。

     

    小蟻股權持有人能夠發起記帳人交易,對所選擇數量的(1~1024個)候選記帳人進行投票支持。通常認爲,記帳人應該實名化,候選記帳人應該經過其餘信道提供能證實其真實身份的數字證書。

    小蟻協議實時統計全部投票,並計算出當前所需記帳人的認數和記帳人名單。爲肯定所需記帳人數,將全部選票按支持人數排序,按所持小蟻股權的權重取中間的50%,而後求算術平均值。當人數不足最低標準時,啓用系統預置的後備記帳人來頂替。所需記帳人數肯定後,按由高到低的得票數肯定記帳人名單。

    咱們以區塊隨機數的生成來了解小蟻共識機制。

    每一個區塊生成前,記帳人之間須要協做生成一個區塊隨機數。小蟻使用沙米爾祕密共享方案(Shamir's Secret Sharing Scheme, SSSS)來協做生成隨機數。

    依據SSSS方案,能夠將密文S生成N份密文碎片,持有其中的K份,就能還原出密文S。小蟻記帳人(假設爲N+1個)之間經過如下3步對隨機數達成共識:

    1. 自選一個隨機數,將此隨機數經過SSSS方案生成N份碎片,用其餘N個記帳人的公鑰加密,並廣播;

    2. 收到其餘N個記帳人的廣播後,將其中本身可解密的部分解密,並廣播;

    3. 收集到至少K份密文碎片後,解出隨機數;得到全部記帳人的隨機數後,合併生成區塊隨機數。

       

  區塊隨機數由各個記帳人協同生成,只要有一個誠實的記帳人蔘與其中,那麼即使其餘全部記帳人合謀,也沒法預測或構造此隨機數。

  在上述區塊隨機數生成第一步的廣播中,記帳人還同時廣播其認爲應該寫入本區塊的每筆交易的哈希值。其餘記帳人偵聽到廣播後,檢查本身是否具備該交易哈希值的對應數據,若是沒有則向其餘節點請求。

  當區塊隨機數產生後,每一個記帳人合併全部第一步廣播中的交易(剔除只有哈希值單沒法獲取交易數據的交易),並簽名。得到2/3的記帳人簽名,則本區塊完成;不然共識失敗,轉回隨機數共識的第一步,再次嘗試。

相關文章
相關標籤/搜索