HBase Bulkload 失敗問題處理以及改進

某天某應用找到我,說線上 bulkload 導入數據到 HBase 失敗

check 了一下 MR 日誌,報錯如下

org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles.groupOrSplitPhase(LoadIncrementalHFiles.java:591)|||IOException during splittingjava.util.concurrent.ExecutionException: org.apache.hadoop.hbase.io.hfile.CorruptHFileException: Problem reading HFile Trailer from file hdfs://******/*****/f1/2adb6a82818642aca73daf999063f655        at java.util.concurrent.FutureTask.report(FutureTask.java:122)        at java.util.concurrent.FutureTask.get(FutureTask.java:188)        at org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles.groupOrSplitPhase(LoadIncrementalHFiles.java:584)        at org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles.doBulkLoad(LoadIncrementalHFiles.java:440)        at org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles.doBulkLoad(LoadIncrementalHFiles.java:327)        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)        at java.lang.reflect.Method.invoke(Method.java:606)        at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:75)        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)        at java.lang.reflect.Method.invoke(Method.java:606)        at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:279) Caused by: org.apache.hadoop.hbase.io.hfile.CorruptHFileException: Problem reading HFile Trailer from file hdfs://******/*****/f1/2adb6a82818642aca73daf999063f655        at org.apache.hadoop.hbase.io.hfile.HFile.pickReaderVersion(HFile.java:495)        at org.apache.hadoop.hbase.io.hfile.HFile.createReader(HFile.java:538)        at org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles.groupOrSplit(LoadIncrementalHFiles.java:661)        at org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles$3.call(LoadIncrementalHFiles.java:574)        at org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles$3.call(LoadIncrementalHFiles.java:571)        at java.util.concurrent.FutureTask.run(FutureTask.java:262)        ... 3 moreCaused by: java.lang.UnsatisfiedLinkError: org.apache.hadoop.util.NativeCodeLoader.buildSupportsSnappy()Z        at org.apache.hadoop.util.NativeCodeLoader.buildSupportsSnappy(Native Method)        at org.apache.hadoop.io.compress.SnappyCodec.checkNativeCodeLoaded(SnappyCodec.java:63)        at org.apache.hadoop.io.compress.SnappyCodec.getDecompressorType(SnappyCodec.java:195)        at org.apache.hadoop.io.compress.CodecPool.getDecompressor(CodecPool.java:181)        at org.apache.hadoop.hbase.io.compress.Compression$Algorithm.getDecompressor(Compression.java:328)        at org.apache.hadoop.hbase.io.compress.Compression.decompress(Compression.java:423)        at org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultDecodingContext.prepareDecoding(HFileBlockDefaultDecodingContext.java:90)        at org.apache.hadoop.hbase.io.hfile.HFileBlock.unpack(HFileBlock.java:549)        at org.apache.hadoop.hbase.io.hfile.HFileBlock$AbstractFSReader$1.nextBlock(HFileBlock.java:1380)        at org.apache.hadoop.hbase.io.hfile.HFileBlock$AbstractFSReader$1.nextBlockWithBlockType(HFileBlock.java:1386)        at org.apache.hadoop.hbase.io.hfile.HFileReaderV2.<init>(HFileReaderV2.java:150)        at org.apache.hadoop.hbase.io.hfile.HFile.pickReaderVersion(HFile.java:483)        ... 8 more


上面的報錯很明顯,Bulkload  導入最後一步,執行 doBulkload 的時候,將生成的 HFile 導入到 HBase 中出現問題,原因是執行 doBulkload 的客戶端 沒有 snappy 本地庫。所以只需要添加 snappy 本地庫即可。

但是這樣處理是否有問題呢:

首先我們來看一下 bulkload 的原理:



bulkload 原理就是通過 MR/Spark 程序根據 HBase 表的 region 範圍 (startkey/endkey) 來做 partition 直接生成 HFile ,然後通過 doBulkload 命令將 HFile move 到 HBase RegionServer 的 Region 對應的列族目錄下, StoreFileManager 更新維護的 HFile 列表對象即可。bulkload 和 doBulkload 詳細原理,由於涉及的內容比較多,後面有時間的話單獨寫個博客來介紹。這裏就不展開了。

所以這裏面會使用到壓縮的地方應該有三處:

1、MR 生成 HFile 的時候

2、doBulkload 的時候

3、導入到 HBase ,然後 HBase 自身讀取/寫入/compaction 的時候

集羣是我們自己開發維護的 HBase 分支, 雖然默認已經集成了常用的 native 的庫,比如 snappyzstd ,但通常執行 bulkload 的 MR 程序或者 doBulkload 的客戶端與 HBase 不在一個集羣,例如這個本例就是。這會導致往壓縮的 HBase 表中導入數據失敗 。

基於以上的原因和問題,對 HBase Bulkload 做了一個簡單的改進:

思路很簡單:就是 bulkload 的時候,支持在客戶端設置壓縮格式,而不是直接使用原始表的壓縮格式。



雖然這個改進很簡單,但在我們的實際場景下,還是很有用的:

1、MR/doBulkload 客戶端可以設置非壓縮的格式,從而避免因爲沒有本地庫導致的失敗,也就是本文中出現的情況

2、bulkload 設置生成非壓縮的 HFile 格式,性能更好,後續compaction,仍然會根據表的壓縮格式來合併,存儲容量影響很小的情況下,提高性能.

這個特性在我們的版本中結合實現的 flush 、compaction 設置異構存儲策略、壓縮編碼以及 WAL ON SSD 可以做到數據異構以及冷熱分離,比如 flush/bulkload 生成的 HFile 到 SSD 中,並且不設置壓縮和編碼;通過compaction 執行壓縮/編碼HDD中. 這樣的話,發生在HBase 的關鍵路徑的寫入、導入、讀取、compaction 性能大幅提升。

3、在跨數據中心同步中,使用 bulkload replication 的情況下,表是未壓縮的,可以反過來,設置生成 HFile 壓縮,這樣可以減少跨數據中心的同步帶寬消耗。

該改進已經貢獻給了社區,感興趣可參考:

https://issues.apache.org/jira/browse/HBASE-21810


https://utf7.github.io/docs/hbaseconasia2019track31430-190819225905.pdf


本文分享自微信公衆號 - HBase工作筆記(HBase-Notes)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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