排序服務
受衆:架構師、排序服務管理員、通道創建者
本主題將概念性的介紹排序的概念、排序節點是如何與 Peer 節點交互的、它們在交易流程中如何所發揮作用以及當前可用的排序服務的實現方式,尤其關注 Raft 排序服務實現。
什麼是排序?
許多分佈式區塊鏈,如以太坊(Ethereum)和比特幣(Bitcoin),都是非許可鏈的,這意味着任何節點都可以參與共識過程,在共識過程中,交易被排序並捆綁成區塊。因爲這個事實,這些系統依靠概率共識算法最終保證賬本一致性高的概率,但仍容易受到不同的賬本(有時也稱爲一個賬本“分叉”),在網絡中不同的參與者對於交易順序有不同的觀點。
Hyperledger Fabric 的工作方式不同。它有一種稱爲排序節點的節點使交易有序,並與其他排序節點一起形成一個排序服務。因爲 Fabric 的設計依賴於確定性的共識算法,所以 Peer 節點所驗證的排序服務生成的任何區塊都是最終的和正確的。賬本不會像其他分佈式區塊鏈中那樣產生分叉。
除了促進確定性之外,排序節點還將鏈碼執行的背書(發生在節點)與排序分離,這在性能和可伸縮性方面給 Fabric 提供了優勢,消除了由同一個節點執行和排序時可能出現的瓶頸。
排序節點和通道配置
除了排序角色之外,排序節點還維護着允許創建通道的組織列表。此組織列表稱爲“聯盟”,列表本身保存在“排序節點系統通道”(也稱爲“排序系統通道”)的配置中。默認情況下,此列表及其所在的通道只能由排序節點管理員編輯。請注意,排序服務可以保存這些列表中的幾個,這使得聯盟成爲 Fabric 多租戶的載體。
排序節點還對通道執行基本訪問控制,限制誰可以讀寫數據,以及誰可以配置數據。請記住,誰有權修改通道中的配置元素取決於相關管理員在創建聯盟或通道時設置的策略。配置交易由排序節點處理,因爲它需要知道當前的策略集合,並根據策略來執行其基本的訪問控制。在這種情況下,排序節點處理配置更新,以確保請求者擁有正確的管理權限。如果有權限,排序節點將根據現有配置驗證更新請求,生成一個新的配置交易,並將其打包到一個區塊中,該區塊將轉發給通道上的所有節點。然後節點處理配置交易,以驗證排序節點批准的修改確實滿足通道中定義的策略。
排序節點和身份
與區塊鏈網絡交互的所有東西,包括節點、應用程序、管理員和排序節點,都從它們的數字證書和成員服務提供者(MSP)定義中獲取它們的組織身份。
有關身份和 MSP 的更多信息,請查看我們關於身份和成員的文檔。
與 Peer 節點一樣,排序節點屬於組織。也應該像 Peer 節點一樣爲每個組織使用單獨的證書授權中心(CA)。這個 CA 是否將作爲根 CA 發揮作用,或者您是否選擇部署根 CA,然後部署與該根 CA 關聯的中間 CA,這取決於您。
排序節點和交易流程
階段一:提案
從我們對 Peer 節點的討論中,我們已經看到它們構成了區塊鏈網絡的基礎,託管賬本,應用程序可以通過智能合約查詢和更新這些賬本。
具體來說,更新賬本的應用程序涉及到三個階段,該過程確保區塊鏈網絡中的所有節點保持它們的賬本彼此一致。
在第一階段,客戶端應用程序將交易提案發送給一組節點,這些節點將調用智能合約來生成一個賬本更新提案,然後背書該結果。背書節點此時不將提案中的更新應用於其賬本副本。相反,背書節點將向客戶端應用程序返回一個提案響應。已背書的交易提案最終將在第二階段經過排序生成區塊,然後在第三階段分發給所有節點進行最終驗證和提交。
要深入瞭解第一個階段,請參閱節點主題。
階段二:將交易排序並打包到區塊中
在完成交易的第一階段之後,客戶端應用程序已經從一組節點接收到一個經過背書的交易提案響應。現在是交易的第二階段。
在此階段,應用程序客戶端把包含已背書交易提案響應的交易提交到排序服務節點。排序服務創建交易區塊,這些交易區塊最終將分發給通道上的所有 Peer 節點,以便在第三階段進行最終驗證和提交。
排序服務節點同時接收來自許多不同應用程序客戶端的交易。這些排序服務節點一起工作,共同組成排序服務。它的工作是將提交的交易按定義好的順序安排成批次,並將它們打包成區塊。這些區塊將成爲區塊鏈的區塊!
區塊中的交易數量取決於區塊的期望大小和最大間隔時間相關的通道配置參數(確切地說,是 BatchSize
和 BatchTimeout
參數)。然後將這些區塊保存到排序節點的賬本中,並分發給已經加入通道的所有節點。如果此時恰好有一個 Peer 節點關閉,或者稍後加入通道,它將在重新連接到排序服務節點或與另一個 Peer 節點通信之後接收到這些區塊。我們將在第三階段看到節點如何處理這個區塊。
排序節點的第一個角色是打包提案的賬本更新。在本例中,應用程序 A1 向排序節點 O1 發送由 E1 和 E2 背書的交易 T1。同時,應用程序 A2 將 E1 背書的交易 T2 發送給排序節點 O1。O1 將來自應用程序 A1 的交易 T1 和來自應用程序 A2 的交易 T2 以及來自網絡中其他應用程序的交易打包到區塊 B2 中。我們可以看到,在 B2 中,交易順序是 T1、T2、T3、T4、T6、T5,但這可能不是這些交易到達排序節點的順序!(這個例子顯示了一個非常簡單的排序服務配置,只有一個排序節點。)
值得注意的是,一個區塊中交易的順序不一定與排序服務接收的順序相同,因爲可能有多個排序服務節點幾乎同時接收交易。重要的是,排序服務將交易放入嚴格的順序中,並且 Peer 節點在驗證和提交交易時將使用這個順序。
區塊內交易的嚴格排序使得 Hyperledger Fabric 與其他區塊鏈稍有不同,在其他區塊鏈中,相同的交易可以被打包成多個不同的區塊,從而形成一個鏈。在 Hyperledger Fabric 中,由排序服務生成的區塊是最終的。一旦一筆交易被寫進一個區塊,它在賬本中的地位就得到了保證。正如我們前面所說,Hyperledger Fabric 的最終性意味着沒有賬本分叉,也就是說,經過驗證的交易永遠不會被重寫或刪除。
我們還可以看到,雖然節 Peer 點執行智能合約並處理交易,而排序節點不會這樣做。到達排序節點的每個授權交易都被機械地打包在一個區塊中,排序節點不判斷交易的內容(前面提到的通道配置交易除外)。
在第二階段的最後,我們看到排序節點負責一些簡單但重要的過程,包括收集已提案的交易更新、排序並將它們打包成區塊、準備分發。
階段三:驗證和提交
交易工作流的第三個階段涉及到從排序節點到 Peer 節點的區塊的分發和隨後的驗證,這些區塊可能會被應用到賬本中。
第三階段排序節點將區塊分發給連接到它的所有 Peer 節點開始。同樣值得注意的是,並不是每個 Peer 節點都需要連接到一個排序節點,Peer 節點可以使用 gossip 協議將區塊關聯到其他節點。
每個節點將獨立地以確定的方式驗證區塊,以確保賬本保持一致。具體來說,通道中每個節點都將驗證區塊中的每個交易,以確保得到了所需組織的節點背書,也就是節點的背書和背書策略相匹配,並且不會因最初認可該事務時可能正在運行的其他最近提交的事務而失效。無效的交易仍然保留在排序節點創建的區塊中,但是節點將它們標記爲無效,並且不更新賬本的狀態。
排序節點的第二個角色是將區塊分發給 Peer 節點。在本例中,排序節點 O1 將區塊 B2 分配給節點 P1 和 P2。節點 P1 處理區塊 B2,在 P1 上的賬本 L1 中添加一個新區塊。同時,節點 P2 處理區塊 B2,從而將一個新區塊添加到 P2 上的賬本 L1中。一旦這個過程完成,節點 P1 和 P2 上的賬本 L1 就會保持一致的更新,並且每個節點都可以通知與之連接的應用程序交易已經被處理。
總之,第三階段看到的是由排序服務生成的區塊一致地應用於賬本。將交易嚴格地按區塊排序,允許每個節點驗證交易更新是否在整個區塊鏈網絡上一致地應用。
要更深入地瞭解階段三,請參閱節點主題。
排序服務實現
雖然當前可用的每個排序服務都以相同的方式處理交易和配置更新,但是仍然有幾種不同的實現可以在排序服務節點之間就嚴格的交易排序達成共識。
有關如何建立排序節點(無論該節點將在什麼實現中使用)的信息,請參閱關於建立排序節點的文檔。
-
Solo
排序服務的 Solo 實現就像它的名字一樣:它只具有一個排序節點。因此,它不是,也永遠不會是容錯的。出於這個原因,Solo 實現不能用於生產環境,但對於測試應用程序和智能合約,或者創建概念證明來說,它是一個很好的選擇。但是,如果您曾經希望將這個 PoC 網絡擴展到生產環境中,那麼您可能希望從單個節點 Raft 集羣開始,因爲它可以通過重新配置來添加其他節點。
-
Raft
作爲v1.4.1的新特性,Raft 是一種基於
etcd
中 Raft 協議實現的崩潰容錯(Crash Fault Tolerant,CFT)排序服務。Raft 遵循“領導者跟隨者”模型,這個模型中,在每個通道上選舉領導者節點,其決策被跟隨者複製。Raft 排序服務會比基於 Kafka 的排序服務更容易設置和管理,它的設計允許不同的組織爲分佈式排序服務貢獻節點。 -
Kafka
和基於 Raft 的排序類似,Apache Kafka 是一個 CFT 的實現,它使用“領導者和跟隨者”節點配置。Kafka 利用一個 ZooKeeper 進行管理。基於 Kafka 的排序服務從 Fabric v1.0開始就可以使用,但許多用戶可能會發現管理 Kafka 集羣的額外管理開銷令人生畏或不受歡迎。
Solo
如上所述,在開發測試、開發或概念驗證網絡時,單獨排序服務是一個不錯的選擇。出於這個原因,它是部署在我們構建第一個網絡教程中默認的排序服務,從其他網絡組件的角度來看, Solo 排序服務處理交易和更復雜的 Kafka 和 Raft 實現相同,同時節省了維護和升級多個節點和集羣的管理開銷。由於 Solo 排序服務不能容錯,因此永遠不應該認爲它是生產區塊鏈網絡的可行替代方案。對於只希望從 Solo 排序節點開始但將來可能希望增長的網絡,單節點 Raft 集羣是更好的選擇。
Raft
有關如何配置 Raft 排序服務的信息,請參閱有關配置 Raft 排序服務的文檔。
對於將用於生產網絡的排序服務,Fabric 實現了使用“領導者跟隨者”模型的 Raft 協議,領導者是在一個通道的排序節點中動態選擇的(這個集合的節點稱爲“批准者集合(consenter set)”),領導者將信息複製到跟隨者節點。Raft 被稱爲“崩潰容錯”是因爲系統可以承受節點的損失,包括領導者節點,前提是要剩餘大量的排序節點(稱爲“法定人數(quorum)”)。換句話說,如果一個通道中有三個節點,它可以承受一個節點的丟失(剩下兩個節點)。如果一個通道中有五個節點,則可以丟失兩個節點(剩下三個節點)。
從它們提供給網絡或通道的服務的角度來看,Raft 和現有的基於 Kafka 的排序服務(我們將在稍後討論)是相似的。它們都是使用領導者跟隨者模型設計的 CFT 排序服務。如果您是應用程序開發人員、智能合約開發人員或節點管理員,您不會注意到基於 Raft 和 Kafka 的排序服務之間的功能差異。然而,有幾個主要的差異值得考慮,特別是如果你打算管理一個排序服務:
- Raft 更容易設置。雖然 Kafka 有很多崇拜者,但即使是那些崇拜者也(通常)會承認部署 Kafka 集羣及其 ZooKeeper 集羣會很棘手,需要在 Kafka 基礎設施和設置方面擁有高水平的專業知識。此外,使用 Kafka 管理的組件比使用 Raft 管理的組件多,這意味着有更多的地方會出現問題。Kafka 有自己的版本,必須與排序節點協調。使用 Raft,所有內容都會嵌入到您的排序節點中。
- Kafka 和 Zookeeper 並不是爲了在大型網絡上運行。它們被設計爲 CFT,但應該在一組緊密的主機中運行。這意味着實際上,您需要有一個組織運行 Kafka 集羣。考慮到這一點,在使用 Kafka 時,讓不同組織運行排序節點不會給您帶來太多的分散性,因爲這些節點都將進入同一個由單個組織控制的 Kafka 集羣。使用 Raft,每個組織都可以有自己的排序節點參與排序服務,從而形成一個更加分散的系統。
- Raft 是原生支持的。雖然基於 Kafka 的排序服務目前與 Fabric 兼容,但用戶需要獲得相關的鏡像,並學習如何單獨使用 Kafka 和 ZooKeeper。同樣,對 Kafka 相關問題的支持是通過 Apache 來處理的,Apache 是 Kafka 的開源開發者,而不是 Hyperledge Fabric。另一方面,Fabric Raft 的實現已經開發出來了,並將在 Fabric 開發人員社區及其支持設備中得到支持。
- Kafka 使用一個服務器池(稱爲“Kafka 代理”),而且排序組織的管理員要指定在特定通道上使用多少個節點,但是 Raft 允許用戶指定哪個排序節點要部署到哪個通道。通過這種方式,節點組織可以確保如果他們也擁有一個排序節點,那麼這個節點將成爲該通道的排序服務的一部分,而不是信任並依賴一箇中心來管理 Kafka 節點。
- Raft 是向開發拜占庭容錯(BFT)排序服務邁出的第一步。正如我們將看到的,Fabric 開發中的一些決策是由這個驅動的。如果你對 BFT 感興趣,學習如何使用 Raft 應該可以慢慢過渡。
注意:與 Solo 和 Kafka 類似,在向客戶發送回執後 Raft 排序服務也可能會丟失交易。例如,如果領導者和跟隨者提供回執時同時崩潰。因此,應用程序客戶端應該監聽節點上的交易提交事件,而不是檢查交易的有效性。但是應該格外小心,要確保客戶機也能優雅地容忍在配置的時間內沒有交易提交超時。根據應用程序的不同,在這種超時情況下可能需要重新提交交易或收集一組新的背書。
Raft 概念
雖然 Raft 提供了許多與 Kafka 相同的功能(儘管它是一個簡單易用的軟件包)但它與 Kafka 的功能卻大不相同,它向 Fabric 引入了許多新的概念,或改變了現有的概念。
日誌條目(Log entry)。 Raft 排序服務中的主要工作單元是一個“日誌條目”,該項的完整序列稱爲“日誌”。如果大多數成員(換句話說是一個法定人數)同意條目及其順序,則我們認爲條目是一致的,然後將日誌複製到不同排序節點上。
批准者集合(Consenter set)。主動參與給定通道的共識機制並接收該通道的日誌副本的排序節點。這可以是所有可用的節點(在單個集羣中或在多個集羣中爲系統通道提供服務),也可以是這些節點的一個子集。
有限狀態機(Finite-State Machine,FSM)。Raft 中的每個排序節點都有一個 FSM,它們共同用於確保各個排序節點中的日誌序列是確定(以相同的順序編寫)。
法定人數(Quorum)。描述需要確認提案的最小同意人數。對於每個批准者集合,這是大多數節點。在具有五個節點的集羣中,必須有三個節點可用,纔能有一個法定人數。如果節點的法定人數因任何原因不可用,則排序服務集羣對於通道上的讀和寫操作都不可用,並且不能提交任何新日誌。
領導者(Leader)。這並不是一個新概念,正如我們所說,Kafka 也使用了領導者,但是在任何給定的時間,通道的批准者集合都選擇一個節點作爲領導者,這一點非常重要(我們稍後將在 Raft 中描述這是如何發生的)。領導者負責接收新的日誌條目,將它們複製到跟隨者的排序節點,並在認爲提交了某個條目時進行管理。這不是一種特殊類型的排序節點。它只是排序節點在某些時候可能扮演的角色,而不是由客觀環境決定的其他角色。
跟隨者(Follower)。再次強調,這不是一個新概念,但是理解跟隨者的關鍵是跟隨者從領導者那裏接收日誌並複製它們,確保日誌保持一致。我們將在關於領導者選舉的部分中看到,跟隨者也會收到來自領導者的“心跳”消息。如果領導者在一段可配置的時間內停止發送這些消息,跟隨者將發起一次領導者選舉,它們中的一個將當選爲新的領導者。
交易流程中的 Raft
每個通道都在 Raft 協議的單獨實例上運行,該協議允許每個實例選擇不同的領導者。這種配置還允許在集羣由不同組織控制的排序節點組成的用例中進一步分散服務。雖然所有 Raft 節點都必須是系統通道的一部分,但它們不一定必須是所有應用程序通道的一部分。通道創建者(和通道管理員)能夠選擇可用排序節點的子集,並根據需要添加或刪除排序節點(只要一次只添加或刪除一個節點)。
雖然這種配置以冗餘心跳消息和線程的形式產生了更多的開銷,但它爲 BFT 奠定了必要的基礎。
在 Raft 中,交易(以提案或配置更新的形式)由接收交易的排序節點自動路由到該通道的當前領導者。這意味着 Peer 節點和應用程序在任何特定時間都不需要知道誰是領導者節點。只有排序節點需要知道。
當排序節點檢查完成後,將按照我們交易流程的第二階段的描述,對交易進行排序、打包成區塊、協商並分發。
架構說明
Raft 是如何選舉領導者的
儘管選舉領導者的過程發生在排序節點的內部過程中,但是值得注意一下這個過程是如何工作的。
節點總是處於以下三種狀態之一:跟隨者、候選人或領導者。所有節點最初都是作爲跟隨者開始的。在這種狀態下,他們可以接受來自領導者的日誌條目(如果其中一個已經當選),或者爲領導者投票。如果在一段時間內沒有接收到日誌條目或心跳(例如,5秒),節點將自己提升到候選狀態。在候選狀態中,節點從其他節點請求選票。如果候選人獲得法定人數的選票,那麼他就被提升爲領導者。領導者必須接受新的日誌條目並將其複製到跟隨者。
要了解領導者選舉過程的可視化表示,請查看數據的祕密生活。
快照
如果一個排序節點宕機,它如何在重新啓動時獲得它丟失的日誌?
雖然可以無限期地保留所有日誌,但是爲了節省磁盤空間,Raft 使用了一個稱爲“快照”的過程,在這個過程中,用戶可以定義日誌中要保留多少字節的數據。這個數據量將符合一定數量的區塊(這取決於區塊中的數據量。注意,快照中只存儲完整的區塊)。
例如,假設滯後副本 R1
剛剛重新連接到網絡。它最新的區塊是100
。領導者 L
位於第 196
塊,並被配置爲快照20個區塊。R1
因此將從 L
接收區塊180
,然後爲區塊101
到180
區塊發送
請求。然後180
到196
的區塊將通過正常 Raft 協議複製到 R1
。
Kafka
Fabric 支持的另一個容錯崩潰排序服務是對 Kafka 分佈式流平臺的改寫,將其用作排序節點集羣。您可以在 Apache Kafka 網站上閱讀更多關於 Kafka 的信息,但是在更高的層次上,Kafka 使用與 Raft 相同概念上的“領導者跟隨者”配置,其中交易(Kafka 稱之爲“消息”)從領導者節點複製到跟隨者節點。就像 Raft 一樣,在領導者節點宕機的情況下,一個跟隨者成爲領導者,排序可以繼續,以此來確保容錯。
Kafka 集羣的管理,包括任務協調、集羣成員、訪問控制和控制器選擇等,由 ZooKeeper 集合及其相關 API 來處理。
Kafka 集羣和 ZooKeeper 集合的設置是出了名的棘手,所以我們的文檔假設您對 Kafka 和 ZooKeeper 有一定的瞭解。如果您決定在不具備此專業知識的情況下使用 Kafka,那麼在試驗基於 Kafka 的排序服務之前,至少應該完成 Kafka 快速入門指南的前六個步驟。您還可以參考這個示例配置文件來簡要解釋 Kafka 和 ZooKeeper 的合理默認值。