HBase Replication詳解

小米運維發表於2019-06-25

本文從全域性出發,詳細講解了HBase的Replication和Replication Endpoint的用法及實踐。

往期文章回顧:一文讀懂HBase多租戶

Replication:複製,指的是持續的將同一份資料拷貝到多個地方進行儲存,是各種儲存系統中常見而又重要的一個概念,可以指資料庫中主庫和從庫的複製,也可以指分散式叢集中多個叢集之間的複製,還可以指分散式系統中多個副本之間的複製。它的難點在於資料通常是不斷變化的,需要持續的將變化也反映到多個資料拷貝上,並保證這些拷貝是完全一致的。

通常來說,資料複製到多個拷貝上有如下好處:

  • 多個備份提高了資料的可靠性

  • 通過主從資料庫/主備叢集之間的複製,來分離OLTP和OLAP請求

  • 提高可用性,即使在單副本掛掉的情況下,依然可以有其他副本來提供讀寫服務

  • 可擴充套件,通過增加副本來服務更多的讀寫請求

  • 跨地域資料中心之間的複製,Client通過讀寫最近的資料中心來降低請求延遲

HBase中的Replication指的是主備叢集間的複製,用於將主叢集的寫入記錄複製到備叢集。HBase目前共支援3種Replication,分別是非同步Replication、序列Replication和同步Replication。

非同步Replication

如果想把HBase的Replication搞清楚,首先需要了解下HBase的架構。

HBase叢集是由一組程式組成的,程式按角色分為Master和RegionServer,其中Master負責DDL操作,比如建表、刪表,而RegionServer負責DML操作,比如資料的讀寫操作等。從資料檢視上講,HBase中的Table會按Range切分為多個Region,然後由不同的RegionServer來負責對外提供服務。

HBase Replication詳解

RegionServer的內部則主要有BlockCache,MemStore和WAL等幾部分組成,需要注意的是每個Region的每個Column Family有自己獨享的MemStore,但是BlockCache和WAL則是多個Region共享的。WAL(Write-ahead logging)是資料庫中的常用技術,所有的修改在寫入資料庫之前都需要持久化到WAL中,從而確保了在出現故障的時候,可以從WAL中回放出已經成功寫入的資料。

HBase Replication詳解

HBase中的Replication也是基於WAL的,其在主叢集的每個RegionServer程式內部起了一個叫做ReplicationSource的執行緒來負責Replication,同時在備叢集的每個RegionServer內部起了一個ReplicationSink的執行緒來負責接收Replication資料。ReplicationSource記錄需要同步的WAL佇列,然後不斷讀取WAL中的內容,同時可以根據Replication的配置做一些過濾,比如是否要複製這個表的資料等,然後通過replicateWALEntry這個Rpc呼叫來傳送給備叢集的RegionServer,備叢集的ReplicationSink執行緒則負責將收到的資料轉換為put/delete操作,以batch的形式寫入到備叢集中。

HBase Replication詳解

因為是後臺執行緒非同步的讀取WAL並複製到備叢集,所以這種Replication方式叫做非同步Replication,正常情況下備叢集收到最新寫入資料的延遲在秒級別。

序列Replication

序列Replication指的是:對於某個Region來說,嚴格按照主叢集的寫入順序複製到備叢集,其是一種特殊的Replication。同時預設的非同步Replication不是序列的,主要原因是Region是可以移動的,比如HBase在進行負載均衡時移動Region。假設RegionA首先在RegionServer1上,然後其被移動到了RegionServer2上,由於非同步Replication是存在延遲的,所以RegionA的最後一部分寫入記錄還沒有完全複製到備叢集上。在Region移動到RegionServer2之後,其開始接收新的寫入請求,並由RegionServer2來複制到備叢集,所以在這個時候RegionServer1和RegionServer2會同時向備叢集進行復制,而且寫入記錄複製到備叢集的順序是不確定的。

HBase Replication詳解

如上圖所示這種極端情況下,還會導致主備叢集資料的不一致。比如RegionServer1上最後一個未同步的寫入操作是Put,而RegionA被移動到RegionServer2上的第一個寫入操作是Delete,在主叢集上其寫入順序是先Put後Delete,如果RegionServer2上的Delete操作先被複制到了備叢集,然後備叢集做了一次Major compaction,其會刪除掉這個Delete marker,然後Put操作才被同步到了備叢集,因為Delete已經被Major compact掉了,這個Put將永遠無法被刪除,所以備叢集的資料將會比主叢集多。

解決這個問題的關鍵在於需要確保RegionServer2上的新寫入操作必須在RegionServer1上的寫入操作複製完成之後再進行復制。所以序列Replication引入了一個叫做Barrier的概念,每當Region open的時候,就會寫入一個新的Barrier,其值是Region open時讀到的最大SequenceId加1。SequenceId是HBase中的一個重要概念,每個Region都有一個SequenceId,其隨著資料寫入嚴格遞增,同時SequenceId會隨著每次寫入操作一起寫入到WAL中。所以當Region移動的時候,Region會在新的RegionServer重新開啟,這時就會寫入一個新的Barrier,Region被移動多次之後,就會寫入多個Barrier,來將Region的寫入操作劃分成為多個區間。同時每個Region都維護了一個lastPushedSequenceId,其代表這個Region當前推送成功的最後一個寫操作的SequenceId,這樣就可以根據Barrier列表和lastPushedSequenceId來判斷WAL中的一個寫入操作是否能夠複製到備叢集了。

HBase Replication詳解

