天天看點

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

作者:DataFunTalk

導讀 ClickHouse是一種用于快速分析大規模資料的技術,在資料分析場景中有着廣泛的應用。然而由于資料量和計算複雜性的增加,建構高可用性的ClickHouse叢集成為一項具有挑戰性的任務。RaftKeeper通過采用Raft分布式一緻性協定,實作高性能高可用的分布式共識服務。可以幫助企業建立可靠穩定的ClickHouse叢集,高效分析大規模資料。

本文就将介紹如何使用RaftKeeper建構跨機房高可用ClickHouse叢集。

全文目錄:

1. RaftKeeper項目簡介

2. 功能和架構

3. 性能優化

4. 跨機房架構

5. Q&A

分享嘉賓|吳建超 京東 架構師

編輯整理|阿東同學 中國科學院大學

内容稽核|李瑤

出品社群|DataFun

01

項目簡介

1. 項目背景

在ClickHouse中Zookeeper扮演着非常重要的角色,主要分為三個方面:首先是中繼資料存儲,包括表定義和Part資訊等。其次是記錄檔,包括插入、修改和Part合并等。最後是功能協調包括服務發現、分布式隊列和分布式鎖等。總結下來ClickHouse場景中對Zookeeper的使用有兩個特點:一資料量大;二請求吞吐量大。

然而由于Zookeeper的性能瓶頸,整個系統中存在一些問題,例如:高頻插入導緻表隻讀進而導緻插入失敗、分布式DDL逾時以及背景Parts 合并失敗等。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

随着京東ClickHouse規模的不斷擴大(目前擁有大幾千節點),這些問題在實際業務中變得越來越突出。當時我們發現社群也計劃開發keeper來代替Zookeeper,以此為契機,我們希望研發RaftKeeper以替代keeper,并貢獻給社群。為此,我們确定了RaftKeeper的項目目标。第一完全相容Zookeeper的使用者接口;第二相比于Zookeeper,吞吐量有大幅提升;第三我們還希望降低Zookeeper中一些會造成阻塞的因素,比如JVM的GC引發的STW阻塞、狀态機Map擴容引發的阻塞,以及MNTR指令的阻塞。目前RaftKeeper項目已經開源,大家可以在GitHub上可以檢視https://github.com/JDRaftKeeper/RaftKeeper。

2. Raft分布式共識算法

在介紹RaftKeeper前先簡單介紹一下Raft分布式共識算法。Raft的算法旨在解決分布式系統中副本之間資料的一緻性問題。相對于Paxos算法而言,它更易于了解,實作也更為簡單,并廣泛應用于資料系統,例如Kudu、TiDB、Etcd等。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

Raft 有兩個關鍵流程, leader選舉和日志複制,總體上,它隻有使用主節點節點進行寫操作,并且資料隻能單向從主節點流量從節點的方案,保證資料一緻性。

3. Why NuRaft?

在算法方面,我們并沒有從零開始實作,而是選擇了開源的NuRaft。主要有三點原因,第一在Raft算法的基礎上做了很多有益的拓展,包括了 Pro-Vote 機制、Leader 過期機制、Leader 指派機制,以及 Commit 和 Leader election quorum size,在實際生産環境中能避免很多問題。第二在工程實作方面,NuRaft 的第三方依賴比較少,代碼也非常優雅,有着非常良好的代碼示例。第三NuRaft 的 Pipeline 和 Batch 請求處理機制設計精良,對後續 RaftKeeper 系統的性能提升會有很大的幫助。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

4. RaftKeeper的核心特性

