背景
工作中有很多使用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,解决了这个问题。