Replication:複製,指的是持續的將同一份數據拷貝到多個地方進行存儲,是各類存儲系統中常見而又重要的一個概念,能夠指數據庫中主庫和從庫的複製,也能夠指分佈式集羣中多個集羣之間的複製,還能夠指分佈式系統中多個副本之間的複製。它的難點在於數據一般是不斷變化的,須要持續的將變化也反映到多個數據拷貝上,並保證這些拷貝是徹底一致的。一般來講,數據複製到多個拷貝上有以下好處:html
多個備份提升了數據的可靠性數據庫
經過主從數據庫/主備集羣之間的複製,來分離OLTP和OLAP請求apache
提升可用性,即便在單副本掛掉的狀況下,依然能夠有其餘副原本提供讀寫服務架構
可擴展,經過增長副原本服務更多的讀寫請求負載均衡
跨地域數據中心之間的複製,Client經過讀寫最近的數據中心來下降請求延遲異步
HBase中的Replication指的是主備集羣間的複製,用於將主集羣的寫入記錄複製到備集羣。HBase目前共支持3種Replication,分別是異步Replication,串行Replication,和同步Replication。async
若是想把HBase的Replication搞清楚,首先須要瞭解下HBase的架構。HBase集羣是由一組進程組成的,進程按角色分爲Master和RegionServer,其中Master負責DDL操做,好比建表、刪表,而RegionServer負責DML操做,好比數據的讀寫操做等。從數據視圖上講,HBase中的Table會按Range切分爲多個Region,而後由不一樣的RegionServer來負責對外提供服務。分佈式
RegionServer的內部則主要有BlockCache,MemStore和WAL等幾部分組成,須要注意的是每一個Region的每一個Column Family有本身獨享的MemStore,可是BlockCache和WAL則是多個Region共享的。WAL(Write-ahead logging)是數據庫中的經常使用技術,全部的修改在寫入數據庫以前都須要持久化到WAL中,從而確保了在出現故障的時候,能夠從WAL中回放出已經成功寫入的數據。ide
HBase中的Replication也是基於WAL的,其在主集羣的每一個RegionServer進程內部起了一個叫作ReplicationSource的線程來負責Replication,同時在備集羣的每一個RegionServer內部起了一個ReplicationSink的線程來負責接收Replication數據。ReplicationSource記錄須要同步的WAL隊列,而後不斷讀取WAL中的內容,同時能夠根據Replication的配置作一些過濾,好比是否要複製這個表的數據等,而後經過replicateWALEntry這個Rpc調用來發送給備集羣的RegionServer,備集羣的ReplicationSink線程則負責將收到的數據轉換爲put/delete操做,以batch的形式寫入到備集羣中。性能
由於是後臺線程異步的讀取WAL並複製到備集羣,因此這種Replication方式叫作異步Replication,正常狀況下備集羣收到最新寫入數據的延遲在秒級別。
串行Replication指的是:對於某個Region來講,嚴格按照主集羣的寫入順序複製到備集羣,其是一種特殊的Replication。同時默認的異步Replication不是串行的,主要緣由是Region是能夠移動的,好比HBase在進行負載均衡時移動Region。假設RegionA首先在RegionServer1上,而後其被移動到了RegionServer2上,因爲異步Replication是存在延遲的,因此RegionA的最後一部分寫入記錄尚未徹底複製到備集羣上。在Region移動到RegionServer2以後,其開始接收新的寫入請求,並由RegionServer2來複制到備集羣,因此在這個時候RegionServer1和RegionServer2會同時向備集羣進行復制,並且寫入記錄複製到備集羣的順序是不肯定的。
如上圖所示這種極端狀況下,還會致使主備集羣數據的不一致。好比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中的一個寫入操做是否可以複製到備集羣了。
以上圖爲例,Pending的寫入記錄就須要等待lastPushedSequenceId推到Barrier2以後才能開始複製。因爲每一個區間之間只會有一個RegionServer來負責複製,因此只有和lastPushedSequenceId在同一個區間內的RegionServer才能進行復制,並在複製成功後不斷更新lastPushedSequenceId,而在lastPushedSequenceId以後各個區間的RegionServer則須要等待lastPushedSequenceId被推到本身區間的起始Barrier,而後才能開始複製,從而確保了Region的寫入操做能夠嚴格按照主集羣的寫入順序串行的複製到備集羣。
同步Replication是和異步Replication對稱的概念,其指的是主集羣的寫入操做必須被同步的寫入到備集羣中。異步Replication的最大問題在於複製是存在延遲的,因此在主集羣整集羣掛掉的狀況下,備集羣是沒有已經寫入的完整數據的,對於一致性要求較高的業務來講,是不能把讀寫徹底切到備集羣的,由於在這個時候可能存在部分最近寫入的數據沒法從備集羣讀到。因此同步Replication的核心思路就是在寫入主集羣WAL的同時,在備集羣上寫入一份RemoteWAL,只有同時在主集羣的WAL和備集羣的RemoteWAL寫入成功了,纔會返回給Client說寫入成功。這樣當主集羣掛掉的時候,即可以在備集羣上根據Remote WAL來回放出來主集羣上全部寫入記錄,從而確保備集羣和主集羣數據的一致。
須要注意的是,同步Replication是在異步Replication的基礎之上的,也就是說異步Replication的複製鏈路還會繼續保留,同時增長了新的寫Remote WAL的步驟。對於具體的實現細節來講,首先是增長了一個Sync replication state的概念,其總共有三個狀態, 分別是Active,Downgrade Active和Standby。這幾個狀態的轉換關係以下圖所示,Standby在提主的時候須要首先提高爲Downgrade Active,而後才能提高爲Active。可是Active是能夠直接降級爲Standby的。目前這個狀態是保存在ReplicationPeerConfig中的, 其表示一個集羣在這個ReplicationPeer中處於哪一個狀態。
而後實現了一個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]。
Async Replication |
Sync Replication |
|
Read Path |
No affect |
No affect |
Write Path |
No affect |
Write extra remote WAL |
Network bandwidth |
100% for async replication. |
100% for async + 100% for remote WAL. |
Storage space |
No affect |
Need extra space for remote WAL |
Eventual Consistency |
No if active cluster crashed |
Yes |
Availability |
Unavailable when master crash |
Few time for waiting replay remote log. |
Operational Complexity |
Simple |
More complex, Need to transition cluster state by hand or your services. |
對比異步複製來看,同步複製主要是影響的寫路徑,從咱們的測試結果上來看,大概會有14%的性能降低,後續計劃在HBASE-20422[2]中進行優化。
除了上述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,並歡迎貢獻到社區。
參考連接:
https://www.slideshare.net/MichaelStack4/hbaseconasia2018-track13-hbase-at-xiaomi
https://jira.apache.org/jira/browse/HBASE-20422
https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Streams.html
https://issues.apache.org/jira/browse/HBASE-10070
mapr.com/blog/in-dep…
本文首發於公衆號「小米雲技術」,轉載請標明出處,點擊查看原文連接。