HBase原理深入

HBase 讀寫數據流程

Hbase 讀數據流程

  1. 首先從 zk 找到 meta 表的 region 位置,然後讀取 meta 表中的數據,meta 表中存儲了用戶表的 region 信息

  2. 根據要查詢的 namespace、表名和 rowkey 信息,找到寫入數據對應的 region 信息

  3. 找到這個 region 對應的 regionServer,然後發送請求

  4. 查找對應的 region

  5. 先從 Memstore 查找數據,如果沒有,再從 BlockCache 上讀取。

    Hbase 上 RegionServer 的內存分爲兩部分:

    • 一部分作爲 Memstore,主要用來寫
    • 另一部分作爲 BlockCache,主要用來讀數據
  6. 如果 BlockCache 中也沒有,再到 StoreFile 上進行讀取。從 StoreFile 中讀到數據後,不是直接把結果返回給客戶端,而是先把數據寫入 BlockCache,然後再返回給客戶端。

HBase 寫數據流程

  1. 首先從 zk 找到 meta 表的 region 位置,然後讀取 meta 表中的數據,meta 表中存儲了用戶表的 region 信息。
  2. 根據 namespace、表名和 rowkey 等信息,找到寫入數據對應的 region
  3. 找到這個 region 對應的 regionServer,然後發送寫入請求
  4. 把數據分別寫入 HLog(Write ahead log)和 memStore
  5. memStore 達到閾值後把數據刷到磁盤,生成 storeFile
  6. 刪除 HLog 中的歷史數據

HBase 的 flush(刷寫)和 compact(合併)機制

Flush 機制

  1. 當 memstore 的大小超過這個值的時候,會 flush 到磁盤,默認爲 128M
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>134217728</value>
</property>
  1. 當 memstore 的數據超過 1 小時,會 flush 到磁盤
<property>
<name>hbase.regionserver.optionalcacheflushinterval</name>
<value>3600000</value>
</property
  1. HregionServer 的全局 memstore 的大小,超過該大小會觸發 flush 到磁盤的操作,默認是堆大小的 40%
<property>
<name>hbase.regionserver.global.memstore.size</name>
<value>0.4</value>
</property>
  1. 手動 flush
flush tableName

阻塞機制

以上介紹了數據刷寫磁盤的標準,但是 HBase 是週期性的檢查是否滿足來進行刷寫的,如果在下次檢查到來之前,數據瘋狂寫入 Memstore,就會把內存撐爆。那怎麼處理這種問題呢?

HBase 有阻塞機制,如果觸發,就無法繼續寫入數據。

  1. 當 Memstore 數據達到 512MB

計算公式:hbase.hregion.memstore.flush.size*hbase.hregion.memstore..block.multiplier

  • hbase.hregion.memstore.flush.size 刷寫的閥值,默認是 134217728,即 128MB。
  • hbase.hregion.memstore.block.multiplier 是一個倍數,默認是 4。
  1. RegionServer 全部 memstore 達到規定值

有時候集羣的“寫負載”非常高,寫入量一直超過 flush 的量,這時,我們就希望 memstore 不要超過一定的安全設置。在這種情況下,寫操作就要被阻塞一直到 memstore 恢復到一個“可管理”的大小, 這個大小就是默認值是堆大小 _ 0.4 _ 0.95。

  • hbase.regionserver.global.memstore.size.lower.limit 是 0.95
  • hbase.regionserver.global.memstore.size 是 0.4

Compact 合併機制

在 HBase 中主要存在兩種類型的 compact 合併。

  1. Minor compact 小合併

將 Store 中的多個 HFile(StoreFile)合併爲一個 HFile

這個過程中,刪除和更新的數據僅僅只是做了標記,並沒有物理移除,這種合併的觸發頻率很高。

minor compact 文件選擇標準由以下幾個參數共同決定:

<!--待合併文件數據必須大於等於下面這個值-->
<property>
  <name>hbase.hstore.compaction.min</name>
  <value>3</value>
</property>
<!--待合併文件數據必須小於等於下面這個值-->
<property>
  <name>hbase.hstore.compaction.max</name>
  <value>10</value>
</property>
<!--默認值爲128m,
表示文件大小小於該值的store file 一定會加入到minor compaction的store file中
-->
<property>
  <name>hbase.hstore.compaction.min.size</name>
  <value>134217728</value>
</property>
<!--默認值爲LONG.MAX_VALUE,
表示文件大小大於該值的store file 一定會被minor compaction排除-->
<property>
  <name>hbase.hstore.compaction.max.size</name>
  <value>9223372036854775807</value>
</property>

觸發條件

  • memstore flush

在進行 memstore flush 前後會進行判斷是否觸發 compact

  • 定期檢查線程

週期性檢查是否需要進行 compaction 操作,週期性時間由參數:hbase.server.thread.wakefrequency 決定,默認值是 10000 millseconds。

  1. major compact 大合併

合併 Store 中所有的 HFile 爲一個 HFile。

這個過程中有刪除標記的數據會真正被移除,同時超過單元格 maxVersion 的版本記錄也會被刪除。合併頻率比較低,默認 7 天執行一次,並且性能消耗非常大。建議生產關閉。在應用空閒時間手動觸發。這樣可以防止出現在業務高峯期進行 compact

觸發條件

<!--默認值爲7天進行一次大合併,-->
<property>
  <name>hbase.hregion.majorcompaction</name>
  <value>604800000</value>
</property>

手動觸發

major_compact tableName

Region 拆分機制

