1.概述
HBase的存儲結構和關系型數據庫不一樣,HBase面向半結構化數據進行存儲。所以,對於結構化的SQL語言查詢,HBase自身並沒有接口支持。在大數據應用中,雖然也有SQL查詢引擎可以查詢HBase,比如Phoenix、Drill這類。但是閱讀這類SQL查詢引擎的底層實現,依然是調用了HBase的Java API來實現查詢,寫入等操作。這類查詢引擎在業務層創建Schema來映射HBase表結構,然后通過解析SQL語法數,最后底層在調用HBase的Java API實現。
本篇內容,筆者並不是給大家來介紹HBase的SQL引擎,我們來關注HBase更低層的東西,那就是HBase的存儲實現。以及跨集群的HBase集群數據遷移。
2.內容
HBase數據庫是唯一索引就是RowKey,所有的數據分布和查詢均依賴RowKey。所以,HBase數據庫在表的設計上會有很嚴格的要求,從存儲架構上來看,HBase是基於分布式來實現的,通過Zookeeper集群來管理HBase元數據信息,比如表名就存放在Zookeeper的/hbase/table目錄下。如下圖所示:
2.1 Architecture
HBase是一個分布式存儲系統,底層數據存儲依賴Hadoop的分布式存儲系統(HDFS)。HBase架構分三部分來組成,它們分別是:ZooKeeper、HMaster和HRegionServer。
- ZooKeeper:HBase的元數據信息、HMaster進程的地址、Master和RegionServer的監控維護(節點之間的心跳,判斷節點是否下線)等內容均需要依賴ZooKeeper來完成。是HBase集群中不可缺少的核心之一。
- HMaster:HMaster進程在HBase中承擔Master的責任,負責一些管理操作,比如給表分配Region、和數據節點的心跳維持等。一般客戶端的讀寫數據的請求操作不會經過Master,所以在分配JVM內存的適合,一般32GB大小即可。
- HRegionServer:HRegionServer進程在HBase中承擔RegionServer的責任,負責數據的存儲。每個RegionServer由多個Region組成,一個Region維護一定區間的RowKey的數據。如下圖所示:
圖中Region(dn2:16030)維護的RowKey范圍為0001~0002。HBase集群的存儲結構如下圖所示:
Zookeeper通常由奇數個組成,便於分布式選舉,可參考《分布式系統選舉算法剖析》一文了解,這里不多贅述細節。HBase為了保證高可用性(HA),一般都會部署兩個Master節點,其中一個作為主,另一個作為Backup節點。這里誰是主,誰是Backup取決於那個HMaster進程能從Zookeeper上對應的Master目錄中競爭到Lock,持有該目錄Lock的HMaster進程為主Master,而另外一個為Backup,當主Master發生意外或者宕機時,Backup的Master會立刻競爭到Master目錄下的Lock從而接管服務,成為主Master對外提供服務,保證HBase集群的高可用性。
2.2 RegionServer
HBase負責數據存儲的就是RegionServer,簡稱RS。在HBase集群中,如果只有一份副本時,整個HBase集群中的數據都是唯一的,沒有冗余的數據存在,也就是說HBase集群中的每個RegionServer節點上保存的數據都是不一樣的,這種模式由於副本數只有一份,即是配置多個RegionServer組成集群,也並不是高可用的。這樣的RegionServer是存在單點問題的。雖然,HBase集群內部數據有Region存儲和Region遷移機制,RegionServer服務的單點問題可能花費很小的代價可以恢復,但是一旦停止RegionServre上含有ROOT或者META表的Region,那這個問題就嚴重,由於數據節點RegionServer停止,該節點的數據將在短期內無法訪問,需要等待該節點的HRegionServer進程重新啟動才能訪問其數據。這樣HBase的數據讀寫請求如果恰好指向該節點將會收到影響,比如:拋出連接異常、RegionServer不可用等異常。
3.日志信息
HBase在實現WAL方式時會產生日志信息,即HLog。每一個RegionServer節點上都有一個HLog,所有該RegionServer節點上的Region寫入數據均會被記錄到該HLog中。HLog的主要職責就是當遇到RegionServer異常時,能夠盡量的恢復數據。
在HBase運行的過程當中,HLog的容量會隨着數據的寫入越來越大,HBase會通過HLog過期策略來進行定期清理HLog,每個RegionServer內部均有一個HLog的監控線程。HLog數據從MemStore Flush到底層存儲(HDFS)上后,說明該時間段的HLog已經不需要了,就會被移到“oldlogs”這個目錄中,HLog監控線程監控該目錄下的HLog,當該文件夾中的HLog達到“hbase.master.logcleaner.ttl”(單位是毫秒)屬性所配置的閥值后,監控線程會立即刪除過期的HLog數據。
4.數據存儲
HBase通過MemStore來緩存Region數據,大小可以通過“hbase.hregion.memstore.flush.size”(單位byte)屬性來進行設置。RegionServer在寫完HLog后,數據會接着寫入到Region的MemStore。由於MemStore的存在,HBase的數據寫入並非是同步的,不需要立刻響應客戶端。由於是異步操作,具有高性能和高資源利用率等優秀的特性。數據在寫入到MemStore中的數據后都是預先按照RowKey的值來進行排序的,這樣便於查詢的時候查找數據。
5.Region分割
在HBase存儲中,通過把數據分配到一定數量的Region來達到負載均衡。一個HBase表會被分配到一個或者多個Region,這些Region會被分配到一個或者多個RegionServer中。在自動分割策略中,當一個Region中的數據量達到閥值就會被自動分割成兩個Region。HBase的表中的Region按照RowKey來進行排序,並且一個RowKey所對應的Region只有一個,保證了HBase的一致性。
一個Region中由一個或者多個Store組成,每個Store對應一個列族。一個Store中包含一個MemStore和多個Store Files,每個列族是分開存放以及分開訪問的。自動分割有三種策略,分別是:
- ConstantSizeRegionSplitPolicy:在HBase-0.94版本之前是默認和唯一的分割策略。當某一個Store的大小超過閥值時(hbase.hregion.max.filesize,默認時10G),Region會自動分割。
- IncreasingToUpperBoundRegionSplitPolicy:在HBase-0.94中,這個策略分割大小和表的RegionServer中的Region有關系。分割計算公式為:Min(R*R*'hbase.hregion.memstore.flush.size','hbase.hregion.max.filesize'),其中,R表示RegionServer中的Region數。比如:hbase.hregion.memstore.flush.size=256MB,hbase.hregion.max.filesize=20GB,那么第一次分割的大小為Min(1*1*256,20GB)=256MB,也就是在第一次大到256MB會分割成2個Region,后續以此公式類推計算。
- KeyPrefixRegionSplitPolicy:可以保證相同前綴的RowKey存放在同一個Region中,可以通過hbase.regionserver.region.split.policy屬性來指定分割策略。
6.磁盤合理規划
部署HBase集群時,磁盤和內存的規划是有計算公式的。隨意分配可能造成集群資源利用率不高導致存在浪費的情況。公式如下:
# 通過磁盤維度的Region數和Java Heap維度的Region數來推導
Disk Size/(RegionSize*ReplicationFactor)=Java Heap*HeapFractionForMemstore/(MemstoreSize/2)
公式中對應的hbase-site.xml文件中的屬性中,見下表:
Key | Property |
Disk Size | 磁盤容量大小,一般一台服務器有多塊磁盤 |
RegionSize | hbase.hregion.max.filesize默認10G,推薦范圍在10GB~30GB |
ReplicationFactor | dfs.replication默認為3 |
Java Heap | 分配給HBase JVM的內存大小 |
HeapFractionForMemstore | hbase.regionserver.global.memstore.lowerLimit默認為0.4 |
MemstoreSize | hbase.hregion.memstore.flush.size默認為128M |
在實際使用中,MemstoreSize空間打下只使用了一半(1/2)的容量。 舉個例子,一個RegionServer的副本數配置為3,RegionSize為10G,HBase的JVM內存分配45G,HBase的MemstoreSize為128M,那此時根據公式計算得出理想的磁盤容量為45G*1024*0.4*2*10G*1024*3/128M=8.5T左右磁盤空間。如果此時,分配一個節點中掛載10個可用盤,共27T。那將有兩倍的磁盤空間不匹配造成浪費。 為了提升磁盤匹配度,可以將RegionSize值提升至30G,磁盤空間計算得出25.5T,基本和27T磁盤容量匹配。
7.數據遷移
對HBase集群做跨集群數據遷移時,可以使用Distcp方案來進行遷移。該方案需要依賴MapReduce任務來完成,所以在執行遷移命令之前確保新集群的ResourceManager、NodeManager進程已啟動。同時,為了查看遷移進度,推薦開啟proxyserver進程和historyserver進程,開啟這2個進程可以方便在ResourceManager業務查看MapReduce任務進行的進度。 遷移的步驟並不復雜,在新集群中執行distcp命令即可。具體操作命令如下所示:
# 在新集群的NameNode節點執行命令 [hadoop@nna ~]$ hadoop distcp -Dmapreduce.job.queue.name=queue_0001_01 -update -skipcrccheck -m 100 hdfs://old_hbase:9000/hbase/data/tabname /hbase/data/tabname
為了遷移方便,可以將上述命令封裝成一個Shell腳本。具體實現如下所示:
#! /bin/bash for i in `cat /home/hadoop/hbase/tbl` do echo $i hadoop distcp -Dmapreduce.job.queue.name=queue_0001_01 -update -skipcrccheck -m 100 hdfs://old_hbase:9000/hbase/data/$i /hbase/data/$i done hbase hbck -repairHoles
將待遷移的表名記錄在/home/hadoop/hbase/tbl文件中,一行代表一個表。內容如下所示:
hadoop@nna ~]$ vi /home/hadoop/hbase/tbl # 表名列表 tbl1 tbl2 tbl3 tbl4
最后,在循環迭代遷移完成后,執行HBase命令“hbase hbck -repairHoles”來修復HBase表的元數據,如表名、表結構等內容,會從新注冊到新集群的Zookeeper中。
8.總結
HBase集群中如果RegionServer上的Region數量很大,可以適當調整“hbase.hregion.max.filesize”屬性值的大小,來減少Region分割的次數。在執行HBase跨集群數據遷移時,使用Distcp方案來進行,需要保證HBase集群中的表是靜態數據,換言之,需要停止業務表的寫入。如果在執行HBase表中數據遷移時,表持續有數據寫入,導致遷移異常,拋出某些文件找不到。
9.結束語
這篇博客就和大家分享到這里,如果大家在研究學習的過程當中有什么問題,可以加群進行討論或發送郵件給我,我會盡我所能為您解答,與君共勉。