開源一個千萬級多組Raft庫 - Dragonboat

向你們介紹Dragonboat,一個開源的Go實現的多組Raft庫,項目已Apache2協議下開源。歡迎你們試用,也請你們點star鼓勵https://github.com/lni/dragonboatgit

通俗的講,這是一個分佈式共識協議庫,應用能夠用它把數據分佈存儲於多臺機器上,只要過半數的機器在線,數據與服務即可在線。這避免了因個別機器當機或網絡故障而形成數據、服務不可用,提升系統可用性。它提供稱爲Linearizability的強一致特性:多個副本的數據在外部看來更像使用單一副本,不會有僅提供最終一致性的系統常見且難纏的讀到舊版數據的問題。github

基於Raft協議的共識庫已經應用於不少互聯網後臺系統。接觸了不少用戶之後,廣泛反饋的當前應用障礙是缺少一個可靠、高性能、且對共識協議自己接近全透明的開箱即用的通用實現。數據庫

優點安全

Dragonboat已經較好的解決全部上述應用障礙:性能優化

  • 測試最完備的開源Raft庫之一,全部的實現代碼、測試工具、測試結果均已開源。
  • 吞吐性能最好的開源Raft庫,千萬級每秒實現,平均單核即達每秒40萬次以上寫吞吐。
  • 功能最完備的開源Raft庫,不作特殊應用假設限制,安全可靠前提下最大程度確保通用性。

同時,Dragonboat的Go實現通過大量具體性能優化打磨,在當前高性能Go系統在行業內需求持續劇增的背景下,爲準備入坑的同窗踩坑帶路提供參考。服務器

 

功能與使用網絡

Dragonboat實現了Raft論文中說起的幾乎全部功能,是當前最完備的Raft協議的Go實現:併發

  • 選主與複製
  • 快照
  • 基於ReadIndex協議的高性能強一致讀
  • 主節點轉移
  • 無投票權節點
  • 節點靜默
  • Quorum自查
  • 對應用透明的冪等更新支持
  • 全異步的執行與快照操做

Dragonboat的使用十分方便。與etcd Raft庫不一樣,Dragonboat無需用戶參與任何Raft協議狀態有關的操做,最大程度下降Raft的使用成本與人爲錯誤機率。用戶首先實現一個IStateMachine接口用以描述更新與查詢請求的執行方法,該接口僅四個方法必須實現,分別用於更新、查詢StateMachine,以及對StateMachine建立與恢復快照。實際項目經驗發現,一個簡單的內存上的Key-Value數據庫,它的StateMachine幾分鐘就能做出一個原型。異步

有了上述IStateMachine實例,即可根據應用需求使用Dragonboat的應用API接口提出各種請求,系統將嚴格經過Raft協議規定的要求處理各用戶請求,並最終提交至用戶的IStateMachine實例完成狀態更新與查詢的執行。分佈式

Dragonboat自帶的詳細中文例程能夠在十幾分鍾那讓用戶瞭解整個使用流程,近距離觀察共識協議給系統所帶來的fault-tolerance容錯特性,並實際操做體驗如發起Proposal、強一致讀、Raft組成員變動、節點重啓等系統功能。

設計與實現概述

Dragonboat的核心組件是分佈在網絡各服務器上的NodeHost,一般每臺服務器一個NodeHost實例,用以分配使用計算、存儲與通信資源,並管理運行於該服務器上的來自各不一樣Raft組的成員節點。

NodeHost同時提供一個facade interface,用以提供所支持的各服務,用戶可以使用其API完成各支持的功能,如發起讀寫或成員變動請求,啓動或中止某成員節點,請求主節點轉移或查詢當前組成員等等。請使用上一段提供的例程的連接,具體瞭解NodeHost的使用。

各Raft成員節點內含下列實例:

  • Raft協議狀態
  • Raft組成員
  • 應用IStateMachine
  • 用於支持冪等更新的Session狀態

其中應用IStateMachine由用戶提供實現,其他皆爲系統實現並對用戶徹底透明。

爲了原生支持大量Raft組,各種batching與pipelining優化手段被仔細的落實到每一個細節,如驅動各Raft組更新執行的執行引擎就是最好例子。以寫(propose)爲例,以下圖所示,各Raft組被分配到不一樣的執行shard上,以提供parallelism,每一個shard又是一個多級流水線,不一樣處理階段不一樣性質(IO密集、內存訪問密集等)的處理在流水線不一樣級間併發完成,充分利用concurrency優點將全部消息傳遞、執行更新等操做異步化。

Dragonboat的Log存儲組件稱爲LogDB,默認使用RocksDB,但可方便替換爲其它Key-Value store方案。默認的RocksDB適配僅350行Go代碼。NodeHost間消息傳輸由稱爲Raft RPC的組件完成,系統提供了默認的TCP與gRPC兩個實現,它們均支持Mutual TLS,同時也可方便地適配其它傳輸方案。

 

測試與正確性檢查

Dragonboat通過及其嚴格的測試。相對於用宣傳式口號稱讚軟件如何可靠,下列具體數字和事實相信更具備說服力:

  • 每晚千萬次規模,歷時一年多共百億次規模的隨機行爲組合下的節點重啓與網絡partition恢復測試,發現並糾正了諸多包括etcd亦存在的Raft實現錯誤
  • 數萬行全手寫高覆蓋測試代碼,Raft協議核心3000行代碼便有高達萬行測試代碼護航
  • 移植並經過了全部etcd raft相關測試代碼,覆蓋etcd累積的各種可能的小几率意外狀況
  • 系統的測試方法:單元與集成測試,Jepsen測試,fuzz隨機輸入測試,隨機組合行爲測試,I/O錯誤注入測試,文件系統掉電測試
  • 全面的檢查:linearizability檢查,應用狀態機狀態一致、Raft組成員一致、Raft組可用、磁盤上Raft Log Entry一致

隨機行爲組合測試中,保存了部分Raft組的I/O歷史數據,可經過Jepsen的Knossos工具進行系統的Linearizability檢查,這些數據也已開源

 

性能分析

在22核2.8GHz的三組服務器間,對16字節的負載,當使用48個Raft組,Dragonboat能夠持續每秒900萬次的寫入,或在9:1的高讀寫比場景下持續進行每秒1100萬次的混合讀寫操做。跨地域高延遲場景下,高吞吐依舊被保持。

 

活躍組的數量增長會由於batching變得更困難而直接下降吞吐,但吞吐始終是百萬數量級的。大量的空閒組則不會顯著影響吞吐。

下表是Dragonboat的寫延遲數據。在每秒800萬次16字節寫的狀況下,P99寫延遲依舊小於5毫秒。得益於ReadIndex協議無需落盤寫的特性,讀延遲一般狀況下顯著小於寫延遲。

Go的GC具備全部主流語言中最低的STW停頓,這對延遲及延遲離散度敏感場景及其重要。在每秒千萬請求的壓力下,STW停頓爲400微秒。在Go 1.12中,該延遲將繼續減半。下圖是120個連續GC週期的全部STW停頓時長,該測試場景下每秒平均3個GC週期。

Dragonboat爲多組Raft而優化,單Raft組性能還沒有經任何優化。當前版本,單Raft組場景下可持續每秒125萬次的16字節的寫,平均延遲爲1.3毫秒,P99延遲2.6毫秒。三組服務器共佔用9個2.8GHz CPU核心,平均每臺服務器佔用3個2.8GHz的CPU核心。

相關文章
相關標籤/搜索