向你們介紹Dragonboat,一個開源的Go實現的多組Raft庫,項目已Apache2協議下開源。歡迎你們試用,也請你們點star鼓勵:https://github.com/lni/dragonboatgit
通俗的講,這是一個分佈式共識協議庫,應用能夠用它把數據分佈存儲於多臺機器上,只要過半數的機器在線,數據與服務即可在線。這避免了因個別機器當機或網絡故障而形成數據、服務不可用,提升系統可用性。它提供稱爲Linearizability的強一致特性:多個副本的數據在外部看來更像使用單一副本,不會有僅提供最終一致性的系統常見且難纏的讀到舊版數據的問題。github
基於Raft協議的共識庫已經應用於不少互聯網後臺系統。接觸了不少用戶之後,廣泛反饋的當前應用障礙是缺少一個可靠、高性能、且對共識協議自己接近全透明的開箱即用的通用實現。數據庫
優點安全
Dragonboat已經較好的解決全部上述應用障礙:性能優化
同時,Dragonboat的Go實現通過大量具體性能優化打磨,在當前高性能Go系統在行業內需求持續劇增的背景下,爲準備入坑的同窗踩坑帶路提供參考。服務器
功能與使用網絡
Dragonboat實現了Raft論文中說起的幾乎全部功能,是當前最完備的Raft協議的Go實現:併發
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成員節點內含下列實例:
其中應用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通過及其嚴格的測試。相對於用宣傳式口號稱讚軟件如何可靠,下列具體數字和事實相信更具備說服力:
隨機行爲組合測試中,保存了部分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核心。