HBase - 生產環境上線前真的優化過嗎?

筆者今天給大家講一下 HBase 生產環境中的實踐,包括資源隔離、參數配置、性能優化等方面,部分內容參考《HBase原理與實踐》(非常建議大家好好讀一讀,一定會大有收穫),以及筆者的實戰經驗。

HBase 業務資源隔離

1. 讀寫分離場景

RegionServer 默認情況下只提供一個請求隊列給所有業務使用,導致部分延遲較高的請求影響其他對延遲敏感的業務。針對這種情況,HBase 提供了讀寫隊列隔離方案。

我們知道,HBase 有三種典型的API操作類型,分別爲 get、scan 和write,其中 get 和 scan 屬於 read 類型。默認場景下,HBase 只提供一個隊列,所有請求都會進入該隊列進行優先級排序。在一些場景下,我們要求這三種類型的訪問儘可能的互相不影響,那麼就需要在線上配置讀寫分離。

HBase 中的相關配置如下:

  1. hbase.ipc.server.callqueue.read.ratio

    如果將 hbase.ipc.server.callqueue.read.ratio 設置爲0.5,則表示有50%的線程數處理讀請求,剩餘50%用於接收寫請求。

  2. hbase.ipc.server.callqueue.scan.ratio

    如果將 hbase.ipc.server.callqueue.scan.ratio 設置爲0.5,則代表在50%的讀線程之中,再有50%的線程處理 scan,也就是全部線程的25%。

2. CPU/內存資源隔離

針對系統資源方面,HBase 提供了 RegionServer Group(RSGroup)方案。RSGroup 方案在HBase 1.4 以上版本才原生支持,但是之前 1.x 版本可以打社區 patch。不過如果使用 CDH 搭建的平臺,比如 CDH 5.13.3,HBase 1.2 版本即可支持。

爲了支持 RSGroup 功能,需要配置如下參數:

  1. <property>

  2. <name>hbase.coprocessor.master.classes</name>

  3. <value>org.apache.hadoop.hbase.rsgroup.RSGroupAdminEndpoint</value>

  4. </property>

  5. <property>

  6. <name>hbase.master.loadbalancer.class</name>

  7. <value>org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer</value>

  8. </property>

生產線上,分組原則一般遵循:

  • 在線業務和離線業務儘量劃分到不同組

  • 重要業務和邊緣業務儘量劃分到不同組

  • 非常重要的業務儘量單獨劃分到獨立組或者單獨部署集羣

使用RSGroup會自動關閉全局自動負載均衡,後續需要手工觸發。

另外要隔離系統表,要麼定義一個 system rsgroup 用來存儲所有系統表,要麼把系統表都默認放在 default rsgroup 中。所有其他用戶的表都定義在非 default 的 rsgroups 中。

根據實踐證明,筆者建議,針對 Dead 或有問題的節點,定義一個特殊的 rsgroup 是非常有用的。所有放在這個特殊的 rsgroup 中的節點是無法運行的,直到修復完成。

最後,使用 RSGroup 要注意幾點:

  1. (1) 遷移完表後記得做 major compact(本地化) 

  2. hbase(main):001:0> major_compact 'tablename'

  3. (2) 遷移完表後做 hbase hbck 校驗,防止添加遷移表的時候有部分 region 未上線的情況

  4. (3) 刪除 group 之前需要將 group 下的 regionserver table 都移除掉

  5. (4) default 組和其他的 rsgroup 不一樣,default 是動態的,其他的 group 則是靜態的

HBase HBCK

線上環境,需要定期地檢測和監控 HBase 集羣中 Region 的一致性和完整性,同時可以對損壞的集羣進行修復。

HBase HBCK 主要工作在兩種模式下:

  • 一致性檢測只讀模式

  • 多階段修復模式

HBase 集羣一致性狀態

  • HBase Region 一致性

    1. 集羣中所有 region 都被 assign,而且被分配到唯一一個 RegionServer 節點上

    2. 該 region 的狀態在內存中、hbase:meta 表中以及 zookeeper 這三個地方需要保持一致

  • HBase 表的完整性

    對於集羣中任意一張表,每個 rowkey 都僅能存在於一個 region 區間

最好制定一個週期計劃,例行地執行 hbck 命令,並在多次出現不一致的情況下發出報警信息,通知運維人員定位分析,及時解決問題。

  1. hbase hbck

  2. hbase hbck -details

  3. # 如果集羣規模大,region很多,hbck耗時很長,可以針對某些表執行:

  4. hbase hbck TableFoo TableBar

HBCK 的局部低危修復

低風險的 Region 一致性問題修復是指:

修復僅僅涉及 HBase Master 內存中 Region 狀態、ZooKeeper 臨時節點中 Region 狀態以及 hbase:meta 元數據表中 Region 狀態的修改、並不實際修改任何 HDFS 文件。

