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的执行时间
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 实操案例
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路径> <目标表名称>
references:
https://www.iteblog.com/archives/1889.html