Hbase的讀寫流程、快照管理以及RegionServer,Region,StoreFile,Hfile,ColumFamily的關係
- 下面是hbase的架構圖:
- .META.表和-ROOT-表
ROOT表和META表都是相當於hbase的元資料表,在zookeeper中記錄的了ROOT表所在的RegionService的地址,你可以通過這個地址找到ROOT表,ROOT表裡面又記錄了你操作的這個表所有ROWKEY的分割槽詳細記錄的META表的地址,然後路由到那個記錄詳細資訊的且管理META這部分表的RegionServer,然後定位到META表,在META表唯一定位到一個指定的RegionServer,三段式路由:zookeeper、ROOT、META。
META表上面儲存的就是Hbase上面所有Region的分佈和詳細資訊,如果META表過大那麼META的region也會分裂,那麼就引進了ROOT表儲存META表的Region的分佈和詳細資訊,不過現在新版本好像已經沒有ROOT表了,因為Hbase中資料個數一般不會使META的Region分裂。
那麼讀寫操作client都不會和hmaster打交道,client會直接通過zookeeper的root表和META表定位到HRegionServer,先根據ROOT表定位META表的Region,在根據META的資訊定位到你需要操作的那個值的Region,所以hbase的讀寫操作不會和hmaster打交道,並且會將這些資訊cache到client埠。
而HMaster的作用主要是:
為HRegionServer分配region
負責HRegionServer的負載均衡
複製處理HRegionServer掛掉的情況,並且為這些Region分配新HRegionServer
維護.META.和-ROOT-表的資訊,比如在Region分裂的時候hmaster就會去維護
- 1.hbase的寫操作
首先client端寫操作會先訪問zookeeper,然後根據zk裡面的-ROOT-中的資訊和.META.中的資訊直接對映到對應的HRegionServer
client會去請求對應的HRegionServer
如果設定了WAL(Write-Ahead-Log)預寫日誌,那麼HRegionServer會先進行預寫日誌操作,並且是多執行緒寫入一個佇列裡面,然後另外一個單執行緒的真正寫日誌的操作從佇列裡面取資料(保證資料的全域性一致性)一個HRegionServer的預寫日誌操作只會寫到一個Hlog裡面,也就是說一個HRegionServer管理的不同的Region的預寫日誌都是公用一個Hlog,寫到Hlog中(sequence file檔案格式),據網友測試在操作hbase開啟和關閉預寫日誌,效能相差大概10到20倍左右
然後寫入資料到HRegion的MemStore(記憶體)中,如果MemStore達到了一定的大小,MemStore會被flush到StoreFile,flush之後還會記錄一個flag,到時候用Hlog恢復的時候就知道哪些資料在HRegionServer掛了之後就丟失了,哪些資料已經持久化到磁碟了。
當StoreFile數量達到一定值後會進行Compact(合併)操作,合併最後StoreFile大小達到一定值之後會進行分裂split操作,在split操作的時候會和hmaster打交道,hmaster會去維護META表和ROOT的資料(META表分裂的時候 同理)。
Region會分裂成兩個相等的Region,之前的Region就會下線,然後後面的兩個新Region會被Hmaster分配到其他的HRegionServer上面
這裡有2個注意事項就是:
1.在建立表的時候我們應該先預估資料量,然後在建立表的時候就先預先建立適量的Region個數,不然所有資料都放一個Region,當資料量很大的時候,就會造成Region的分裂會很平常,就特別影響效能;
2.最好在建表的時候指定比較少的ColumnFamily,因為如果ColumnFamily比較多,一個StoreFile對應一個ColumnFamily,如果有多個ColumnFamily那麼就有多個StoreFile,當有的ColumnFamily資料量很大有的很小,但是當Region達到一定資料量會分裂,那麼會我們查詢就可能會誇多個Region,導致效能不高
- 2.hbase讀資料
Client會先訪問zookeeper並且根據zk裡面的-ROOT-中的資訊和.META.中的資訊(我的理解是ROOT儲存一段一段的資料,你查詢的資料能直接定位到在那一段中,然後在去META表中查詢具體的資訊)直接對映到對應的HRegionServer
client請求對應的HRegionServer,首先會去MemStore(記憶體)中查詢資料,如果有資料就返回
MemStore沒有查詢到資料,就會去Block快取塊中查詢,快取塊中查詢到資料就直接返回
Block快取塊沒有查詢到資料,就會去硬碟讀取StoreFile的資訊,並且也放到Block快取塊中,Block快取塊舊的東西就會被刪除,直到查詢到資料為止並返回,或者沒有查詢到資料就返回空
- 3. Hbase中RegionServer,Region,StoreFile,Hfile,ColumFamily等等的關係
Region是hbase最小的邏輯儲存單元,但是物理的還有StoreFile,Hfile,一個Region包含一個或者多個StoreFile,一個StoreFile包含一個或者多個Hfile,其中RegionServer是為Region服務的。
一個Region包含一個或者多個StoreFile,而一個StoreFile對應一個ColumnFamily,所以一個Region會包含一個或者多個ColumnFamily
一個Region只能由一個RegionServer服務,但是一個RegionServer可以服務多個Region
- 4.hbase的快照管理
快照就是一份元資訊的合集,允許管理員恢復到表的先前狀態。快照不是表的複製而是一個檔名稱列表,因而不會複製資料。
hbase的快照是依賴於hdfs提供的快照功能,可以對之前的資料進行快照拍攝,當誤操作刪除了資料,可以恢復到以前快照版本的資料,但是之後的資料就沒有了(還有一個方法,如果誤操作刪除了表,可以在hdfs的/hbase/archive資料夾裡面找到對應的表資訊,預設刪除了表,會將Region的資料先轉移到這個資料夾,但是當達到設定的時間後這個檔案下的資料也會被刪除,配置專案:hbase.master.hfilecleaner.ttl,預設是600000 ms,可以在這時間之類把資料拷貝到data目錄下,然後使用hbase的修復元資料功能進行資料恢復)。
hbase的快照管理提供了shell指令碼的方式,也提供了javaAPI的方式
前提是hbase-site.xml中的hbase.snapshot.enabled 是否是true (預設為true)
shell方式:
一.建立快照:
hbase(main):005:0> snapshot 'lijie001','lijie001snapshot'
0 row(s) in 8.6660 seconds
二.快照列表:
hbase(main):008:0> list_snapshots
SNAPSHOT TABLE + CREATION TIME
lijie001snapshot lijie001 (Thu Feb 23 09:40:23 -0500 2017)
1 row(s) in 3.1330 seconds
=> ["lijie001snapshot"]
三.克隆快照(從快照中克隆一個新表):
hbase(main):009:0> clone_snapshot 'lijie001snapshot','clone_lijie001'
0 row(s) in 5.9920 seconds
四.刪除快照:
hbase(main):011:0> delete_snapshot 'lijie001snapshot'
0 row(s) in 3.8050 seconds
五.快照恢復
必須首先disable表,不然會報錯
hbase(main):019:0> disable 'lijie001'
0 row(s) in 1.2740 seconds
hbase(main):020:0> restore_snapshot 'lijie001snapshot'
0 row(s) in 8.5710 seconds
hbase(main):021:0> enable 'lijie001'
0 row(s) in 4.8730 seconds
javaAPI方式(方法在org.apache.hadoop.hbase.client 的Admin類中)
一.建立快照:
void snapshot(final String snapshotName, final TableName tableName) throws IOException, SnapshotCreationException, IllegalArgumentException;
二.獲取快照:
List<HBaseProtos.SnapshotDescription> listSnapshots() throws IOException;
List<HBaseProtos.SnapshotDescription> listSnapshots(String regex) throws IOException;
List<HBaseProtos.SnapshotDescription> listSnapshots(Pattern pattern) throws IOException;
三.刪除快照(單個或者多個):
void deleteSnapshot(final byte[] snapshotName) throws IOException;
void deleteSnapshot(final String snapshotName) throws IOException;
void deleteSnapshots(final String regex) throws IOException;
void deleteSnapshots(final Pattern pattern) throws IOException;