Region一致性問題修復有兩個常用選項:

  • -fixAssignments 修復 assign 相關問題,如沒有 assign、assign 不正確或者同時 assign 到多個 RegionServer 節點問題的 regions。

  • -fixMeta 主要修復 .regioninfo 文件和 hbase:meta 元數據表的不一致。修復的原則是以 HDFS 文件爲準:如果 region 在 HDFS 上存在,但在 hbase.meta 表中不存在,就會在 hbase:meta 表中添加一條記錄。反之如果在 HDFS 上不存在,而在 hbase:meta 表中存在,就會將 hbase:meta 表中對應的記錄刪除。

比如針對 HDFS Region 空洞(HDFS Region Holes)問題,解決方案可以添加 -fixHdfsHoles 選項進行修復,這個命令會在空洞形成的地方填充一個空 Region 。這個命令通常不單獨使用,而是和 -fixMeta、-fixAssignments 一起使用,如下命令組合:

  1. hbase hbck -fixAssignments -fixMeta -fixHdfsHoles

或者使用選項 -repairHoles,等價於上面的命令:

  1. hbase hbck -repairHoles

HBCK高危修復

Region 區間 overlap 相關問題的修復屬於高危修復操作,因爲這類修復通常需要修改 HDFS 上的文件,有時甚至需要人工介入。對於這類高危修復操作,建議先執行 hbck-details ,然後根據結果詳細瞭解問題細節,再執行相應的修復操作。

筆者建議在 overlap 分析的基礎上使用 merge 命令,強制將存在 overlap 的相關Region 合併到一起。需要注意的是,對於多個Region,需要兩兩合併,之後對合並後的Region 執行 Major Compaction ,再兩兩合併。

這裏需要特別注意: -repair|-fix 命令強烈不建議生產線上使用。

使用案例

接下來針對線上出現的一些問題,進行案例分析和提出問題解決的方案。

1. Region 沒有部署到任何 RegionServer 節點 

