HBase高可用原理與實踐
前言
前段時間有套線上HBase出了點小問題,導致該套HBase集群服務停止了2個小時,從而造成使用該套HBase作為數據存儲的應用也出現了 服務異常。在排查問題之余,我們不禁也在思考,以后再出現類似的問題怎么辦?這種問題該如何避免?用慣了MySQL,于是乎想到了HBase是否跟 MySQL一樣,也有其高可用方案?
答案當然是肯定的,幾乎所有的數據庫(無論是關系型還是分布式的),都采用WAL的方式來保障服務異常時候的數據恢復,HBase同樣也是通過 WAL來保障數據不丟失。HBase在寫數據前會先寫HLog,HLog中記錄的是所有數據的變動, HBase的高可用也正是通過HLog來實現的。
進階
HBase是一個沒有單點故障的分布式系統,上層(HBase層)和底層(HDFS層)都通過一定的技術手段,保障了服務的可用性。上層 HMaster一般都是高可用部署,而RegionServer如果出現宕機,region遷移的代價并不大,一般都在毫秒級別完成,所以對應用造成的影 響也很有限;底層存儲依賴于HDFS,數據本身默認也有3副本,數據存儲上做到了多副本冗余,而且Hadoop 2.0以后NameNode的單點故障也被消除。所以,對于這樣一個本身沒有單點故障,數據又有多副本冗余的系統,再進行高可用的配置是否有這個必要?會 不會造成資源的極大浪費?
高可用部署是否有必要,這個需要根據服務的重要性來定,這里先簡單介紹下沒有高可用的HBase服務會出現哪些問題:
- 數據庫管理人員失誤,進行了不可逆的DDL操作
不管是什么數據庫,DDL操作在執行的時候都需要慎之又慎,很可能一條簡單的drop操作,會導致所有數據的丟失,并且無法恢復,對于HBase來說也是這樣,如果管理員不小心drop了一個表,該表的數據將會被丟失。
- 離線MR消耗過多的資源,造成線上服務受到影響
HBase經過這么多年的發展,已經不再是只適合離線業務的數據存儲分析平臺,許多公司的線上業務也相繼遷移到了HBase上,比較典型的 如:非死book的iMessage系統、360的搜索業務、小米米聊的歷史數據等等。但不可避免在這些數據上做些統計分析類操作,大型MR跑起來, 會有很大的資源消耗,可能會影響線上業務。
- 不可預計的另外一些情況
比如核心交換機故障,機房停電等等情況都會造成HBase服務中斷
對于上述的那些問題,可以通過配置HBase的高可用來解決:
- 不可逆DDL問題
HBase的高可用不支持DDL操作,換句話說,在master上的DDL操作,不會影響到slave上的數據,所以即使在master上進行 了DDL操作,slave上的數據依然沒有變化。這個跟MySQL有很大不同,MySQL的DDL可以通過statement格式的Binlog進行復 制。
- 離線MR影響線上業務問題
高可用的最大好處就是可以進行讀寫分離,離線MR可以直接跑在slave上,master繼續對外提供寫服務,這樣也就不會影響到線上的業務,當然HBase的高可用復制是異步進行的,在slave上進行MR分析,數據可能會有稍微延遲。
- 意外情況
對于像核心交換機故障、斷電等意外情況,slave跨機架或者跨機房部署都能解決該種情況。
基于以上原因,如果是核心服務,對于可用性要求非常高,可以搭建HBase的高可用來保障服務較高的可用性,在HBase的Master出現異常時,只需簡單把流量切換到Slave上,即可完成故障轉移,保證服務正常運行。
原理
HBase高可用保證在出現異常時,快速進行故障轉移。下面讓我們先來看看HBase高可用的實現,首先看下官方的一張圖:
HBase Replication
需要聲明,HBase的replication是以Column Family為單位的,每個Column Family都可以設置是否進行replication。
上圖中,一個Master對應了3個Slave,Master上每個RegionServer都有一份HLog,在開啟Replication 的情況下,每個RegionServer都會開啟一個線程用于讀取該RegionServer上的HLog,并且發送到各個 Slave,Zookeeper用于保存當前已經發送的HLog的位置。Master與Slave之間采用異步通信的方式,保障Master上的性能不會 受到Slave的影響。用Zookeeper保存已經發送HLog的位置,主要考慮在Slave復制過程中如果出現問題后重新建立復制,可以找到上次復制 的位置。
HBase Replication步驟
- HBase Client向Master寫入數據
- 對應RegionServer寫完HLog后返回Client請求
- 同時replication線程輪詢HLog發現有新的數據,發送給Slave
- Slave處理完數據后返回給Master
- Master收到Slave的返回信息,在Zookeeper中標記已經發送到Slave的HLog位置
注: 在進行 replication 時, Master 與 Slave 的配置并不一定相同,比如 Master 上可以有 3 臺 RegionServer , Slave 上并不一定是 3 臺, Slave 上的 RegionServer 數量可以不一樣,數據如何分布這個 HBase 內部會處理。
種類
HBase通過HLog進行數據復制,那么HBase支持哪些不同種類的復制關系?
從復制模式上來講,HBase支持主從、主主兩種復制模式,也就是經常說的Master-Slave、Master-Master復制。
- Master-Slave
Master-Slave復制比較簡單,所有在Master集群上寫入的數據都會被同步到Slave上。
- Master-Master
Master-Master復制與Master-Slave類似,主要的不同在于,在Master-Master復制中,兩個Master地位相同,都可以進行讀取和寫入。
既然Master-Master兩個Master都可以進行寫入,萬一出現一種情況:兩個Master上都進行了對同一表的相同Column Family的同一個rowkey進行寫入,會出現什么情況?
create ‘t’, {NAME=>’cf’, REPLICATION_SCOPE=>’1’}
Master1 Master2
put ‘t’, ‘r1’, ‘cf’, ‘aaaaaaaaaaaaaaa’ put ‘t’, ‘r1’, ‘cf’, ‘bbbbbbbbbbbbbbb’
如上操作,Master1上對t的cf列簇寫入rowkey為r1,value為aaaaaaaaaaaaaaa的數據,Master2上同時 對t的cf列簇寫入rowkey為r1, value為bbbbbbbbbbbbbbb的數據,由于是Master-Master復制,Master1和Master2上在寫入數據的同時都會把更 新發送給對方,這樣最終的數據就變成了:
Master1 | Master2 | ||
rowkey | value | rowkey | value |
r1 | bbbbbbbbbbbbbbb | r1 | aaaaaaaaaaaaaaa |
從上述表格中可以看到,最終Master1和Master2上cf列簇rowkey為r1的數據兩邊不一致。
所以,在做 Master-Master 高可用時,確保兩邊寫入的表都是不同的,這樣能防止上述數據不一致問題。
異常
HBase復制時,都是通過RegionServer開啟復制線程進行HLog的發送,那么當其中某個RegionServer出現異常 時,HBase是如何處理的?這里需要區別兩種不同的情況,即Master上RegionServer異常和Slave上RegionServer異常。
- Slave 上RegionServer 異常
對于該種異常HBase處理比較簡單,Slave上出現某個RegionServer異常,該RegionServer直接會被標記為異常狀 態,后續所有的更新都不會被發送到該臺RegionServer,Slave會重新選取一臺RegionServer來接收這部分數據。
- Master 上RegionServer 異常
Master上RegionServer出現異常,由于HLog都是通過RegionServer開啟復制線程進行發送,如果 RegionServer出現異常,這個時候,屬于該臺RegionServer的HLog就沒有相關處理線程,這個時候,這部分數據又該如何處理?
Master上某臺RegionServer異常,其他RegionServer會對該臺RegionServer在zookeeper中的信 息嘗試加鎖操作,當然這個操作是互斥的,同一時間只有一臺RegionServer能獲取到鎖,然后,會把HLog信息拷貝到自己的目錄下,這樣就完成了 異常RegionServer的HLog信息的轉移,通過新的RegionServer把HLog的信息發送到Slave。
Master regionserver crash
操作
上面介紹的都是HBase高可用的理論實現和異常處理等問題,下面就動手實踐下,如何配置一個HBase的Replication(假設已經部 署好了兩套HBase系統,并且在配置文件中已經開啟了replication配置),首先嘗試配置下Master-Slave模式的高可用:
- 選取一套系統作為Master,另外一套作為Slave
- 在Master上通過add_peer 命令添加復制關系,如下
add_peer ‘1’, “db-xxx.photo.163.org:2181:/hbase”
- 在Master上新建表t,該表擁有一個列簇名為cf,并且該列簇開啟replication,如下:
create ‘t’, {NAME=>’cf’, REPLICATION_SCOPE=>’1’}
上面REPLICATION_SCOPE的值需要跟步驟2中的對應
- 在slave建立相同的表(HBase不支持DDL的復制),在master-slave模式中,slave不需要開啟復制,如下:
create ‘t’, {NAME=>’cf’ }
這樣,我們就完成了整個master-slave模式高可用的搭建,后續可以在master上通過put操作插入一條記錄,查看slave上是否會復制該記錄,最終結果如下:
Master上操作
Slave上結果
上述結果顯示,在添加完復制關系后,Master上插入rowkey=r1, value=’aaaaaaaaa’的記錄,slave上可以獲取該記錄,Master-Slave模式數據復制成功。
接下來我們再看下Master-Master模式的復制,配置的時候與Master-Slave模式不同的是,在Master上添加完復制關系 后,需要在另外一臺Master也添加復制關系,而且兩邊的cluster_id必須相同,并且在另外一臺Master上建表的時候,需要加上列簇的 REPLICATION_SCOPE=>’1’配置,最終結果如下:
Master1上操作
Master2上操作
上述結果顯示,添加完了Master-Master復制關系,在Master1上插入一條記錄rowkey=r1, value=“aaaaaaaaaa”,Master2上通過scan操作發現該記錄已經被復制到Master2上,接著我們在Master2上添加一條 記錄rowkey=r2, value=’bbbbbbbbbbbb’,查看Master1上的數據,該條記錄也已經被復制到Master2上,Master-Master模式的 replication驗證成功。