HBase的BulkLoad

    在网上看到了一篇文章说到了HBase的BulkLoad机制,从文章中看出BulkLoad是不走HBase的服务端的,直接和Hadoop打交道将数据直接生成HFile,然后将文件直接移到Region下面。如下图所示:

    相比较于直接写HBase,BulkLoad主要是绕过了写WAL日志这一步,还有写Memstore和Flush到磁盘,从理论上来分析性能会比Put快!

 

 

Spark+BulkLoad往HBase中导入数据:

//HFileOutputFormat要求行键有序: rowKey + 列族 + 列名 整体有序
val hfileRDD = df.rdd.map(row => {
  //OneRecord(rowKey: String, plateNo: String, plateColor: Int, passTime: Long, crossingId: Int)
  val rowKeyBytes = Bytes.toBytes(row.getString(0))
  //这里控制 列族 + 列名 的排序
  new ImmutableBytesWritable(rowKeyBytes) ->
    new KeyValue(rowKeyBytes, family, column1, Bytes.toBytes(row.getString(1)))
  //这里控制行键的排序
}).sortByKey()


val hfileInHDFSPath = "hdfs://*IP*:8020/tmp/Test"
hfileRDD.saveAsNewAPIHadoopFile(hfileInHDFSPath,
  classOf[ImmutableBytesWritable],
  classOf[KeyValue],
  classOf[HFileOutputFormat2],
  sparkSession.sparkContext.hadoopConfiguration
)

val load = new LoadIncrementalHFiles(sparkSession.sparkContext.hadoopConfiguration)n
val table = connection.getTable(TableName.valueOf("TEST"))

//创建BulkLoad作业将数据写入到HBase
val job = Job.getInstance(sparkSession.sparkContext.hadoopConfiguration)
job.setJobName("Test")
job.setMapOutputKeyClass(classOf[ImmutableBytesWritable])
job.setMapOutputValueClass(classOf[KeyValue])
HFileOutputFormat2.configureIncrementalLoadMap(job, table)
load.doBulkLoad(new Path(hfileInHDFSPath), table.asInstanceOf[HTable])
table.close()
connection.close()

 

一些有意思的点分析:

1.需要对RDD中的数据手动排序

使用Put写到HBase中的时候HBase会自动进行排序,但是自己生成的HFile文件不会自动排序,所以需要手动排序好,先主键再列族再列这样的方式进行排序,不然会报错。

 

2.KeyValue格式的时间戳会自动赋值

    new KeyValue的时候默认会给这个cell一个时间戳,默认是Long.MaxValue:

但是写的时候会更新为当前时间,从HBase中来看确实也是这样的:

从KeyValue对象的构造函数中可以清楚的看到,每个KeyValue对象中都包含rowKey,所以一直说rowKey不应太大,不然每条数据都会很大:

 

3.BulkLoad是怎么进行的?

其实BulkLoad分成客户端和服务端两步操作,先来看客户端干了啥:

客户端主要是为每个HFile创建了一个LoadQueueItem结构,然后判断HFile是否过大或者跨约了多个Region,如果是则要对HFile文件进行拆分。然后将属于同一个Region的文件记录到一起:

  /**

   * @return A Multimap<startkey, LoadQueueItem> that groups LQI by likely

   * bulk load region targets.

   */

 

接着发送请求给服务端,请求服务端进行挂载:

接下来就是服务端的操作了

 

 

服务端操作

   RSRpcService收到BulkLoad请求之后,会调用HRegion中的bulkLoadHFiles方法:

    同时进行multi-family bulk load需要获取writeLock

    向一个region里面load的可能会有多个列族,不同的列族对应不用HStore,需要分别load。写的时候还要flushcache(),保证HFile SeqId不重复:

 

    正式Load的时候,如果文件与当前hbase所在的文件系统不是同一个文件系统,那么则会把HFile copy到当前的文件系统中:

真正的Load就是一个对文件rename的操作…就不细说了

 

    个人理解是,如果是现成的大批量数据的导入操作,比如做数据级联,尽量使用BulkLoad,比Spark直接写入HBase性能要高。咨询过同事,他给了我如下几个他的建议:

1.导入数据的表要做好预拆分Region,并且HFile文件要控制在Region内,不要让BulkLoad进行拆分

2.HBase和Hadoop尽量在同一套环境中,以免影响挂载性能。

3.生成的HFile要尽量避免合并,以免影响HBase服务(这点厚点要研究下如何做到,生成什么样的HFile的情况下会进行合并)

 

 

 

 

 

参考:

    https://www.cnblogs.com/smartloli/p/9501887.html(BulkLoad示意图)

    https://www.2cto.com/net/201710/692437.html(HFile手工排序)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值