執行 hbck 命令後,確認 Region 元數據信息在 HDFS 和 hbase:meta 中都存在,但沒有部署到任何一臺 RegionServer 上,hbck 命令的輸出如下:

  1. ERROR:Region {meta => NEW_REGION_XXXXXXXXXX,\x001\x01,1566748778085.652f5c6d6623f060adeefc622d8ffead., hdfs => hdfs://xxxxx/default/NEW_REGION_XXXXXXXXXX/652f5c6d6623f060adeefc622d8ffead, deploy => } not deployed on any region server.

  2. ......

  3. ERROR: There is a hole in the region chain between and . You need to create a new .regioninfo and region dir in hdfs to plug the hole.

  4. ERROR: Found inconsistency in table NEW_REGION_XXXXXXXXXX

如果在 hbck 命令輸出的詳細的信息中看到 “not deployed on any region server”,可以使用如下命令修復:

  1. hbase hbck -fixAssignments

當然,我們也可以在 hbase shell 中執行 assign 命令部署指定 Region。

需要特別注意的是,hbck命令輸出中如果包含 “There is a hole in the region chain...“ 這樣的信息,暫時不用處理,先執行 -fixAssignments 命令,再執行 hbck 命令,看看是否還會輸出這樣的信息。

2. Region 沒有部署到任何 RegionServer 節點且元數據表中對應記錄爲空 

執行 hbck 命令檢查之後,發現 Region 元數據信息只在 HDFS 中存在,在 hbase:meta 中不存在,而且沒有部署到任何一臺 RegionServer 節點上,hbck 命令輸出如下:

  1. ERROR:Region {meta => null, hdfs => hdfs://xxxxx/default/NEW_REGION_XXXXXXXXXX/652f5c6d6623f060adeefc622d8ffead, deploy => } ON HDFS, but not listed in hbase:meta or deployed on any region server.

  2. ......

  3. ERROR: There is a hole in the region chain between and . You need to create a new .regioninfo and region dir in hdfs to plug the hole.

  4. ERROR: Found inconsistency in table NEW_REGION_XXXXXXXXXX

可以看到錯誤信息 “ON HDFS, but not listed in hbase:meta or deployed on any region server”,可以使用如下命令修復:

  1. hbase hbck -fixMeta -fixAssignments

hbck 命令輸出中如果包含 “There is a hole in the region chain...“ 這樣的信息,暫時不用處理,先執行 -fixMeta-fixAssignments 命令,再執行 hbck 命令,看看是否還會輸出這樣的信息。

3. HBase version file 丟失 

HBase 集羣啓動時會加載 HDFS 上的 version file(/hbase/hbase.version) 來確認HBase 的版本信息,如果該文件丟失或者損壞,則系統無法正常啓動。此時可以使用如下命令修復:

  1. hbase hbck -fixVersionFile

該命令重新生成一份 hbase.version 文件,文件中 HBase 集羣版本信息來自當前運行的HBCK版本。

生產環境的實踐總結:

  • 週期性地多次運行 hbck 命令,檢查是否有異常信息

  • 對錶單獨 hbck 修復,不要對整個集羣修復

  • 對於 overlap 的情況,需要管理員認真分析,再謹慎使用 hbck 命令修復。建議最大可能手工修復。

  • 如果 hbck 工具無法修復集羣的不一致,需要結合日誌進行進一步分析,決定修復方案。

HBase核心參數配置

Region

hbase.hregion.max.filesize : 

默認爲 10G,簡單理解爲 Region 中任意 hstore 所有文件大小的總和大於該值就會進行 split 。

實際生產環境中該值不建議太大,也不能太小。太大會導致系統後臺執行 compaction 消耗大量系統資源,一定程度上影響業務響應;太小會導致 Region 分裂比較頻繁(分裂本身其實對業務讀寫會有一定影響),另外單個 RegionServer 中必然存在大量 Region,太多 Region 會消耗大量維護資源,並且在 RegionSever 下線遷移時比較耗時耗資源。

綜合考慮,建議線上設置爲 50G~80G 左右。

BlockCache

不同 BlockCache 策略對應不同的參數,而且這裏參數配置會影響到 Memstore 相關參數的配置。筆者對 BlockCache 策略一直持有這樣的觀點:RegionServer 內存在20G以內的就選擇 LRUBlockCache,大於20G的就選擇BucketCache 中的 Offheap 模式。接下來所有的相關配置都基於 BucketCache 的 offheap 模型進行說明。

hfile.block.cache.size : 

默認0.4,該值用來設置LRUBlockCache的內存大小,0.4表示JVM內存的40%。

當前 HBase 系統默認採用 LRUBlockCache 策略,BlockCache 大小和 Memstore 大小均爲 JVM 的40%。但對於 BucketCache 策略來講,Cache 分爲了兩層,L1 採用LRUBlockCache,主要存儲 HFile 中的元數據 Block,L2 採用 BucketCache,主要存儲業務數據 Block。因爲只用來存儲元數據 Block,所以只需要設置很小的 Cache 即可。建議線上設置爲 0.05~0.1 左右。

hbase.bucketcache.ioengine : 

BucketCache 策略的模式選擇,可選擇 heap、offheap 以及 file 三種,分別表示使用堆內內存、堆外內存以及 SSD 硬盤作爲緩存存儲介質。

hbase.bucketcache.size : 

堆外存大小,設置的大小主要依賴物理內存大小。

配置file模式的參數(線上環境針對內存資源不足,某段時間使用 SSD 存儲 cache):

  1. # SSD

  2. hbase.bucketcache.ioengine=file:/disk/disk11/hbase_ssd/cache.data

  3. hbase.bucketcache.size=20GB

Memstore

hbase.hregion.memstore.flush.size : 

默認 128M(134217728),memstore 大於該閾值就會觸發 flush。如果當前系統 flush 比較頻繁,並且內存資源比較充足,可以適當將該值調整爲 256M。調大的副作用可能是造成宕機時需要分裂的 hlog 數量變多,從而延長故障恢復時間。

hbase.hregion.memstore.block.multiplier : 

默認值爲 4,表示一旦某 region 中所有寫入 memstore 的數據大小總和達到或超過閾值 hbase.hregion.memstore.block.multiplier*hbase.hregion.memstore.flush.size,就會執行 flush 操作,並拋出 RegionTooBusyException 異常。

該值在 HBase 目前版本中默認值爲 4,大家可以檢查一下 HBase 版本的配置值,記得舊的版本默認值爲 2,比較小,需要調整。如果日誌中出現如下內容:

  1. RegionTooBusyException: Above memstore limit, regionName=xxxxx ...

這個是 Region 的 memstore 佔用內存大小超過正常的 4 倍,這時候會拋異常,寫入請求會被拒絕,客戶端開始重試請求。當達到 128MB 的時候會觸發 flush memstore,當達到128M * 4 還沒法觸發 flush 時候會拋異常來拒絕寫入。

上面的情況,就需要考慮修改該參數值了。

hbase.regionserver.global.memstore.size : 

默認值爲 0.4,表示佔用總 JVM 內存大小的 40%,該參數非常重要,整個 RegionServer 上所有寫入 memstore 的數據大小總和不能超過該閾值,否則會阻塞所有寫入請求並強制執行 flush 操作,直至總 memstore 數據大小降到hbase.regionserver.global.memstore.lowerLimit 以下。

該值在 offheap 模式下需要配置爲 0.6~0.65。一旦寫入出現阻塞,立馬查看日誌定位,錯誤信息類似如下:

  1. regionserver.MemStoreFlusher: Blocking updates on hostname,16020,1522286703886: the global memstore size 1.3 G is >= than blocking 1.3 G size

  2. regionserver.MemStoreFlusher: Memstore is above high water mark and block 528ms

一般情況下不會出現這類異常,如果出現需要明確是不是 region 數目太多、單表列族設計太多或者該參數設置太小。

hbase.regionserver.global.memstore.lowerLimit : 

默認值 0.95,表示 RegionServer 級別總 MemStore 大小的低水位是 hbase.regionserver.global.memstore.size 的 95%。這個參數表示 RegionServer 上所有寫入 MemStore 的數據大小總和一旦超過這個閾值,就會挑選最大的 MemStore 執行強制flush操作。

hbase.regionserver.optionalcacheflushinterval : 

默認值爲 3600000(即 1 小時),hbase 會起一個線程定期 flush 所有 memstore,時間間隔就是該值配置。

生產線上該值建議設大,比如 10h。因爲很多場景下1小時 flush 一次會導致產生很多小文件,一方面導致 flush 比較頻繁,一方面導致小文件很多,影響隨機讀性能。因此建議設置較大值。

Compaction

compaction 模塊主要用來合併小文件,刪除過期數據、delete 數據等。涉及參數較多,對於系統讀寫性能影響也很重要,下面主要介紹部分比較核心的參數。

hbase.hstore.compactionThreshold : 

默認值爲 3,compaction 的觸發條件之一,當 store 中文件數超過該閾值就會觸發compaction。通常建議生產線上寫入較高的系統調高該值,比如 5~10 之間。

如在任意一個 hstore 中有超過此數量的 HStoreFiles,則將運行壓縮以將所有 HStoreFiles 文件作爲一個 HStoreFile 重新寫入。(每次 memstore 刷新寫入一個 HStoreFile)您可通過指定更大數量延長壓縮,但壓縮將運行更長時間。在壓縮期間,更新無法刷新到磁盤。長時間壓縮需要足夠的內存,以在壓縮的持續時間內記錄所有更新。如太大,壓縮期間客戶端會超時。

hbase.hstore.compaction.max : 

默認值爲 10,最多可以參與 minor compaction 的文件數。該值通常設置爲 hbase.hstore.compactionThreshold 的 2~3 倍。

hbase.regionserver.thread.compaction.throttle : 

默認值爲 2G,評估單個 compaction 爲 small 或者 large 的判斷依據。爲了防止 large compaction 長時間執行阻塞其他 small compaction,HBase 將這兩種 compaction 進行了分離處理,每種 compaction 會分配獨立的線程池。

hbase.regionserver.thread.compaction.large/small : 

默認值爲 1,large 和 small compaction 的處理線程數。生產線上建議設置爲 5,強烈不建議再調太大(比如10),否則會出現性能下降問題。

在寫入負載比較高的集羣,可以適當增加這兩個參數的值,提高系統 Compaction 的效率。但是這兩個參數不能太大,否則有可能出現 Compaction 效率不增反降到現象,要結合生產環境測試。

hbase.hstore.blockingStoreFiles :

默認值爲10,表示一旦某個 store 中文件數大於該閾值,就會導致所有更新阻塞。生產線上建議設置該值爲 100,避免出現阻塞更新,一旦發現日誌中出現如下日誌信息:

  1. too many store files; delaying flush up to 90000ms

這時就要查看該值是否設置正確了。

hbase.hregion.majorcompaction : 

默認值爲 604800000(即 一週),表示 major compaction 的觸發週期。

生產線上建議大表手動執行 major compaction,需要將此參數設置爲0,即關閉自動觸發機制。

HLog

hbase.regionserver.maxlogs : 

默認值爲 32,region flush 的觸發條件之一,WAL 日誌文件總數超過該閾值就會強制執行 flush 操作。該默認值對於很多集羣來說太小,生產線上具體設置參考HBASE-14951

可以參考如下:

  1. heap memstore perc maxLogs

  2. 1G 40% 32

  3. 2G 40% 32

  4. 10G 40% 80

  5. 20G 40% 160

  6. 32G 40% 256

hbase.regionserver.hlog.splitlog.writer.threads : 

默認值爲 3,regionserver 恢復數據時日誌按照 region 切分之後寫入 buffer,重新寫入HDFS 的線程數。生產環境因爲 region 個數普遍較多,爲了加速數據恢復,建議設置稍微大點,比如 10。

請求隊列相關參數

hbase.regionserver.handler.count : 

默認值爲 30,服務器端用來處理用戶請求的線程數。生產線上通常需要將該值調到 100~200。

用戶關心的請求響應時間由兩部分構成:排隊時間和服務時間,即 response time = queue time + service time。優化系統需要經常關注排隊時間,如果用戶請求排隊時間很長,首要關注的問題就是 hbase.regionserver.handler.count 是否沒有調整。

hbase.ipc.server.callqueue.handler.factor : 

默認值爲 0,服務器端設置隊列個數,假如該值爲 0.1,那麼服務器就會設置 handler.count*0.1=30*0.1=3 個隊列。

hbase.ipc.server.callqueue.read.ratio : 

默認值爲 0,服務器端設置讀寫業務分別佔用的隊列百分比以及 handler 百分比。假如該值爲0.5,表示讀寫各佔一半隊列,同時各佔一半 handler。

hbase.ipc.server.call.queue.scan.ratio : 

默認值爲 0,服務器端爲了將 get 和 scan 隔離需要設置該參數。

隊列相關參數設置比較複雜,爲了方便理解,舉例如下:

  1. <property>

  2. <name>hbase.regionserver.handler.count</name>

  3. <value>100</value>

  4. </property>

  5. <!--RegionServer會設置100*0.1=10個隊列處理用戶的請求-->

  6. <property>

  7. <name>hbase.ipc.server.callqueue.handler.factor</name>

  8. <value>0.1</value>

  9. </property>

  10. <!--10個隊列中分配5(10*0.5)個隊列處理用戶的讀請求,另外5個隊列處理用戶的寫請求-->

  11. <property>

  12. <name>hbase.ipc.server.callqueue.read.ratio</name>

  13. <value>0.5</value>

  14. </property>

  15. <!--5個隊列中分配1(5*0.2)個隊列處理用戶的scan請求,另外4個隊列處理用戶的get請求-->

  16. <property>

  17. <name>hbaes.ipc.server.callqueue.scan.ratio</name>

  18. <value>0.2</value>

  19. </property>

其他重要參數

hbase.online.schema.update.enable : 

默認值爲 true,表示更新表 schema 的時候不再需要先 disable 再 enable,直接在線更新即可。該參數在HBase 2.0之後默認爲true。

生產線上建議設置爲true。

hbase.quota.enabled : 

默認值爲 false,表示是否開啓 quota 功能,quota 的功能主要是限制用戶/表的 QPS,起到限流作用。

hbase.snapshot.enabled : 

默認值爲 true,表示是否開啓 snapshot 功能,snapshot 功能主要用來備份 HBase 數據。

生產線上建議設置爲true。

zookeeper.session.timeout : 

默認值爲 180s,表示 Zookeeper 客戶端與服務器端 session 超時時間,超時之後 RegionServer 將會被踢出集羣。

有兩點需要重點關注:其一是該值需要與 Zookeeper 服務器端 session 相關參數一同設置纔會生效。但是如果一味的將該值增大而不修改 Zookeeper 服務端參數,可能並不會實際生效。其二是通常情況下離線集羣可以將該值設置較大,在線業務需要根據業務對延遲的容忍度考慮設置。

hbase.zookeeper.useMulti : 

默認值爲 true,表示是否開啓 ZooKeeper 的 multi-update 功能,該功能在某些場景下可以加速批量請求完成,而且可以有效防止部分異常問題。

生產線上建議設置爲 true。主要設置爲 true 的前提是 ZooKeeper 服務端的版本爲3.4以上,否則會出現 ZooKeeper 客戶端夯住的情況。

hbase.coprocessor.master.classes : 

生產線上建議設置 org.apache.hadoop.hbase.security.access.AccessController,可以使用 grant 命令對 namespace、table、cf 設置訪問權限。

hbase.coprocessor.region.classes : 

生產線上建議設置爲 org.apache.hadoop.hbase.security.token.TokenProvider,org.apache.hadoop.hbase.security.access.AccessController,含義如上。

說明

上面只是核心參數的一部分,其他的參數,比如 Kerberos、Replication、Rest、Thrift 和 HDFS Client 等相關模塊等參數沒有涉及,請參閱資料。

另外,在 HBase 1.0 版本之後,開始支持在線配置更新,可以在不重啓 Region Server 的情況下更改部分配置。

HBase 表設計

表名

命名空間加表名,不同業務使用不同的命名空間。

列簇屬性設置

  • VERSIONS

    系統保留的最大版本數,默認爲 1。

  • BLOCKCACHE

    是否開啓 BlockCache,默認爲 true。如果該值爲 true,數據 Block 從 HFile 加載出來後會被放入讀緩存,提供讀請求讀取。

  • BLOOMFILTER

    布隆過濾器類型,可選項爲 NONE、ROW 和 ROWCOL 。默認爲 ROW。布隆過濾器可以用於檢索一個元素是否在一個集合中,提高隨機讀的效率。ROWCOL 模式只對指定列的隨機讀有優化作用,如果只是根據 rowkey 查詢,沒有指定列,ROWCOL 不起作用通常使用 ROW 模式。

  • TTL(Time To Live)

    數據失效時間。HBase TTL 過期的數據是通過 Compaction 機制進行刪除的。

  • COMPRESSION

    壓縮算法,可選項爲 LZO、GZ、NONE、SNAPPY 和 LZ4。理論上,SNAPPY 算法的壓縮率可以達到 5:1 甚至更高。

    從理論上講,數據壓縮不是 KV 級別的,而是文件 Block 級別的操作。HBase 在寫入 Block 到 HDFS 之前首先對數據塊進行壓縮,再寫入底層存儲。讀數據如果需要涉及到讀取 HDFS 文件時,則首先從 HDFS 中加載出 Block 之後進行解壓縮,然後緩存到 BlockCache,最後返回給使用的用戶。經過測試,生產線上一般推薦使用 SNAPPY。

  • DATA_BLOCK_ENCODING

    數據編碼算法,可選項 NONE、PREFIX、DIFF、FAST_DIFF 和 ROW_INDEX_V1。和壓縮一樣,編碼最直接、最重要的作用也是減少數據存儲成本,但是消耗大量CPU資源。

    如果使用 HBase 1.x 版本,還有 PREFIX_TREE 編碼,但是此編碼存在很多問題,比如會引起 Compaction 一直卡住(HBASE-12959),此外還可能造成 Scan miss(HBASE-12817)等原因,不建議生產使用。

    HBase 2.0 版本開始,PREFIX_TREE 已經被移除了。

  • BLOCKSIZE

    HBase 數據塊大小。Block 是 HBase 系統文件層寫入、讀取的最小粒度,默認塊大小爲 64K。

    對於不同的業務數據,塊大小的合理設置對讀寫性能有很大的影響。通常來說,如果業務請求以 get 請求爲主,可以考慮將塊設置較小;如果以 scan 請求爲主,可以將塊調大;默認的 64K 塊大小是在 scan 和 get 之間取得的一個平衡。

    調整時,一定要進行充分測試,再決定是否部署生產。

  • DFS_REPLICATION

    數據 Block 在 HDFS 上存儲的副本數,默認爲 HDFS 系統設置的值(dfs.replication)。

  • IN_MEMORY

    如果表中某些列的數據量不大,但是進行 get 和 scan 操作的頻率又特別高,同時業務要求延時低,此時可以採用 IN_MEMORY 效果比較好。

表屬性設置

1. 預分區設置屬性

不經過預分區設置的業務通常在後期出現數據分佈不均衡的情況,造成讀寫請求不均衡,嚴重時出現寫入阻塞,讀取延遲不可控,甚至影響整個集羣其他業務。因此,建議所有業務表上線必須做預分區處理。

與預分區相關的配置項主要有 NUMREGIONS 和 SPLITALGO 。NUMREGIONS 表示預分區個數,該屬性設置由業務表預估數據量、規劃 Region 大小等因素共同決定。

SPLITALGO 表示切分策略,可選項有 UniformSpilt 和 HexStringSplit 兩種:

  • HexStringSplit 策略 適用於 rowkey 前綴是十六進制字符串的場景,比如經過 MD5 編碼爲十六進制的 rowkey;

  • UniformSpilt 策略 適用於 rowkey 是比較隨機的字符數組的場景,比如經過某些 hash 算法轉換爲字節數組的 rowkey。

當然,用戶也可以通過實現 org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm 接口定製實現自己業務表的切分策略。

使用示例:

  1. # create table with four regions based on random bytes keys

  2. hbase>create 't2','f1', { NUMREGIONS => 4 , SPLITALGO => 'UniformSplit' }

  3. # create table with five regions based on hex keys

  4. hbase>create 't3','f1', { NUMREGIONS => 5, SPLITALGO => 'HexStringSplit'

當然也可以通過 Ruby 創建:

  1. # generate splits for long (Ruby fixnum) key range from start to end key

  2. hbase(main):070:0> def gen_splits(start_key,end_key,num_regions)

  3. hbase(main):071:1> results=[]

  4. hbase(main):072:1> range=end_key-start_key

  5. hbase(main):073:1> incr=(range/num_regions).floor

  6. hbase(main):074:1> for i in 1 .. num_regions-1

  7. hbase(main):075:2> results.push([i*incr+start_key].pack("N"))

  8. hbase(main):076:2> end

  9. hbase(main):077:1> return results

  10. hbase(main):078:1> end

  11. hbase(main):079:0>

  12. hbase(main):080:0> splits=gen_splits(1,2000000,10)

  13. => ["\000\003\r@", "\000\006\032\177", "\000\t'\276", "\000\f4\375", "\000\017B<", "\000\022O{", "\000\025\\\272", "\000\030i\371", "\000\ew8"]

  14. hbase(main):081:0> create 'test_splits','f',SPLITS=>splits

  15. 0 row(s) in 0.2670 seconds

  16. => Hbase::Table - test_splits

2. MAX_FILESIZE 

最大文件大小,功能與配置文件中 hbase.hregion.max.filesize 的配置項相同,默認爲10G。

Region 中最大的 Store 所有文件大小總和一旦大於該值,整個 Region 就會執行分裂。

綜合考慮,建議線上設置爲5G-30G。

3. READONLY 

只讀表,默認爲 false。

4. COMPACTION_ENABLED

Compaction 是否開啓,默認爲 true,表示允許 Minor/Major Compaction 自動執行。

5. MEMSTORE_FLUSHSIZE 

單個 MemStore 的大小,功能與配置文件中 hbase.hregion.memstore.flush.sizse 的配置項相同,默認爲 128M。

如果要求寫入吞吐量非常大,可以將該值設置較大。

6. DURABLITY 

WAL 持久化等級,默認爲 SYNC_WAL。其他可選項有 SKIP_WAL、ASYNC_WAL 以及 FSYNC_WAL。根據業務的重要程度以及寫入吞吐量的要求綜合考慮該配置項的設置,比如部分業務寫入吞吐量非常大,但數據並不是很重要,允許在異常情況下丟失部分數據,則可以選擇 SKIP_WAL 或者 ASYNC_WAL。

將一些參數提升到表級別,甚至列簇級別,非常方便業務定製化,不需要重啓集羣。

Salted Table

如果 rowkey 本身不具備前綴散列性,例如時間戳,如果把時間戳作爲 rowkey,連續的時間戳會存在同一個 Region,造成數據熱點問題。

因此對 rowkey 做哈希就是一種很好的解決數據熱點的方式。

例如,業務要存放的 rowkey = row1,通過哈希算法算出來一個前綴: PREFIX=MD5SUM(rowkey)%4,實際在 HBase 中存放的的 rowkey=PREFIX+row1

在創建表的時候,把表預分區爲 5 個 Regions:

  • region-00 對應區間 (-oo,01)

  • region-01 對應區間 [01,02)

  • region-02 對應區間 [02,03)

  • region-03 對應區間 [03,+oo)

這樣,很好地保證了每一個 rowkey 都隨機、均勻地落在不同的 region 上,解決了數據熱點的問題。在 get 操作的時候,假設待讀取的 rowkey=rowl,則先算出 HBase 中實際存儲的 rowkey=MD5SUM(row1)%4+row1,按照這個 rowkey 去 get 數據即可。

但是,對於 Salted Table 的 scan 操作,就會稍微麻煩一點,會轉換爲多個 Region 的多路歸併算法(HBase 的 Release 中未實現,可以藉助 Phoenix),性能上比正常要差不少。

HBase-HDFS 調優策略

1. Short-Circuit Local Read

當前 HDFS 讀取數據都需要經過 DataNode,客戶端會向 DataNode 發送讀取數據的請求,DataNode 接收到請求後從磁盤中將數據讀取出來,再通過 TCP 發送給客戶端。

對於本地數據,Short Circuit Local Read 策略允許客戶端繞過 HDFS DataNode 直接從磁盤讀取本地數據,減少多次網絡傳輸開銷,讀取效率更高。

開啓 Short Circuit Local Read,配置參數:

  1. <configuration>

  2. <property>

  3. <name>dfs.client.read.shortcircuit</name>

  4. <value>true</value>

  5. </property>

  6. <property>

  7. <name>dfs.domain.socket.path</name>

  8. <value>/var/lib/hadoop-hdfs/dn_socket</value>

  9. </property>

  10. <property>

  11. <name>dfs.client.read.shortcircuit.buffer.size</name>

  12. <value>131072</value>

  13. </property>

  14. </configuration>

需要注意的是 dfs.client.read.shortcircuit.buffer.size 參數默認值爲 1M,對於 HBase 系統來說有可能造成 OOM(HBASE-8143)。

2. Hedged Read

HBase 數據在 HDFS 中默認存儲 3 個副本,通常情況下,HBase 會根據一定算法優先選擇一個 DataNode 進行數據讀取。根據 Hedged Read 策略,如果在指定時間內讀取請求沒有返回,HDFS 客戶端就會向第二個副本發送第二次數據請求,並且誰先返回就使用誰,之後返回的將會被丟棄。

開啓 Hedged Read 功能,設置:

  1. <configuration>

  2. <property>

  3. <name>dfs.client.hedged.read.threadpool.size</name>

  4. <value>20</value> <!--20 threads-->

  5. </property>

  6. <property>

  7. <name>dfs.client.hedged.read.threshold.millis</name>

  8. <value>10</value> <!--10 milliseconds-->

  9. </property>

  10. </configuration>

其中,參數 dfs.client.hedged.read.threadpool.size 表示用於 hedged read 的線程池線程數量,默認爲 0,表示關閉 hedged read 功能。參數 dfs.client.hedged.read.threshold.millis 表示 HDFS 數據讀取超時時間,超過這個閾值,HDFS客戶端將會再發起一次讀取請求。

3. Region Data Locaity

Region Data Locaity,即數據本地率,表示當前 Region 的數據在 Region 所在節點存儲的比例。提高本地化率,可以有效優化隨機讀性能。

數據本地化率低通常是由於 Region 遷移(自動 balance 開啓、RegionServer 宕機遷移、手工遷移等)導致的,因此可以通過避免 Region 無故遷移來維護數據高本地率,具體措施有關閉自動balance,RegionServer 宕機及時拉起並遷回遷移走的 Region 等。另外,如果數據本地化率很低,還可以在業務低峯期通過執行 major_compact 將數據本地化率提升到 100%。

執行 major_compact 提升數據本地率的理論依據是,major_compact 本質上是將 Region 中的所有文件讀取出來然後寫入一個大文件,寫大文件必然會在本地 DataNode 生成一個副本。

HBase 讀取性能優化

HBase服務器優化

1. 讀請求是否均衡

Rowkey 必須進行散列化處理,同時建表必須進行預分區處理。

2. BlockCache 設置是否合理

如果 JVM 內存配置量小於 20G,BlockCache 策略選擇 LRUBlockCache;否則選擇 BucketCache 策略的 offheap 模式。

3. HFile 文件是否太多

一個 Store 中包含多個 HFile 文件,文件越多,檢索所需的 IO 次數越多,讀取延遲也越高。文件數量通常取決於 Compaction 的執行策略,一般和兩個配置參數有關: hbase.hstore.compactionThreshold 和 hbase.hstore.compaction.max.size ,前者表示一個 store 中的文件數超過閾值就應該進行合併,後者表示參與合併的文件大小最大是多少,超過此大小的文件不能參與合併。

可以查看 RegionServer 級別以及 Region 級別的HFile數量,確認 HFile 文件是否過多。

hbase.hstore.compactionThreshold 設置不能太大,默認爲3個。

4. Compaction 是否消費系統資源過多

對於大 Region 讀延遲敏感的業務(100G以上)通常不建議開啓自動 Major Compaction,手動低峯期觸發。小 Region 或者延遲不敏感的業務可以開啓 Major Compaction,但建議限制流量。

5. 數據本地率是不是很低

儘量避免 Region 無故遷移。對於本地化率較低的節點,可以在業務低峯期執行 major_compact。

HBase客戶端優化

1. scan 緩存是否設置合理

大 scan 場景下將 scan 緩存從 100 增大到 500 或者 1000,用以減少 RPC 次數。

2. get 是否使用批量請求

HBase 分別提供了單條 get 以及批量 get 的 API 接口,使用批量 get 接口可以減少客戶端到 RegionServer 之間的 RPC 連接數,提高讀取吞吐量。

3. 請求是否可以顯式指定列簇或者列

儘量指定列簇或者列進行精確查詢。

4. 離線批量讀取請求是否設置禁止緩存

離線批量讀取請求設置禁用緩存,scan.setCacheBlocks(false)

HBase列簇設計優化

建議,任何業務都應該設置布隆過濾器,通常設置爲 row,除非確定業務隨機查詢類型爲 row + column,則設置爲 rowcol。

HBase 寫入性能調優

HBase 服務器端優化

1. Region 是否太少

在表的 Region 數量小於 RegionServer 節點數的場景下,需要將切分部分請求負載高的Region,並遷移到其他 RegionServer 節點上。

2. 寫入請求是否均衡

檢查 RowKey 設計以及預分區策略,保證寫入請求均衡。

3. 使用 SSD 存儲 WAL

將 WAL 文件寫到SSD上,對於寫性能會有非常大的提升。

使用該特性配置步驟:

  • 使用 HDFS Archival Storage 機制,配置 HDFS 的部分文件目錄爲 SSD 介質

  • hbase-site.xml 添加配置

  1. <property>

  2. <name>hbase.wal.storage.policy</name>

  3. <value>ONE_SSD</value>

  4. </property>

hbase.wal.storage.policy 默認爲 none,用戶可以指定 ONESSD(WAL 一個副本寫入 SSD 介質)或者 ALLSSD(WAL的三個副本全部寫入 SSD 介質)。

HBase客戶端優化

1. 是否可以使用 Bulkload 方案寫入

Bulkload 是一個 MapReduce 程序,輸出 HFile 文件。

2. 是否需要寫WAL?WAL是否需要同步寫入

數據寫入流程可以理解爲 一次順序寫WAL+一次寫緩存

WAL 的持久化分爲四個等級:

  • SKIP_WAL

  • ASYNC_WAL

  • SYNC_WAL

  • FSYNC_WAL

默認爲 SYNC_WAL 等級持久化數據。

根據業務關注點在 WAL 機制和寫入吞吐量之間作出選擇,用戶可以通過客戶端設置 WAL 持久化策略。

3. Put 是否可以同步批量提交

類似 Get 接口。

4. Put 是否可以異步批量提交

開啓異步批量提交,用戶可以設置 setAutoFlush(false),客戶端緩存達到閾值(默認2M)後批量提交給 RegionServer。如果客戶端異常,緩存數據可能丟失。

5. 寫入 KeyValue 數據是否太大

KeyValue 大小對寫入性能影響巨大。

參考

  • 《HBase原理與實踐》

  • http://hbase.apache.org/book.html

發佈了272 篇原創文章 · 獲贊 99 · 訪問量 105萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章