MapReduce over HBase Snapshot
背景
工作中有很多使用HBase作為批處理源和目標的場景。之前已經做過很多優化措施,基本原則就是減少對RegionServer的影響,特別是降低RegionServer GC的時間,比如寫入時先寫HFile再BulkLoad、使用Filter儘量只讀取需要的行和列、使用G1GC等等。但是讀取HBase表資料要通過RegionServer的堆,在大批量處理的程式中可能會帶來長時間GC的情況。
能不能繞過RegionServer直接讀HFile中的資料呢?曾經考慮過直接從HFDS讀取HFile中的資料,但是要自己去處理檔案合併、資料版本、Filter等,將是一個非常複雜的工程。
直到一次機會在HBase Con Asia中看到有不少公司在使用一個Feature解決這個問題,就是HBASE-8369 MapReduce over snapshot files,支援0.98及以上版本。
介紹
特點
- 對RegionServer不產生壓力!
通過快照的連結檔案讀取對應HFile中的資料,資料不再經過RegionServer的堆,所以站在系統角度它最大的好處就是: 對RegionServer不產生壓力。
- 程式碼改動非常少!
用於替代表讀取的快照讀取類中,對相關的Scan類等有足夠的支援,使用者需要關心的就是維護快照,並在程式碼中使用initTableSnapshotMapperJob換掉initTableMapperJob,所以站在工程的角度它最大的好處是:程式碼改動非常少!
相關類和方法
- TableSnapshotInputFormat
一個可以讓MapReudce程式讀取Hbase快照的InputFormat。
https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormat.html
- TableMapReduceUtil.initTableSnapshotMapperJob
一個可以建立讀取Hbase快照的MapReduce job的方法
https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/mapreduce/TableMapReduceUtil.html
效果
當時的一個簡單的測試結果截圖,前一次是沒有使用SnapShot的
使用舉例
如果MapReduce程式中原來使用的是initTableMapperJob,那麼只要加上一段Snapshot的配置程式碼,並把initTableMapperJob換成initTableSnapshotMapperJob就可以了。
HBaseProtos.SnapshotDescription.Builder builder = HBaseProtos.SnapshotDescription.newBuilder();
final HBaseProtos.SnapshotDescription snapshotDescription = builder.setName(snapshotName).build();
try (HBaseAdmin admin = new HBaseAdmin(conf)) {
useSnapshot = admin.isSnapshotFinished(snapshotDescription);
} catch (Exception e) {
System.out.println(e.getMessage());
useSnapshot = false;
}
System.out.println("snapshot Finished:" + useSnapshot);
TableMapReduceUtil.initTableSnapshotMapperJob(snapshotName, scan, ctMapper.class,
ImmutableBytesWritable.class, Put.class, job, false, new Path("/tmp/snapshot"));
問題
建立快照失敗
我們認為可能是在建立快照時剛好有region正在做compaction\split\transition等等,還有一種可能是因為我們沒有去指定skipflush建立快照時需要做Flush,如果此時有大量資料要Flush成HFile,就會花費很多時間。
我們可以用下面的這些辦法來避免快照建立失敗:
- 如果建立不成功就隔1分鐘再來試試,
- 如果源端這張表不需要一直線上的話,我們可以先把表disable掉再建快照。
- 為了避免transition,還可以暫時關閉balance
- 避免flush可以再建立快照時加上跳過flush的引數
- 預設的超時時間是60s我們後來改大到了10分鐘。
讀取快照失敗
在拷貝的過程中報找不到檔案,通過讀日誌和原始碼我們瞭解到,對於快照中定義中的每個HFile,這個拷貝程式會從4個資料夾中查詢,順序是data、.tmp、mobdir、archive,原本資料可能都在data目錄下,當發生compaction/split的時候,會有產生新的HFile檔案,快照定義中的哪個老的檔案會被轉移到archive下面。理論上順著找下來也沒什麼問題,但原始碼中有一處bug,導致找到第二個目錄,就是.tmp的時候就會報錯了,不會找到archive,我們做了一點調整後打成一個新的程式替換掉原來的ExportSnapshot,解決了這個問題。