HBase实操 | 使用Spark通过BulkLoad快速导入数据到HBase
Posted HBase技术社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HBase实操 | 使用Spark通过BulkLoad快速导入数据到HBase相关的知识,希望对你有一定的参考价值。
HBase社区直播本期分享专家:明惠(网名:过往记忆)-阿里云数据架构师
https://yq.aliyun.com/live/590?spm=a2c4e.11155435.0.0.460177969kCLxf
https://yq.aliyun.com/download/3033
PS:欢迎关注HBase+Spark团队号 https://yq.aliyun.com/teams/382 博客,问答,直播,各类HBase资料,线下meetup都会发布到这里。
1.文档编写目的
在项目中有需求需要将Hive表中的数据存储在HBase中。使用Spark访问Hive表,将读表数据导入到HBase中,写入HBase有两种方式:一种是通过HBase的API接口批量的将数据写入HBase,另一种是通过BulkLoad的方式生成HFile文件然后加载到HBase中,两种方式相比之下第二种效率会更高。本篇文章Fayson主要介绍如何使用Spark读取Hive表数据通过BulkLoad的方式快速的将数据导入到HBase。
文章概述
1.环境准备
2.示例代码及运行
3.总结
测试环境
1.CM5.14.3和CDH5.14.2
2.集群未启用Sentry和Kerberos
3.Spark1.6.0
2.环境准备
本篇文章主要使用HBase中hbase-spark包提供的HBaseContext来实现,需要准备hbase-spark的依赖包并部署到Spark集群。
1.将准备好的hbase-spark-1.2.0-cdh5.13.1.jar部署到集群所有节点的/opt/cloudera/parcels/CDH/lib/spark/lib目录下
[root@cdh01 ~]# ll /opt/cloudera/parcels/CDH/lib/spark/lib/
2.登录CM配置在spark-env.sh中增加hbase-spark的依赖,增加如下配置内容
export SPARK_DIST_CLASSPATH=$SPARK_DIST_CLASSPATH:/opt/cloudera/parcels/CDH/lib/spark/lib/hbase-spark-1.2.0-cdh5.13.1.jar
保存配置,并重新部署Spark客户端配置
3.Hive表示例数据查看
去除重复数据共600条数据
3.Spark示例代码
1.使用Maven创建Scala示例工程,pom.xml文件内容如下:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-assembly_2.10</artifactId>
<version>1.6.0-cdh5.12.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-spark</artifactId>
<version>1.2.0-cdh5.13.1</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.10</artifactId>
<version>1.6.0-cdh5.12.1</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.10</artifactId>
<version>1.6.0-cdh5.12.1</version>
</dependency>
2.在工程中创建Hive2HBase.scala文件,内容如下:
package com.cloudera.hbase
import java.io.IOException
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.Path
import org.apache.hadoop.hbase._
import org.apache.hadoop.hbase.client._
import org.apache.spark.sql.hive.HiveContext
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.hadoop.hbase.mapreduce.{HFileOutputFormat2, LoadIncrementalHFiles}
import org.apache.hadoop.hbase.spark.{HBaseContext, KeyFamilyQualifier}
import org.apache.hadoop.hbase.spark.HBaseRDDFunctions._
import org.apache.hadoop.hbase.util.Bytes
import org.apache.hadoop.mapreduce.Job
import scala.collection.mutable
/**
* package: com.cloudera.hbase
* describe: 使用BulkLoad的方式将Hive数据导入HBase
* creat_user: Fayson
* email: htechinfo@163.com
* creat_date: 2018/7/31
* creat_time: 下午2:04
* 公众号:Hadoop实操
*/
object Hive2HBase {
def main(args: Array[String]) {
//库名、表名、rowKey对应的字段名、批次时间、需要删除表的时间参数
val rowKeyField = "id"
val quorum = "cdh01.fayson.com,cdh02.fayson.com,cdh03.fayson.com"
val clientPort = "2181"
val hBaseTempTable = "ods_user_hbase"
val sparkConf = new SparkConf().setAppName("Hive2HBase")
val sc = new SparkContext(sparkConf)
val hiveContext = new HiveContext(sc)
//从hive表读取数据
val datahiveDF = hiveContext.sql(s"select * from ods_user")
//表结构字段
var fields = datahiveDF.columns
//去掉rowKey字段
fields = fields.dropWhile(_ == rowKeyField)
val hBaseConf = HBaseConfiguration.create()
hBaseConf.set("hbase.zookeeper.quorum", quorum)
hBaseConf.set("hbase.zookeeper.property.clientPort", clientPort)
//表不存在则建Hbase临时表
creteHTable(hBaseTempTable, hBaseConf)
val hbaseContext = new HBaseContext(sc, hBaseConf)
//将DataFrame转换bulkload需要的RDD格式
val rddnew = datahiveDF.rdd.map(row => {
val rowKey = row.getAs[String](rowKeyField)
fields.map(field => {
val fieldValue = row.getAs[String](field)
(Bytes.toBytes(rowKey), Array((Bytes.toBytes("info"), Bytes.toBytes(field), Bytes.toBytes(fieldValue))))
})
}).flatMap(array => {
(array)
})
//使用HBaseContext的bulkload生成HFile文件
hbaseContext.bulkLoad[Put](rddnew.map(record => {
val put = new Put(record._1)
record._2.foreach((putValue) => put.addColumn(putValue._1, putValue._2, putValue._3))
put
}), TableName.valueOf(hBaseTempTable), (t : Put) => putForLoad(t), "/tmp/bulkload")
val conn = ConnectionFactory.createConnection(hBaseConf)
val hbTableName = TableName.valueOf(hBaseTempTable.getBytes())
val regionLocator = new HRegionLocator(hbTableName, classOf[ClusterConnection].cast(conn))
val realTable = conn.getTable(hbTableName)
HFileOutputFormat2.configureIncrementalLoad(Job.getInstance(), realTable, regionLocator)
// bulk load start
val loader = new LoadIncrementalHFiles(hBaseConf)
val admin = conn.getAdmin()
loader.doBulkLoad(new Path("/tmp/bulkload"),admin,realTable,regionLocator)
sc.stop()
}
/**
* 创建HBase表
* @param tableName 表名
*/
def creteHTable(tableName: String, hBaseConf : Configuration) = {
val connection = ConnectionFactory.createConnection(hBaseConf)
val hBaseTableName = TableName.valueOf(tableName)
val admin = connection.getAdmin
if (!admin.tableExists(hBaseTableName)) {
val tableDesc = new HTableDescriptor(hBaseTableName)
tableDesc.addFamily(new HColumnDescriptor("info".getBytes))
admin.createTable(tableDesc)
}
connection.close()
}
/**
* Prepare the Put object for bulkload function.
* @param put The put object.
* @throws java.io.IOException
* @throws java.lang.InterruptedException
* @return Tuple of (KeyFamilyQualifier, bytes of cell value)*/
@throws(classOf[IOException])
@throws(classOf[InterruptedException])
def putForLoad(put: Put): Iterator[(KeyFamilyQualifier, Array[Byte])] = {
val ret: mutable.MutableList[(KeyFamilyQualifier, Array[Byte])] = mutable.MutableList()
import scala.collection.JavaConversions._
for (cells <- put.getFamilyCellMap.entrySet().iterator()) {
val family = cells.getKey
for (value <- cells.getValue) {
val kfq = new KeyFamilyQualifier(CellUtil.cloneRow(value), family, CellUtil.cloneQualifier(value))
ret.+=((kfq, CellUtil.cloneValue(value)))
}
}
ret.iterator
}
}
3.使用Maven命令将工程编译为jar包
4.示例运行
1.将编译好的spark-demo-1.0-SNAPSHOT.jar包上传至服务器,使用spark-submit提交
export HADOOP_USER_NAME=hbase
spark-submit --class com.cloudera.hbase.Hive2HBase
--master yarn-client
--driver-cores 1
--driver-memory 2g
--executor-cores 1
--executor-memory 2g
spark-demo-1.0-SNAPSHOT.jar
通过Spark作业界面,查看作业运行情况
2.作业执行成功后,查看HBase表数据
查看表数据
5.总结
1.本篇文章是使用hbase-spark包中提供的bulkload方法生成HFile文件,然后将生成的文件导入到HBase表中。
2.使用bulkload的方式导入数据到HBase表时,在load HFile文件到表过程中会有短暂的时间导致该表停止服务(在load文件过程中需要先disable表,load完成后在enable表。
3.需要使用hbase用户提交Spark作业
https://github.com/fayson/cdhproject/blob/master/sparkdemo/src/main/scala/com/cloudera/hbase/Hive2HBase.scala
HBase直播主题调研,以及2019年HBase Meetup举办城市调研,欢迎大家积极参与。
推荐关注Hadoop实操,第一时间,分享更多Hadoop干货,欢迎转发和分享。
以上是关于HBase实操 | 使用Spark通过BulkLoad快速导入数据到HBase的主要内容,如果未能解决你的问题,请参考以下文章
HBase实操 | 使用Phoenix在CDH的HBase创建二级索引
Spark-on-Hbase:通过Spark的DataFrame访问Hbase表
0539-5.15.0-HBase-Spark无法在Spark2编译通过问题解决
Spark进阶 大数据离线与实时项目实战 Spark-Hbase-Redis-Hadoop 大技术栈的企业级应用 网盘云分享