以上圖為例,Pending的寫入記錄就需要等待lastPushedSequenceId推到Barrier2之後才能開始複製。由於每個區間之間只會有一個RegionServer來負責複製,所以只有和lastPushedSequenceId在同一個區間內的RegionServer才能進行復制,並在複製成功後不斷更新lastPushedSequenceId,而在lastPushedSequenceId之後各個區間的RegionServer則需要等待lastPushedSequenceId被推到自己區間的起始Barrier,然後才能開始複製,從而確保了Region的寫入操作可以嚴格按照主叢集的寫入順序序列的複製到備叢集。

同步Replication

同步Replication是和非同步Replication對稱的概念,其指的是主叢集的寫入操作必須被同步的寫入到備叢集中。非同步Replication的最大問題在於複製是存在延遲的,所以在主叢集整叢集掛掉的情況下,備叢集是沒有已經寫入的完整資料的,對於一致性要求較高的業務來說,是不能把讀寫完全切到備叢集的,因為在這個時候可能存在部分最近寫入的資料無法從備叢集讀到。所以同步Replication的核心思路就是在寫入主叢集WAL的同時,在備叢集上寫入一份RemoteWAL,只有同時在主叢集的WAL和備叢集的RemoteWAL寫入成功了,才會返回給Client說寫入成功。這樣當主叢集掛掉的時候,便可以在備叢集上根據Remote WAL來回放出來主叢集上所有寫入記錄,從而確保備叢集和主叢集資料的一致。

HBase Replication詳解

需要注意的是,同步Replication是在非同步Replication的基礎之上的,也就是說非同步Replication的複製鏈路還會繼續保留,同時增加了新的寫Remote WAL的步驟。對於具體的實現細節來說,首先是增加了一個Sync replication state的概念,其總共有三個狀態, 分別是Active,Downgrade Active和Standby。這幾個狀態的轉換關係如下圖所示,Standby在提主的時候需要首先提升為Downgrade Active,然後才能提升為Active。但是Active是可以直接降級為Standby的。目前這個狀態是儲存在ReplicationPeerConfig中的, 其表示一個叢集在這個ReplicationPeer中處於哪個狀態。

HBase Replication詳解

然後實現了一個DualAsyncFSWAL來同時寫主叢集的WAL和備份叢集的Remote WAL。寫WAL的操作是對於HDFS的rpc請求,其會有三種結果: 成功,失敗或者超時。當超時的時候,對於HBase來說結果是不確定的,即資料有可能成功寫入到WAL或Remote WAL裡了,也有可能沒有。只有同時寫成功或者同時寫失敗的時候,主叢集和備叢集才會有一樣的WAL,如果是主叢集寫WAL成功,寫Remote WAL失敗或者超時,這時候主叢集WAL裡的資料就有可能比備叢集的Remote WAL多。相反如果寫備叢集Remote WAL成功了,而主叢集的WAL寫失敗或者超時了,備叢集的Remote WAL裡的資料就有可能比主叢集多。當兩邊都超時的時候, 就不確定那邊多了。所以同步複製的關鍵就在於在上述情況下,如何確保主備叢集資料的最終一致。即在切換主備叢集的時候,Client應該始終從主備叢集看到一致的資料。而且在主備沒有達到一致的中間狀態時,需要一些限制來確保Client沒法讀到這種中間不一致的結果。所以總結一下就是主備叢集最終一致,但對於Client來說是強一致,即成功寫入的資料無論主備叢集都要一定能讀到。具體的實現細節可以參考HBaseCon Asia 2018:HBase at Xiaomi[1]。

HBase Replication詳解

對比非同步複製來看,同步複製主要是影響的寫路徑,從我們的測試結果上來看,大概會有14%的效能下降,後續計劃在HBASE-20422[2]中進行優化。

自定義Replication Endpoint

除了上述3種Replication之外,HBase還支援外掛式的Replication Endpoint,可以自定義Replication Endpoint來實現各種各樣的功能。具體到小米來說,我們實現了可以在不同表之間的Replication Endpoint,比如可以將主叢集的表A複製到備叢集的表B,其應用場景有叢集遷移,Namespace更換或者表名更換等。同時為了實現Point-in-time Recovery,我們做了可以同步資料到小米訊息佇列Talos的Replication Endpoint,當出現需要恢復某個時間點t1的場景時,可以首先找到冷備中距離t1最近的一個的Snapshot進行恢復,然後將訊息佇列中的資料來回放到t1時間點,從而做到Point-in-time Recovery。

最後,我們還做了類似DynamoDB Stream的功能[3],將使用者表的修改日誌複製到使用者自己的訊息佇列中,然後使用者可以依賴這份資料來做一些流式的資料處理。此外,HBase Read Replica功能,目前的一種實現方案就是依賴HBase Replication,通過外掛式的Replication Endpoint將主Replica的資料複製到其他Read Replica中,詳見HBASE-10070[4]。

以上就是HBase中各種各樣的Replication,如有錯誤,歡迎指正。

同時歡迎大家在業務場景中按需進行使用,大家也可以根據自己的特殊場景自定義新的Replication Endpoint,並歡迎貢獻到社群。

參考連結:

  1. https://www.slideshare.net/MichaelStack4/hbaseconasia2018-track13-hbase-at-xiaomi

  2. https://jira.apache.org/jira/browse/HBASE-20422

  3. https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Streams.html

  4. https://issues.apache.org/jira/browse/HBASE-10070

  5. https://mapr.com/blog/in-depth-look-hbase-architecture/

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559359/viewspace-2648711/,如需轉載,請註明出處,否則將追究法律責任。

相關文章