天天看點

HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

目錄

寫原理

讀原理

Flush流程

HFile合并流程

Region拆分流程

資料删除時間

HBase系列:

  • HBase系列(一)、資料模型 
  • HBase系列(二)、架構原理

寫原理

HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

用戶端請求HBase寫請求(PUT,DELETE)流程如下:

  1. Client 先通路ZK中的/hbase/meta-region-server 這個Znode,擷取 hbase:meta 表所在的RegionServer;
  2. ZK傳回META表所在的RS01資訊;
  3. Client 通路META所在的RS01,查詢hbase:meta;
  4. RS01将HBase中繼資料資訊meta傳回給用戶端;
  5. Client 将得到的中繼資料資訊進行緩存,之後再有讀取請求時可以免去步驟1~5節約時間和資源;
  6. Client 向目标表所在的RS02發送寫請求(PUT/DELETE);
  7. RS02将資料順序追加到WAL(HLog)内;
  8. RS02将資料寫入對應的Region内的MemStore,資料會在MemStore 進行排序;
  9. RS02向Client 傳回應答資訊完成寫操作;
  10. 當滿足Flush政策時,memstore内的資料會被刷寫至HFile内;

讀原理

HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

用戶端請求HBase讀請求(GET)流程如下: 前面1~5步驟和寫請求一樣。

  1. Client 先通路ZK中的/hbase/meta-region-server 這個Znode,擷取 hbase:meta 表所在的RegionServer;
  2. ZK傳回META表所在的RS01資訊;
  3. Client 通路META所在的RS01,查詢hbase:meta;
  4. RS01将HBase中繼資料資訊meta傳回給用戶端;
  5. Client 将得到的中繼資料資訊進行緩存,之後再有讀取請求時可以免去步驟1~5節約時間和資源;
  6. Client 向目标表所在的RS02發送讀請求(GET);
  7. 從BlockCache(塊緩存),MemStore 和 StoreFile(HFile)中查詢目标資料,然後根據RowKey和時間戳進行資料合并;
  8. 将從StoreFile(HFile)中讀到的資料緩存到BlockCache内供下次查詢時使用,免去再次讀取檔案的磁盤IO消耗;
  9. 将合并後的結果傳回給用戶端;
注意:
  • 這裡并不是先讀記憶體,如果記憶體沒有該資料再讀磁盤,而是同時查詢記憶體(BlockCache,MemStore)以及磁盤(StoreFile)。這樣做的原因是當相同的rowkey在StoreFile檔案内的資料時間戳大于MemStore中的時間戳時,如果先讀MemStore的話會給用戶端傳回一個舊的資料,是以需要同時讀記憶體和磁盤裡的資料,然後根據rowkey為主鍵,以timestamp為版本進行資料合并;
  • 同時,在讀磁盤的時候會将磁盤中的HFile緩存到BlockCache内,這樣的話在下一次通路該HFile時就可以先到BlockCache中拿了,如果BlockCache内沒有該檔案,再去StoreFile中取。這裡不必擔心萬一緩存到BlockCache之後又修改了該rowkey的資料會不會與BlockCache内的資料不一緻,因為當資料被修改之後再次讀取時:
    • 如果在此期間沒有觸發flush,該資料會在MemStore内,下次讀取資料時會将BlockCache和MemStore中的該rowkey的資料進行合并;
    • 如果在此期間觸發了flush,新的資料會在StoreFile中另一個新的HFile内,此時用戶端再次請求讀該RowKey的資料時會同時通路BlockCache内的包含舊版本資料的HFile以及StoreFile中的新HFile進行資料合并,然後會再将新的HFile緩存至BlockCache;
  • 也即是說每次讀HBase時,如果該資料不在記憶體中,都會産生一次磁盤IO,而寫資料是直接追加寫WAL和記憶體,是以HBase是寫比讀更快。

Flush流程

HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

上面多次提到了Flush刷寫機制,表示的就是将記憶體中的MemStore資料持久化到HDFS内,即可以避免記憶體壓力過大又可以保證資料安全,我們知道一個Region内包含多個列族,即在同一個Region内的每個Store表示了不同的列族,而每次Flush都會将MemStore持久化到HDFS内的一個HFile中,是以一個Store的資料最終會落到很多HFile中。

MemStore觸發Flush刷寫的條件如下,基本上就是按時間和容量:

  1. 當Region内某個MemStore 的大小達到了參數( hbase.hregion.memstore.flush.size)的值(預設值 128M),該Region内所有 MemStore 都會刷寫;
  2. 當MemStore 的大小達到了公式 [hbase.hregion.memstore.flush.size(預設128MB) * hbase.hregion.memstore.block.multiplier(預設4)] 時,會阻止繼續往該MemStore中寫資料;
  3. 當 RegionServer 中 MemStore 的總大小達到公式[java_heapsize * hbase.regionserver.global.memstore.size(預設值 0.4)*hbase.regionserver.global.memstore.size.lower.limit(預設值 0.95)] 時,Region會按照其所有MemStore 的大小順序(由大到小)依次進行刷寫。直到 該RegionServer 中所有 MemStore 的總大小減小到上述值以下。
  4. 當 RegionServer 中 MemStore 的總大小達到公式[java_heapsize * hbase.regionserver.global.memstore.size(預設值 0.4)] 時,會阻止繼續往該RegionServer 中所有MemStore中寫資料;
  5. 通過配置參數(hbase.regionserver.optionalcacheflushinterval)進行自動刷寫(預設 1 小時);
  6. 當 WAL 檔案的數量超過最大數量 hbase.regionserver.max.logs,region 會按照時間順序依次進行刷寫,直到 WAL 檔案數量減小到 hbase.regionserver.max.log 以下(該屬性名已經廢棄,現無需手動設定,預設值為 32)。