簡要介紹一下 RaftKeeper 項目及其核心特點。第一個特點是完全相容 Zookeeper 生态系統,包括用戶端監控管理工具也可以複用。第二個特點是高性能,寫入吞吐量是 Zookeeper 的兩倍,詳見Benchmark(https://github.com/JDRaftKeeper/RaftKeeper/blob/master/benchmark%2FBenchmark.md)。第三個特點是查詢更平穩,TP99表現更穩定。第四個特點是同一個session内的請求,用戶端會按照請求發出的順序收到響應。第五特點是使用了多路複用網絡模型,支援 30 萬個長連接配接同時線上。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

02

功能和架構

1. 功能介紹

第二部分介紹RaftKeeper的功能和架構。首先,在基礎功能方面,RaftKeeper與Zookeeper保持相容,目前支援了90%的最常見基礎指令,隻有少量很少使用的指令暫時沒有實作,未來我們會根據使用者需求考慮添加。在網絡協定方面與Zookeeper完全相容,舉兩個例子:第一個是握手協定的資料包格式,第二個是建立指令的資料包格式。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

在進階功能方面,RaftKeeper提供了Node Watch機制、特殊的節點和四字指令。Node Watch機制支援Zookeeper全部的節點事件:建立、删除、更新。特殊節點包括:Ephemeral節點、Sequential節點和Sequential Ephemeral節點。四字指令是用來RaftKeeper的監控機制,在RaftKeeper的實作中,其指令進行了優化,消除了Zookeeper mntr指令在大資料幾下引起的阻塞。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

2. 架構設計

RaftKeeper 的架構中,狀态機、LogStore、Snapshot 是最核心的子產品。狀态機是 RaftKeeper 的核心,實作了資料的存取、Watch Ephemeral節點等進階功能。LogStore和Snapshot是資料的持久化木塊,持久化采用了Snapshot+Binlog的方式。

在一緻性限制方面,RaftKeeper提供了兩種保障:第一,同一Session内的請求的響應按照請求發出的順序傳回;第二,整個使用者請求周期内的所有Session中,已經送出的事務按照送出順序來執行。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

3. Session内請求順序性保證

對于用戶端來說需要保證請求的順序性,是以RaftKeeper 需要保證session内的請求按照順序響應,在一個分布式系統中請求需要被多個節點處理,并且每個節點内有多個線程,session請求順序性保障是一個非常複雜的問題。

在RaftKeeper中,寫請求是按照流水線的方式執行,主要步驟有:IO子產品接收使用者請求,Forwarder子產品将使用者的寫請求轉發給Leader節點,Leader節點接收到請求後積攢成一個Batch,然後走Raft的log replication流程,最後由Processor子產品進行請求的處理,并傳回給用戶端。

在整個流水線執行過程中,如果每個環節都是單線程、單連結那麼響應的順序性是可以保證的,但是性能很差。為此我們抽象了Pipe Runner的概念,每個Pipe Runner包含一個線程、一個連結和一個執行隊列。對對整個執行pipeline來說,有一個全局的并行度,這裡假設是3,那麼Pipe Runner的id範圍是0-2,當請求在不同子產品間流轉的時候,每個子產品的Pipe Runner請求隻會流轉到id相同的下遊Pipe Runner,這樣建立起了一個管道,多個節點間的請求不會跨Pipe Runner執行。同時我們IO子產品在接受請求的時候通過哈希的方式将Session散列到Pipe Runner,在宏觀上保證了同一個Session的請求不會跨Pipe Runner執行,進而保證了寫請求響應的一緻性。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

對于讀請求直接發送給Processor來處理,沒有Pipeline沒有Log Replication流程,那麼如何保障讀寫請求混合場景的順序性?對于同一個Session内的請求,有全局的xid,xid是按照順序遞增的數字,在Processor内處理請求的時候按照xid的順序處理。這樣保證了混合場景的資料順序性。

4. 存儲結構

RaftKeeper 采用了Snapshot+Binlog的資料存儲方式。這兩種檔案都采用了分段存儲方式,将單個檔案大小控制在合理範圍,這種設計主要是考慮到降低大檔案傳輸時候的魯棒性。同僚檔案頭部設定了版本CRC校驗、壓縮等中繼資料字段以支援版本疊代、資料校驗和壓縮的功能需求。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

03

性能優化

1. 性能優化

接下來,将簡單介紹一些性能優化的例子。在Raft Keeper中,pipeline和batch執行是最重要的優化手段,這也是Raft論文中也有提到的核心優化方式。下面以送快遞的例子來說明pipeline和batch的優化原理。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

假設快遞員需要從倉庫将 100 個包裹運送至小區。第一種方式是一次隻運送一個包裹,這種方式最為低效。假設每個包裹的運送需要 1 小時,那麼運送全部 100 個包裹總共需要 100 個小時。

而第一種優化方式是采用批量運送的方法,即每次運送十個包裹。這樣,隻需要進行十趟運送,10 個小時即可完成任務,效率提升了 10 倍。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

對應在RaftKeeper中,我們使用專門的元件Accumulater來打包使用者的寫請求,以進行批處理。這樣,在請求處理的最初階段(Log Replication的流程中還會進行一次咱屁)就進行了贊批。

另一個優化方法是“接力運輸”。例如,假設我們增加了一個快遞員,他在路程中間繼續運輸,這兩個快遞員形成一種接力狀态,進而使時間縮短了一半,從10個小時縮短到了5個小時。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

對應到在RaftKeeper中,我們使用了流式處理機制來分段處理請求,進而大大提高了整個系統的吞吐量。

2. 請求延遲優化

接下來介紹幾個關于優化請求延遲的例子。第一個例子是狀态機的哈希表,采用了雙層哈希表的設計來降低哈希表擴容帶來的阻塞。假設我希望在哈希表擴容時控制阻塞時間在1秒以下,根據線上環境實驗,每個小哈希表的資料量不應超過500萬。如果我們希望支援1億個節點,那麼小哈希表的資料量可設定為16至32個。右側表格列出了每次單個哈希表在不同資料量級下進行擴容時所需消耗的時間。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

第二個優化延遲方面的例子是異步的快照機制,這是一個在開發中的優化。當RaftKeeper中的日志數量達到一定門檻值時,整個系統會建立快照,将資料全量存儲到磁盤上,以清理大量的日志資料。然而,建立快照會阻塞使用者的請求,這會導緻較大的阻塞。下圖的表格展示了,不同資料量級HDD磁盤上建立快照需要的時間,可以看出當snapshot大小為2000M時會有13秒的延遲,如果資料量達到幾千萬時,會造成100秒的阻塞。

為了解決這個問題,可以采用異步的快照機制,異步的快照消除了查詢的阻塞時間,但它也會帶來一些問題。在整個快照過程中,部分操作可能已經被應用到了快照中,但是當系統重新開機加載資料的時候,依然會執行這些操作,導緻部分日志可能會被應用兩次。,因為所有的寫請求都是幂等的,隻需要狀态機對不同的寫請求的沖突做出适當的處理即可。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

3. 上線效果

下面對比了Zookeeper和RaftKeeper在延遲和吞吐量兩個方面的表現, RaftKeeper在吞吐量方面提升了一倍,同時TP99表現更加穩定。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

RaftKeeper項目從2021年11月份左右開始上線,目前線上大約有60多個叢集。經過三次京東的大促考驗。RaftKeeper

大大緩解了ClickHouse高頻導數失敗的問題,下圖顯示了RaftKeeper上線前後導數失敗率情況。同時我們也逐漸擴大了主流叢集的規模,從之前的60個節點擴大到現在約200個節點。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

04

跨機房架構

最後來介紹一下 RaftKeeper 項目的應用案例,即 ClickHouse 跨機房高可用方案。該方案主要解決 ClickHouse 在跨機房應用時的高可用問題。傳統的跨機房高可用方案是設定兩個 ClickHouse 叢集,使用者在導數時需要同時導入兩個叢集,在故障發生時需要在兩個叢集之間進行切換。這種方案存在一些痛點,首先是成本問題,需要維護兩個叢集,并且浪費了導數時的伺服器資源與人力資源;其次,兩個叢集導數,它們的資料有可能不一緻。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

是以我們設計了 ClickHouse 跨叢集的方案,如上圖所示ClickHouse叢集部署在zone1 和zone2,每個zone包含2個副本。RaftKeeper 叢集部署在zone1、2、3,zone1、2各自部署兩個節點,zone3部署一個節點。

該架構保障機房級别的高可用,整個系統對外仍然可用。假設任意一個zone出現故障,比如第一個zone故障,另一個zone内的ClickHouse副本依然是完整的,并且可以對外提供服務,而對于 RaftKeeper 叢集來說,因為它擁有五個節點,在挂掉兩個節點後,依然剩餘了大多數節點,服務依然可以用。

為什麼選擇RaftKeeper而非Zookeeper?主要有兩個方面的原因:一是RaftKeeper性能和穩定性更佳;二是RaftKeeper支援手動指定leader所在的zone。例如在使用者導入資料時,如果導入zone1的ClickHouse副本,可以将RaftKeeper的leader指在zone1,這樣減少了跨機房轉發打來的延遲。

最後簡單介紹一下 RaftKeeper 項目與開源社群的關系。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

RaftKeeper 項目源自于 ClickHouse 社群,是其下遊項目。因為在我們開始項目的時候ClickHouse社群有研發Keeper的計劃,我們最開始的想法是貢獻給社群,但是在做了一些貢獻(如四字指令、會話逾時協商機制、重連等)之後,發現 RaftKeeper 項目與社群的 Keeper 項目的發展思路不同,RaftKeeper更傾向于在多場景中替換Zookeeper,比如HBase,是以我們決定獨立開發。在RaftKeeper的開發過程中,NuRaft社群給我們提供了很多幫助,同時我們也做了一些社群回饋,上圖中簡要列舉了幾個Pull Request ID。

以上就是本次分享的所有内容,謝謝大家。

04

Q&A

Q1:RaftKeeper再往後發展的話,和ClickHouse Keeper之間功能的一緻性、相容性方面是怎麼考慮的?

A:首先我們希望RaftKeeper能夠相容更多的Zookeeper使用場景,在公司内部,我們已經将 RaftKeeper 項目應用到更多的其他元件當中了。而ClickHouse keeper更傾向于更好地支援 ClickHouse 的場景,這是兩個元件發展思路的差別。但是整體上兩個元件的功能是一緻的。

RaftKeeper從ClickHouse社群分開後,目前還沒有進行過同步,但後續我們可能會考慮是否與ClickHouse社群溝通做一些同步或者合并,需要看RaftKeeper項目的發展情況。

Q2:ClickHouse也有自己的Keeper, RaftKeeper 相比于它的Keeper 的優勢在哪裡?

A:首先,性能方面吞吐量更高一些。雖然沒有直接與 ClickHouse Keeper 進行對比,但已經與 Zookeeper 進行了比較。結果顯示,Zookeeper 的寫性能是讀的兩倍。

其次,保障了Session内請求響應的順序性,與Zookeeper的語義保持一緻。Zookeeper 在用戶端加入嚴格的校驗機制,每個請求XID,用戶端接受到響應後會進行XID的校驗,如果XID不比對,就會抛出異常。

再次,使用了NIO網絡模型,經過測試可以同時支援約30萬個長連接配接。我們在HBase場景中,驗證了大量長連結同時線上的場景。

最後,在架構和内部機制上也有很大不同,比如會話管理和Pipeline、Batch理機制。

Q3:RaftKeeper 的生産環境的應用規模大概多大?對于 RaftKeeper 後續的規劃能不能簡單介紹一下?

A:在京東内部目前部署了60多套環境。至于後續項目規劃,首先我們會繼續嘗試将其适配并推廣到更多的應用場景中。

今天的分享就到這裡,謝謝大家。

京東RaftKeeper:建構跨機房高可用 OLAP 叢集

繼續閱讀