• 简述HBase的Bulk Load


    为什么用Bulk load?

    批量加载数据到HBase集群,有很多种方式,比如利用 HBase API 进行批量写入数据、使用Sqoop工具批量导数到HBase集群、使用MapReduce批量导入等等,但是这些方法都有一个问题:导入数据的过程如果数据量过大,可能耗时会比较严重或者占用HBase集群资源较多(如磁盘IO、HBase Handler数等)

    使用 HBase BulkLoad的方式来进行海量数据批量写入到HBase集群,可以对大数据量的情况下做一些优化,提高性能。

    在使用BulkLoad之前,我们先来了解一下HBase的存储机制。HBase存储数据其底层使用的是HDFS来作为存储介质,HBase的每一张表对应的HDFS目录上的一个文件夹,文件夹名以HBase表进行命名(如果没有使用命名空间,则默认在default目录下),在表文件夹下存放在若干个Region命名的文件夹,Region文件夹中的每个列簇也是用文件夹进行存储的,每个列簇中存储就是实际的数据,以HFile的形式存在,路径格式如下:

    /hbase/data/default/<tbl_name>/<region_id>/<cf>/<hfile_id>
    

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

    生成HFile文件
    HFile文件的生成,可以使用MapReduce来进行实现,将数据源准备好,上传到HDFS进行存储,然后在程序中读取HDFS上的数据源,进行自定义封装,组装RowKey,然后将封装后的数据在回写到HDFS上,以HFile的形式存储到HDFS指定的目录中。实现代码:

    public class GemeratorHFile2 {
        static class HFileImportMapper2 extends Mapper<LongWritable, Text, ImmutableBytesWritable, KeyValue> {
    
            protected final String CF_KQ = "cf";
    
            @Override
            protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
                String line = value.toString();
                System.out.println("line : " + line);
                String[] datas = line.split(" ");
                String row = new Date().getTime() + "_" + datas[1];
                ImmutableBytesWritable rowkey = new ImmutableBytesWritable(Bytes.toBytes(row));
                KeyValue kv = new KeyValue(Bytes.toBytes(row), this.CF_KQ.getBytes(), datas[1].getBytes(), datas[2].getBytes());
                context.write(rowkey, kv);
            }
        }
    
        public static void main(String[] args) {
            if (args.length != 1) {
                System.out.println("<Usage>Please input hbase-site.xml path.</Usage>");
                return;
            }
            Configuration conf = new Configuration();
            conf.addResource(new Path(args[0]));
            conf.set("hbase.fs.tmp.dir", "partitions_" + UUID.randomUUID());
            String tableName = "person";
            String input = "hdfs://nna:9000/tmp/person.txt";
            String output = "hdfs://nna:9000/tmp/pres";
            System.out.println("table : " + tableName);
            HTable table;
            try {
                try {
                    FileSystem fs = FileSystem.get(URI.create(output), conf);
                    fs.delete(new Path(output), true);
                    fs.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
    
                Connection conn = ConnectionFactory.createConnection(conf);
                table = (HTable) conn.getTable(TableName.valueOf(tableName));
                Job job = Job.getInstance(conf);
                job.setJobName("Generate HFile");
    
                job.setJarByClass(GemeratorHFile2.class);
                job.setInputFormatClass(TextInputFormat.class);
                job.setMapperClass(HFileImportMapper2.class);
                FileInputFormat.setInputPaths(job, input);
                FileOutputFormat.setOutputPath(job, new Path(output));
    
                HFileOutputFormat2.configureIncrementalLoad(job, table);
                try {
                    job.waitForCompletion(true);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    
    

    在HDFS目录/tmp/person.txt中,准备数据源如下:

    1 smartloli 100
    2 smartloli2 101
    3 smartloli3 102
    
    

    然后将上述代码编译打包成jar,上传到Hadoop集群进行执行,执行以下命令:

    hadoop jar GemeratorHFile2.jar /data/soft/new/apps/hbaseapp/hbase-site.xml
    

    如果在执行命令的过程中,出现找不到类的异常信息,可能是本地没有加载HBase依赖jar包,当前用户配置如下环境变量信息:

    export HADOOP_CLASSPATH=$HBASE_HOME/lib/*:classpath
    

    然后执行source命令使配置的内容立即生效。

    执行预览

    成功提交任务Linux控制台打印执行任务进度,也可以到YARN的资源监控界面查看执行进度,结果如图所示:

    等待任务的执行,执行完成后在对应HDFS路径上会生成相应的HFile数据文件,如图所示:

    使用BulkLoad导入到HBase
    使用BulkLoad的方式将生成的HFile文件导入到HBase集群中,这里有两种导入方式。一种是写代码实现导入,另一种是使用HBase命令进行导入。

    写代码实现导入
    通过LoadIncrementalHFiles类来实现导入,具体代码:

    public class BulkLoad2HBase {
    
        public static void main(String[] args) throws Exception {
            if (args.length != 1) {
                System.out.println("<Usage>Please input hbase-site.xml path.</Usage>");
                return;
            }
            String output = "hdfs://cluster1/tmp/pres";
            Configuration conf = new Configuration();
            conf.addResource(new Path(args[0]));
            HTable table = new HTable(conf, "person");
            LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
            loader.doBulkLoad(new Path(output), table);
        }
    
    }
    

    执行上述代码运行结果:

    使用HBase命令进行导入

    先将生成好的HFile文件迁移到目标集群(即HBase集群所在的HDFS上),然后使用HBase命令进行导入,执行以下命令:

    # 先使用distcp迁移hfile
    hadoop distcp -Dmapreduce.job.queuename=queue_1024_01 -update -skipcrccheck -m 10 /tmp/pres hdfs://nns:9000/tmp/pres
    # 使用bulkload方式导入数据
    hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /tmp/pres person
    

    最后,我们可以到指定的RegionServer节点上查看导入的日志信息,导入成功的日志信息:

    2018-08-19 16:30:34,969 INFO  [B.defaultRpcServer.handler=7,queue=1,port=16020] regionserver.HStore: Successfully loaded store file hdfs://cluster1/tmp/pres/cf/7b455535f660444695589edf509935e9 into store cf (new location: hdfs://cluster1/hbase/data/default/person/2d7483d4abd6d20acdf16533a3fdf18f/cf/d72c8846327d42e2a00780ac2facf95b_SeqId_4_)
    

    2.5 验证
    使用BulkLoad方式导入数据后,可以进入到HBase集群,使用HBase Shell来查看数据是否导入成功,预览结果如图所示:

    总结
    本篇文章为了演示实战效果,将生成HFile文件和使用BulkLoad方式导入HFile到HBase集群的步骤进行分解,实际情况可以将这两个步骤合并为一个,实现自动化生成与HFile自动导入。如果在执行的过程中出现RpcRetryingCaller的异常,可以到对应RegionServer节点查看日志信息,这里面记录出现这种异常的详细原因。

  • 相关阅读:
    让你忘记 Flash 的15款精彩 HTML5 游戏
    经典网页设计:10个响应式设计的国外购物网站
    个人网站设计:25个国外优秀案例带给你灵感
    震撼!20幅令人难以置信的摄影图片欣赏
    Vex – 超轻量!可以轻松自定义的现代风格弹窗插件
    高端大气上档次!10个精美的国外HTML5网站欣赏
    桂系军阀老大为何不是打仗独步天下的白崇禧?三个方面不如李宗仁(气量,人缘,大局观)
    LEO原创-FMX之你不知道的ARC
    ubuntu64位系统编译时头文件找不到的问题(可以查看g++ -v路径,设置export C_INCLUDE_PATH,CPLUS_INCLUDE_PATH)
    qt设计器中使用自定义控件
  • 原文地址:https://www.cnblogs.com/bigband/p/13529753.html
Copyright © 2020-2023  润新知