1. RegionServer 架構(gòu)
1.1 StoreFile
保存實際數(shù)據(jù)的物理文件咧擂,StoreFile以Hfile的形式存儲在HDFS上铣减。每個Store會有一個或多個StoreFile(HFile)驳癌,數(shù)據(jù)在每個StoreFile中都是有序的耻台。
1.2 MemStore
寫緩存,由于HFile中的數(shù)據(jù)要求是有序的,所以數(shù)據(jù)是先存儲在MemStore中蜜徽,排好序后,等到達(dá)刷寫時機才會刷寫到HFile票摇,每次刷寫都會形成一個新的HFile拘鞋。
1.3 WAL
由于數(shù)據(jù)要經(jīng)MemStore排序后才能刷寫到HFile,但把數(shù)據(jù)保存在內(nèi)存中會有很高的概率導(dǎo)致數(shù)據(jù)丟失矢门,為了解決這個問題盆色,數(shù)據(jù)會先寫在一個叫做Write-Ahead logfile的文件中,然后再寫入MemStore中祟剔。所以在系統(tǒng)出現(xiàn)故障的時候隔躲,數(shù)據(jù)可以通過這個日志文件重建。
每間隔hbase.regionserver.optionallogflushinterval(默認(rèn)1s)物延, HBase會把操作從內(nèi)存寫入WAL宣旱。
一個RegionServer上的所有Region共享一個WAL實例。
WAL的檢查間隔由hbase.regionserver.logroll.period定義叛薯,默認(rèn)值為1小時浑吟。檢查的內(nèi)容是把當(dāng)前WAL中的操作跟實際持久化到HDFS上的操作比較笙纤,看哪些操作已經(jīng)被持久化了,被持久化的操作就會被移動到.oldlogs文件夾內(nèi)(這個文件夾也是在HDFS上的)组力。一個WAL實例包含有多個WAL文件省容。WAL文件的最大數(shù)量通過hbase.regionserver.maxlogs(默認(rèn)是32)參數(shù)來定義。
1.4 BlockCache
讀緩存燎字,每次查詢出的數(shù)據(jù)會緩存在BlockCache中腥椒,方便下次查詢
2. 寫流程
寫流程:
- Client先訪問zookeeper,獲取hbase:meta表位于哪個Region Server轩触。
- 訪問對應(yīng)的Region Server寞酿,獲取hbase:meta表家夺,根據(jù)讀請求的namespace:table/rowkey脱柱,查詢出目標(biāo)數(shù)據(jù)位于哪個Region Server中的哪個Region中。并將該table的region信息以及meta表的位置信息緩存在客戶端的meta cache拉馋,方便下次訪問榨为。
- 與目標(biāo)Region Server進(jìn)行通訊;
- 將數(shù)據(jù)順序?qū)懭耄ㄗ芳樱┑絎AL煌茴;
- 將數(shù)據(jù)寫入對應(yīng)的MemStore随闺,數(shù)據(jù)會在MemStore進(jìn)行排序;
- 向客戶端發(fā)送ack蔓腐;
- 等達(dá)到MemStore的刷寫時機后矩乐,將數(shù)據(jù)刷寫到HFile
3. 讀流程
讀流程:
- Client先訪問zookeeper,獲取hbase:meta表位于哪個Region Server回论。
- 訪問對應(yīng)的Region Server散罕,獲取hbase:meta表,根據(jù)讀請求的namespace:table/rowkey傀蓉,查詢出目標(biāo)數(shù)據(jù)位于哪個Region Server中的哪個Region中欧漱。并將該table的region信息以及meta表的位置信息緩存在客戶端的meta cache,方便下次訪問葬燎。
- 與目標(biāo)Region Server進(jìn)行通訊
- 分別在Block Cache(讀緩存)误甚,MemStore和Store File(HFile)中查詢目標(biāo)數(shù)據(jù),并將查到的所有數(shù)據(jù)進(jìn)行合并谱净。此處所有數(shù)據(jù)是指同一條數(shù)據(jù)的不同版本(time stamp)或者不同的類型(Put/Delete)窑邦。
- 將查詢到的數(shù)據(jù)塊(Block,HFile數(shù)據(jù)存儲單元壕探,默認(rèn)大小為64KB)緩存到Block Cache冈钦。
- 將合并后的最終結(jié)果返回給客戶端。
4. MemStore Flush
MemStore存在的意義是在寫入HDFS前浩蓉,將其中的數(shù)據(jù)整理有序派继。
MemStore刷寫時機:
1.當(dāng)某個memstore的大小達(dá)到了hbase.hregion.memstore.flush.size(默認(rèn)值128M)宾袜,其所在region的所有memstore都會刷寫。
當(dāng)memstore的大小達(dá)到了:
- hbase.hregion.memstore.flush.size(默認(rèn)值128M)
- hbase.hregion.memstore.block.multiplier(默認(rèn)值4)時驾窟,會阻止繼續(xù)往該memstore寫數(shù)據(jù)庆猫。
2.當(dāng)region server中memstore的總大小達(dá)java_heapsize
- hbase.regionserver.global.memstore.size(默認(rèn)值0.4)
- hbase.regionserver.global.memstore.size.lower.limit(默認(rèn)值0.95),
3.到達(dá)自動刷寫的時間绅络,也會觸發(fā)memstore flush月培。自動刷新的時間間隔由該屬性進(jìn)行配置hbase.regionserver.optionalcacheflushinterval(默認(rèn)1小時)。
4.當(dāng)WAL文件的數(shù)量超過hbase.regionserver.max.logs恩急,region會按照時間順序依次進(jìn)行刷寫杉畜,直到WAL文件數(shù)量減小到hbase.regionserver.max.log以下(該屬性名已經(jīng)廢棄,現(xiàn)無需手動設(shè)置衷恭,最大值為32)此叠。
5. StoreFile Compaction
由于Hbase依賴HDFS存儲,HDFS只支持追加寫随珠。所以灭袁,當(dāng)新增一個單元格的時候,HBase在HDFS上新增一條數(shù)據(jù)窗看。當(dāng)修改一個單元格的時候茸歧,HBase在HDFS又新增一條數(shù)據(jù),只是版本號比之前那個大(或者自定義)显沈。當(dāng)刪除一個單元格的時候软瞎,HBase還是新增一條數(shù)據(jù)!只是這條數(shù)據(jù)沒有value拉讯,類型為DELETE涤浇,也稱為墓碑標(biāo)記(Tombstone)
HBase每間隔一段時間都會進(jìn)行一次合并(Compaction),合并的對象為HFile文件遂唧。合并分為兩種
minor compaction和major compaction芙代。
在HBase進(jìn)行major compaction的時候,它會把多個HFile合并成1個HFile盖彭,在這個過程中纹烹,一旦檢測到有被打上墓碑標(biāo)記的記錄,在合并的過程中就忽略這條記錄召边。這樣在新產(chǎn)生的HFile中铺呵,就沒有這條記錄了,自然也就相當(dāng)于被真正地刪除了隧熙。
由于memstore每次刷寫都會生成一個新的HFile片挂,且同一個字段的不同版本(timestamp)和不同類型(Put/Delete)有可能會分布在不同的HFile中,因此查詢時需要遍歷所有的HFile。為了減少HFile的個數(shù)音念,以及清理掉過期和刪除的數(shù)據(jù)沪饺,會進(jìn)行StoreFile Compaction。
Compaction分為兩種闷愤,分別是Minor Compaction
和Major Compaction
整葡。Minor Compaction會將臨近的若干個較小的HFile合并成一個較大的HFile,但不會清理過期和刪除的數(shù)據(jù)
讥脐。Major Compaction會將一個Store下的所有的HFile合并成一個大HFile遭居,并且會清理掉過期和刪除的數(shù)據(jù)
。
6. Region Split
默認(rèn)情況下旬渠,每個Table起初只有一個Region俱萍,隨著數(shù)據(jù)的不斷寫入,Region會自動進(jìn)行拆分告丢。剛拆分時枪蘑,兩個子Region都位于當(dāng)前的Region Server,但處于負(fù)載均衡的考慮芋齿,HMaster有可能會將某個Region轉(zhuǎn)移給其他的Region Server腥寇。
Region Split時機:
當(dāng)1個region中的某個Store下所有StoreFile的總大小超過
hbase.hregion.max.filesize,
該Region就會進(jìn)行拆分(0.94版本之前)觅捆。0.94版本之后的切分策略:默認(rèn)使用IncreasingToUpperBoundRegionSplitPolicy策略切分region, getSizeToCheck()是檢查region的大小以判斷是否滿足切割切割條件。
具體的切分策略為tableRegionsCount在0和100之間麻敌,則為initialSize(默認(rèn)為2*128)
- tableRegionsCount^3, 例如:
第一次split:1^3 * 256 = 256MB
第二次split:2^3 * 256 = 2048MB
第三次split:3^3 * 256 = 6912MB
第四次split:4^3 * 256 = 16384MB > 10GB栅炒,因此取較小的值10GB
后面每次split的size都是10GB了。
tableRegionsCount超過100個术羔,則超過10GB才會切分region赢赊。