當 Region 中存儲的是大量的 rowkey 數據,當 Region 中的數據條數過多的時候,直接影響查詢效率。當 Region 過大的時候,HBase 就會拆分 Region。

拆分策略

HBase 的 Region Split 策略一共有以下幾種:

  1. ConstantSizeRegionSplitPolicy
  • 0.94 版本前默認切分策略

當 region 大小大於某個閾值(hbase.hregion.max.filesize=10G)之後就會觸發切分,一個 region 等分爲 2 個 region。

但是在生產線上這種切分策略卻有相當大的弊端:切分策略對於大表和小表沒有明顯的區分。閾值(hbase.hregion.max.filesize)設置較大對大表比較友好,但是小表就有可能不會觸
發分裂,極端情況下可能就 1 個,這對業務來說並不是什麼好事。如果設置較小則對小表友好,但一個大表就會在整個集羣產生大量的 region,這對於集羣的管理、資源使用、failover 來
說都不是一件好事

  1. IncreasingToUpperBoundRegionSplitPolicy
  • 0.94 版本~2.0 版本默認切分策略

切分策略稍微有點複雜,總體看和 ConstantSizeRegionSplitPolicy 思路相同,一個 region 大小大於設置閾值就會觸發切分。但是這個閾值並不像 ConstantSizeRegionSplitPolicy 是一個固定的值,而是會在一定條件下不斷調整,調整規則和 region 所屬表在當前 regionserver 上的 region 個數有關係.

region split 的計算公式是:

regioncount^3 _ 128M _ 2,當 region 達到該 size 的時候進行 split:

例如::

第一次 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 了

  1. SteppingSplitPolicy
  • 2.0 版本默認切分策略

這種切分策略的切分閾值又發生了變化,相比 IncreasingToUpperBoundRegionSplitPolicy 簡單了一些,依然和待分裂 region 所屬表在當前 regionserver 上的 region 個數有關係,如果 region 個數等於 1,切分閾值爲 flushsize*2,否則爲 MaxRegionFileSize。
這種切分策略對於大集羣中的大表、小表會比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小表不會再產生大量的小 region,而是適可而止。

  1. KeyPrefixRegionSplitPolicy

根據 rowKey 的前綴對數據進行分組,這裏是指定 rowKey 的前多少位作爲前綴,比如 rowKey 都是 16 位的,指定前 5 位是前綴,那麼前 5 位相同的 rowKey 在進行 regionsplit 的時候會分到相同的 region 中。

  1. DelimitedKeyPrefixRegionSplitPolicy

保證相同前綴的數據在同一個 region 中,例如 rowKey 的格式爲:userideventtype_eventid,指定的 delimiter 爲,則 split 的的時候會確保 userid 相同的數據在同一個 region 中

  1. DisabledRegionSplitPolicy

不啓用自動拆分, 需要指定手動拆分

拆分策略的應用

Region 拆分策略可以全局統一配置,也可以爲單獨的表指定拆分策略

  1. 通過 hbase-site.xml 全局統一配置,也可以爲單獨的表指定拆分策略
<property>
  <name>hbase.regionserver.region.split.policy</name>
  <value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>
</property>
  1. 通過 Java API 爲單獨的表指定 Region 拆分策略
HTableDescriptor tableDesc = new HTableDescriptor("test1");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, IncreasingToUpperBoundRegionSplitPolicy.class.getName());
tableDesc.addFamily(new HColumnDescriptor(Bytes.toBytes("cf1")));
admin.createTable(tableDesc);
  1. 通過 HBase Shell 爲單個表指定 Region 拆分策略
> create 'test2', {METADATA => {'SPLIT_POLICY' =>
'org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy'}},{NAME => 'cf1'}

HBase 表的預分區

  1. 爲什麼要預分區?

當一個 table 剛被創建的時候,HBase 默認分配一個 region 給 table。也就是說這個時候,所有的讀寫請求都會訪問同一個 regionServer 的同一個 region 中,這個時候就達不到負載均衡的效果了,集羣中其他的 regionServer 就可能會處於比較空閒的狀態。解決這個問題可以用 pre-splitting。在創建 table 的時候就配置好,生成多個 region。

好處就是:

  • 增加數據讀寫效率
  • 負載均衡,防止數據傾斜
  • 方便集羣容災調度 region

每個 region 維護着 startRow 與 endRowyKey,如果加入的數據符合某個 region 維護的 rowkey 範圍,則該數據交給這個 region 來維護。

  1. 手動指定預分區

create 'person','info1','info2',SPLITS => ['1000','2000','3000']

也可以把分區規則創建於文件中。

create 'student','info',SPLITS_FILE => '/root/hbase/split.txt'

Region 合併

Region 的合併不是爲了性能,而是出於維護的目的。

Region 合併的方式:

  1. 通過 Merge 類冷合併

需要先關閉 HBase 集羣。

不需要進入 hbase shell,直接執行:

合併的信息可以從頁面上獲取

hbase org.apache.hadoop.hbase.util.Merge user user,,1662823434957.f971c62e76cdff90ea957c0709099bb5. user,1000,1662823434957.366fc3c5e6237a8993cc0e143109c229.
  1. 通過 online_merge 熱合並 Region

不需要關閉 HBase 集羣,在線進行合併

與冷合併不同的是,online_merge 的傳參是 Region 的 hash 值,Region 的 hash 值就是 Region 名稱的最後那段在兩個“.”之間的字符串部分。

示例:

merge_region 'c8d1a1b7f709dfcd8b0c574b4121fdca','1d7e67e13a48b67d2d7867ca9717183c'

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章