HBase骚操作之数据加载方式BulkLoad


目 录

0 引言

1 原理

2 BulkLoad的使用场景

3 HBase命令行实现

4 Java代码实现

5 小 结


0 引言

 通常 MapReduce 在写HBase时使用的是 TableOutputFormat 方式,在reduce中直接生成put对象写入HBase,该方式在大数据量写入时效率低下(HBase会block写入,频繁进行flush,split,compact等大量IO操作),并对HBase节点的稳定性造成一定的影响(GC时间过长,响应变慢,导致节点超时退出,并引起一系列连锁反应)。针对上述问题本文研究了一种HBase BulkLoad的入库方式,该方式利用HBase的数据信息按照特定格式存储在hdfs内这一原理,直接在HDFS中生成持久化的HFile数据格式文件,然后上传至合适位置,即完成巨量数据快速入库的办法。该方式配合MapReduce完成,高效便捷,而且不占用Region资源,增添负载,在大数据量写入时能极大的提高写入效率,并降低对Hbase节点的写入压力。

    通过使用先生成HFile,然后利用BuckLoad到Hbase的方式来替代之前直接调用HTableOutputFormat的方法有如下的好处:

  •   (1)减小HBase集群插入数据的压力
  •   (2)提供了job的运行速度,降低了job的执行时间
  •   (3)使用HBase API相比,使用Bulkload导入数据占用更少的CPU和网络资源。

1 原理

 按照HBase存储数据按照HFile格式存储在HDFS的原理,使用MapReduce直接生成HFile格式的数据文件,然后在通过RegionServer将HFile数据文件移动到相应的Region上去。流程如下图所示:

BulkLoad涉及三个过程:

  • 1.   Transform阶段:使用MapReduce将HDFS上的数据生成HBase的底层HFile数据。
  • 2.    Load阶段:根据生成的目标HFile,利用HBase提供的BulkLoad工具将HFile Load到HBase的region中。
  • 3.   加载完数据后原来生成的HFile文件将会被移除(也就是load的过程其实就是文件剪切的过程,此过程类似于hive的load的过程)

注意:在bulkLoading执行之前要提前把数据导入到hdfs上,因为mapreduce只能读取HDFS上的数据;如果原始数据在hdfs上占用100G大小的空间,那么hdfs上的预留的空间大小要大于200G,因为数据要首先生成hfile也是放在hdfs临时目录下。

2 BulkLoad的使用场景

  bulkload适合的场景:(批处理)

 (1)大量数据一次性加载到HBase。(首次将原始数据载入HBase)

 (2)对数据加载到HBase可靠性要求不高,不需要生成WAL文件。

 (3)使用put加载大量数据到HBase速度变慢,且查询速度变慢时。

 (4)加载到HBase新生成的单个HFile文件大小接近HDFS block大小。

  (5) 数据需要源于其他位置:需要将其他业务库的数据合并到HBase中,可以从源系统中将数据定期批量加载

      到HBase中。

 (6)要定期加载新数据,使用BulkLoad并按照自己的理想时间间隔分批次导入数据。注意如果频繁导入大量

     HFile可能会导致更频繁地发生大型压缩,从而对性能产生负面影响。

     可以通过以下方法缓解此问题:

     调整压缩设置,确保不触发压缩即可存在的最大 HFile 文件数很高,并依赖于其他因素,如Memstore

     的大小触发压缩。

  put适合的场景:(实时处理)
 
 (1) 每次加载到单个Region的数据大小小于HDFS block大小的一半。

 (2) 数据需要实时加载。

 (3) 加载数据过程不会造成用户查询速度急剧下降。

3 HBase命令行实现

    BulkLoad会将tsv/csv格式的文件通过MapReduce任务直接生成HBase的HFile文件,然后再将数据导入集群。使用bulk load最简单的方式是使用ImportTsv,ImportTsv是一个内置的工具MapReduce任务的方式,可以将TSV文件中的文本数据直接的导入到HBase的表中,或者导入到HBase已经格式化的文件中

  • tsv格式的文件:字段之间以制表符\t分割
  • csv格式的文件:字段之间以逗号,分割

  在使用bulkload方式导入数据之前先用 ImportTsv做一个数据导入的测试

(1)案例1:利用ImportTsv将CSV文件导入Hbase

        1)数据准备

        创建test.csv文件

       2) 上传数据至HDFS文件系统中

[root@bigdata3 dan_test]# hadoop fs -put test.csv /test

 查看如下:

      3)创建Hbase表

hbase(main):002:0> create 'test_csv','cf'
0 row(s) in 2.4510 seconds

=> Hbase::Table - test_csv

    4)执行导入命令

hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \
-Dimporttsv.separator="," \
-Dimporttsv.columns=HBASE_ROW_KEY,cf test_csv /test/test.csv

 -Dimporttsv.separator=","   表示指定的分隔符为逗号

-Dimporttsv.columns=HBASE_ROW_KEY,cf test_csv /test/test.csv   HBASE_ROW_KEY表示RowKey,cf指定的额列簇,test_csv表示HBase中要导入的表,/test/test.csv 表示hdfs中被导入的文件地址。

 MapReduce运行过程如下图所示

    5)到HBase shell中查看结果如下

  可以看到HBase中数据已经被导入进来。 耗时2419ms

  (2) 案例2:利用bulkload的方式导入数据

        1)step1:先通过ImportTsv生成HFile文件

hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \
-Dimporttsv.separator="," \
-Dimporttsv.bulk.output=/test/hfile_tmp \
-Dimporttsv.columns=HBASE_ROW_KEY,cf test_csv_02 /test/test.csv

        注意 :此步操作与上一步ImportTsv导入文件操作中多了一个-Dimporttsv.bulk.output=/test/hfile_tmp,这个是指定生成HFile文件目录的地方,这里将生成的HFile文件放在hdfs的/test/hfile_tmp目录下。此时不用预先在HBase中创建表test_csv_02,执行该命令后会自动帮你创建该表。

        mr执行结果如下

           查看生成的HFile结果

          可以看到在/test/hfile_tmp目录下有文件生成,具体生成文件形式如上图所示。

         继续查看可以看到列簇文件夹下有文件生成   

         查看文件内容如下:

         查看HBase中是否生成test_csv_0

        可以看到该表已被创建,且无数据。

       生成HFile的另一种写法可以用通用的命令格式如下所示:

HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase classpath` hadoop jar ${HBASE_HOME}/lib/hbase-server-version.jar importtsv -Dimporttsv.bulk.output=<输出文件夹路径> -Dimporttsv.separator=<分割符> -Dimporttsv.columns=<key和列映射> <目标表> <数据源路径>

        2)step2:利用completebulkload将数据导入Hbase

      completebulkload 会将上一步生成的StoreFiles导入到HBase中,导入成功后自动删除这些中间文件。生成的HFile必须尽快的去load到表中,在第一个步骤中HFile生成的规则是一个region一个文件,如果不尽快加载一旦线上的region发生分裂就会造成加载的性能下降。

          运行如下命令

HADOOP_CLASSPATH=`/usr/idp/1.1.0.0-0131/hbase/bin/hbase classpath` \
hadoop jar /usr/idp/1.1.0.0-0131/hbase/lib/hbase-server-1.1.2.1.1.0.0-0131.jar \
completebulkload hdfs://iotcluster/test/hfile_tmp test_csv_02

     到hbase上查看test_csv_02看是否数据导入

  可以看到数据被导入进来。

  最后查看hdfs上的HFile文件可以看到该文件的内容已经被移除

 将completebulkload使用方法总结成通用的命令格式如下所示:

HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase classpath` hadoop jar ${HBASE_HOME}/lib/hbase-server-version.jar completebulkload <生成的HFile路径> <目标表名称> 

4 Java代码实现

(1)使用MapReduce生成HFile文件

public class IteblogBulkLoadMapper extends Mapper<LongWritable, Text, ImmutableBytesWritable, Put>{
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            String[] items = line.split("\t");
  
            ImmutableBytesWritable rowKey = new ImmutableBytesWritable(items[0].getBytes());
            Put put = new Put(Bytes.toBytes(items[0]));   //ROWKEY
            put.addColumn("f1".getBytes(), "url".getBytes(), items[1].getBytes());
            put.addColumn("f1".getBytes(), "name".getBytes(), items[2].getBytes());
            
            context.write(rowkey, put);
        }
}

(2) 驱动程序

public class IteblogBulkLoadDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        final String SRC_PATH= "hdfs://iteblog:9000/user/iteblog/input";
        final String DESC_PATH= "hdfs://iteblog:9000/user/iteblog/output";
        Configuration conf = HBaseConfiguration.create();
       
        Job job=Job.getInstance(conf);
        job.setJarByClass(IteblogBulkLoadDriver.class);
        job.setMapperClass(IteblogBulkLoadMapper.class);
        job.setMapOutputKeyClass(ImmutableBytesWritable.class);
        job.setMapOutputValueClass(Put.class);
        job.setOutputFormatClass(HFileOutputFormat2.class);
        HTable table = new HTable(conf,"blog_info");
        HFileOutputFormat2.configureIncrementalLoad(job,table,table.getRegionLocator());
        FileInputFormat.addInputPath(job,new Path(SRC_PATH));
        FileOutputFormat.setOutputPath(job,new Path(DESC_PATH));
          
        System.exit(job.waitForCompletion(true)?0:1);
    }
}

(3) 通过BlukLoad方式加载HFile文件

public class LoadIncrementalHFileToHBase {
    public static void main(String[] args) throws Exception {
            Configuration configuration = HBaseConfiguration.create();
            HBaseConfiguration.addHbaseResources(configuration);
            LoadIncrementalHFiles loder = new LoadIncrementalHFiles(configuration);
            HTable hTable = new HTable(configuration, "blog_info");
            loder.doBulkLoad(new Path("hdfs://iteblog:9000/user/iteblog/output"), hTable);
    }
}

    由于Hbase的BulkLoad方式是绕过了Write to WAL,Write to MemStore及Flush to disk的过程,所以并不能通过WAL来进行一些复制数据的操作。

5 小 结

    本文主要分析完成了HBase BulkLoad的实现原理,适用场景以及具体的操作,包括HBase的命令行操作以及java代码的实现方式,HBase BulkLoad对于异构数据源的合并及大量数据一次性导入具有重要指导意义,相比HBase Put操作在性能上具有较高的优势。

references:

https://www.iteblog.com/archives/1889.html

https://www.cnblogs.com/ios123/p/6398916.html

https://forum.huawei.com/enterprise/zh/thread-512009.html

https://www.cnblogs.com/felixzh/p/10251802.html

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值