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及以上版本。

介绍

特点

  1. 对RegionServer不产生压力

通过快照的链接文件读取对应HFile中的数据,数据不再经过RegionServer的堆,所以站在系统角度它最大的好处就是: 对RegionServer不产生压力。

  1. 代码改动非常少!

          用于替代表读取的快照读取类中,对相关的Scan类等有足够的支持,使用者需要关心的就是维护快照,并在代码中使用initTableSnapshotMapperJob换掉initTableMapperJob,所以站在工程的角度它最大的好处是:代码改动非常少!

相关类和方法

  1. TableSnapshotInputFormat

一个可以让MapReudce程序读取Hbase快照的InputFormat。

https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormat.html

  1. 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. 如果创建不成功就隔1分钟再来试试,
  2. 如果源端这张表不需要一直在线的话,我们可以先把表disable掉再建快照。
  3. 为了避免transition,还可以暂时关闭balance
  4. 避免flush可以再创建快照时加上跳过flush的参数
  5. 默认的超时时间是60s我们后来改大到了10分钟。

读取快照失败

       在拷贝的过程中报找不到文件,通过读日志和源码我们了解到,对于快照中定义中的每个HFile,这个拷贝程序会从4个文件夹中查找,顺序是data、.tmp、mobdir、archive,原本数据可能都在data目录下,当发生compaction/split的时候,会有产生新的HFile文件,快照定义中的哪个老的文件会被转移到archive下面。理论上顺着找下来也没什么问题,但源码中有一处bug,导致找到第二个目录,就是.tmp的时候就会报错了,不会找到archive,我们做了一点调整后打成一个新的程序替换掉原来的ExportSnapshot,解决了这个问题。

你可能感兴趣的:(HBase,MapReduce)