HFile合并流程

由于MemStore 每次刷寫都會生成一個新的HFile,且同一個字段的不同版本(timestamp)和不同類型(Put/Delete)有可能會分布在不同的 HFile 中,是以查詢時需要周遊很多 HFile檔案。為了減少 HFile 的個數,以及清理掉過期和删除的資料,HBase會對StoreFile 進行Compaction(合并)。

Compaction 分為兩種:

  • Minor Compaction:将臨近的若幹個較小的 HFile 合并成一個較大的 HFile,但不會清理過期和删除的資料;minor的過程一般較快,而且IO相對較低。當HFile數量達到參數(minFilesToCompact,預設3個)最低标準時,此指令才會觸發,否則忽略本次操作。當待合并的HFile大小超過參數(maxCompactSize)時會将多的檔案過濾掉不進行合并。
  • Major Compaction:将一個 Store 下的所有的 HFile 合并成一個大 HFile,并且會清理掉過期和删除的資料;由于此合并政策影響讀寫性能,是以一般在生産環境中,都會禁用major自動合并操作(參數hbase.hregion.majorcompaction設為0,預設是7天),隻在空閑的時段手動或定時執行;
HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

HBase會将隊列中的HFile 按照檔案年齡排序(older to younger),Minor Compaction總是從older HFile 開始選擇,然後将選擇出來的HFiles進行Minor Compaction:

  1. 如果該檔案小于hbase.hstore.compaction.min.size(為memestoreFlushSize)則一定會被添加到合并隊列中。
  2. 如果該檔案大于hbase.hstore.compaction.max.size(Long.MAX_VALUE)則一定會被排除,這個值很大,一般不會有。
  3. 如果該檔案的大小 小于它後面hbase.hstore.compaction.max(預設為10) 個HFile 的大小之和乘以一個ratio(配置項是hbase.hstore.compaction.ratio,預設為1.2),則該HFile 也将加入到minor compaction 中。如果他後面不足10個檔案,那麼也就是取他後面幾個檔案總和*ratio。

相關參數:

參數名 配置項 預設值 含義
minFileToCompact hbase.hstore.compactionThreshold 3 最低合并HFile數量
maxFileToCompact hbase.hstore.compaction.max 10 最大合并HFile數量
minCompactSize hbase.hstore.compaction.min.size memstoreFlushSize 最小合并HFile檔案大小
maxCompactSize hbase.hstore.compaction.max.size Long.MAX_VALUE 最大合并HFile檔案大小
majorCompaction hbase.hregion.majorcompaction 7天 自動觸發Major 間隔時間

Region拆分流程

預設情況下,每個 Table 起初隻有一個 Region,随着資料的不斷寫入,Region 會越來越大然後自動進行拆分(Split)。剛拆分時,兩個子 Region 都位于目前的 RegionServer,但出于負載均衡的考慮,HMaster 有可能會将某個 Region 轉移給其他的 RegionServer。 

Region 拆分時機:

  1. 當1個region中的某個Store下所有StoreFile的總大小超過hbase.hregion.max.filesize(預設10GB),該 Region 就會進行拆分(0.94 版本之前)。
  2. 當1個region 中的某個 Store 下所有 StoreFile 的總大小超過公式Min(R^2 * "hbase.hregion.memstore.flush.size(預設128MB)",hbase.hregion.max.filesize(預設10GB)"),該 Region 就會進行拆分,其中 R 為目前 RegionServer 中屬于該 Table 的Region個數(0.94 版本之後)。
HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

可以看出,在新版之後,Region的拆分條件會預設從128MB不斷的變大一直到10GB,這樣就會導緻某個表的不同Region内的資料不均衡的情況,是以在實際應用中都會提前設定預分區以及RowKey優化,避免因自動拆分導緻的資料傾斜的情況。  

資料删除時間

當HBase中執行PUT修改相同RowKey的資料或者執行DELETE删除RowKey的資料時,我們可以通過指令檢視到曆史版本,那麼什麼時候這些過期資料和删除資料才會被删除呢?

其實失效資料在Flush和Compact都會被删除,但它們實作的地方不一樣:

  • Flush刷寫時:
    • Flush将MemStore内的資料進行合并然後去除小于該列族設定的VERSION号以前的資料,将剩餘資料持久化到HFile;
    • 當執行DELETE時,Flush操作不會删掉MemStore裡的該删除标記記錄,隻會删掉MemStore内該RowKey的在該删除标記操作的timestamp之前的操作,原因是可能在之前已持久化到HFile實體檔案中也有該RowKey記錄的曆史版本,如果把記憶體裡的删除标記也删除的話,再次查詢就會将實體檔案中的曆史版本查出來,這樣就不對了,是以Flush不會删除MemStore内的删除标記記錄。
  • Compact合并時:
    • Compact指令會真正将記憶體和磁盤上的檔案進行merge,去除小于該列族設定的VERSION号以前的資料,将剩餘資料合并為一個新的HFile;
HBase系列(三)、讀寫原理,Flush刷寫,HFile Compact合并,Region Split切分寫原理讀原理Flush流程HFile合并流程Region拆分流程資料删除時間

希望本文對你有幫助,請點個贊鼓勵一下作者吧~ 謝謝! 

繼續閱讀