Hbase-Spark BulkLoad 解析

一、背景

项目中有需求,要频繁地、快速地向一个表中初始化数据。因此如何加载数据,如何提高速度是需要解决的问题。
一般来说,作为数据存储系统会分为检索和存储两部分。检索是对外暴露数据查询接口。存储一是要实现数据按固定规则存储到存储介质中(如磁盘、内存等),另一方面还需要向外暴露批量装载的工具。如DB2的 db2load 工具,在关闭掉日志的前提下,写入速度能有显著提高。

二、知识点

  1. Hbase 2.0 的LoadIncrementalHFiles 支持向Hbase 写入HFile 文件
  2. 写入的HFile 文件要求是排序的(rowKey,列簇,列)
  3. 关键是绕过Hbase regionServer,直接写入Hbase文件
  4. Spark RDD的repartitionAndSortWithinPartitions 方法可以高效地实现分区并排序
  5. JAVA util.TreeMap 是红黑树的实现,能很好的实现排序的要求

三、流程

  1. 对待写入的数据按Key值构造util.TreeMap 树结构。目的是按Key值构造匹配Hbase 的排序结构
  2. 转换成RDD,使用repartitionAndSortWithinPartitions算子 对Key值分区并排序
  3. 调用RDD的saveAsNewAPIHadoopFile 算子,生成HFile文件
  4. 调用Hbase: LoadIncrementalHFiles 将HFile文件Load 到Hbase 表中

四、实现

结构

ByteArrayWrapper.scala-> 对RowKey 结构的封装,支持排序
FamiliesQualifiersValues.scala -> 使用treeMap,实现排序结构
HBaseContext.scala ->
-saveAsHFile -> 写HFile文件
- bulkLoadThinRows -> 写入Hbase
代码参考:[HbaseETL] (https://github.com/Smallhi/HbaseETL)

例子

def initDate() = {
    // 清空,并重新创建表
    createTable
    // 准备数据,rdd 处理
    import spark.implicits._
    val rdd = spark.sql("select * from hive.graph").map(x => {
      val sid = x.getString(0)
      val id = x.getString(1)
      val idType = x.getString(3)
      (sid, id, idType)
    }).rdd
    // bulk load
    hc.bulkLoadThinRows[(String, String, String)](rdd,
      "lenovo:GRAPH",
      t => {
        val rowKey = rowKeyByMD5(t._2, t._3)
        val familyQualifiersValues = new FamiliesQualifiersValues

        val pk = t._2 + "|" + t._3
        // Hbase 存入两列,一列 PK 存 业务主键,一列 s 存 superid
        val column = List(("pk", pk), ("s", t._1))
        column.foreach(f => {
          val family: Array[Byte] = Bytes.toBytes(columnFamily.head)
          val qualifier = Bytes.toBytes(f._1)
          val value: Array[Byte] = Bytes.toBytes(f._2)
          familyQualifiersValues += (family, qualifier, value)
        })
        (new ByteArrayWrapper(rowKey), familyQualifiersValues)
      },
      10
    )
  }

你可能感兴趣的:(Hbase-Spark BulkLoad 解析)