大数据Sqoop快速入门
因为数据仓库是甲方自建的, 所以如果我们需要数仓中的数据, 需要申请, 申请完成后, 甲方会将对应的 Hive 表开放给我们, 所以我们需要把 Hive 表中需要的数据抽取到我们的 HBase 中, 如下
抽取方向: Hive -> HBase
在大量数据需要写入HBase时,通常有 put方式和bulkLoad 两种方式。
1、put方式为单条插入,在put数据时会先将数据的更新操作信息和数据信息 写入WAL ,在写入到WAL后, 数据就会被放到MemStore中 ,当MemStore满后数据就会被 flush到磁盘(即形成HFile文件) ,在这种写操作过程会涉及到flush、split、compaction等操作,容易造成节点不稳定,数据导入慢,耗费资源等问题,在海量数据的导入过程极大的消耗了系统性能,避免这些问题最好的方法就是使用BulkLoad的方式来加载数据到HBase中。
2、BulkLoader利用HBase数据按照HFile格式存储在HDFS的原理,使用MapReduce直接批量
生成HFile格式文件后,RegionServers再将HFile文件移动到相应的Region目录下。
1)、Extract,异构数据源数据导入到 HDFS 之上。
2)、Transform,通过用户代码,可以是 MR 或者 Spark 任务将数据转化为 HFile。
3)、Load,HFile 通过 loadIncrementalHFiles 调用将 HFile 放置到 Region 对应的
HDFS 目录上,该过程可能涉及到文件切分。
1、不会触发WAL预写日志,当表还没有数据时进行数据导入不会产生Flush和Split。
2、减少接口调用的消耗,是一种快速写入的优化方式。
Spark读写HBase之使用Spark自带的API以及使用Bulk Load将大量数据导入HBase:
https://www.jianshu.com/p/b6c5a5ba30af
先说说要使用 BulkLoad 的原因
为什么会非常慢呢? 因为一条数据插入 HBase 的大致步骤如下
而我们有 260G 的数据要插入, 触发很多次 Compaction, 会分裂 Region 几百次, 这无疑会造成 HBase 集群的不稳定, 并且, 我们插入的速度也会很慢
所以, 当一次性要插入的数据太多时, 要通过 HBase 的 BulkLoad 方式加载
将MySQL数据库中表的数据导入到Hive表中,以便加载到HBase表中。
启动HiveMetastore服务和HiveServer2服务,使用beeline命令行连接,相关命令如下:
[root@bigdata-cdh01 ~]# /export/servers/hive/bin/beeline
Beeline version 1.1.0-cdh5.14.0 by Apache Hive
beeline> !connect jdbc:hive2://bigdata-cdh01.itcast.cn:10000
scan complete in 2ms
Connecting to jdbc:hive2://bigdata-cdh01.itcast.cn:10000
Enter username for jdbc:hive2://bigdata-cdh01.itcast.cn:10000: root
Enter password for jdbc:hive2://bigdata-cdh01.itcast.cn:10000: ****
Connected to: Apache Hive (version 1.1.0-cdh5.14.0)
Driver: Hive JDBC (version 1.1.0-cdh5.14.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://bigdata-cdh01.itcast.cn:10000>
创建Hive中数据库Database:
CREATE DATABASE tags_dat;
根据MySQL数据库表在Hive数据仓库中构建相应的表:
用户信息表: tbl_users
/export/servers/sqoop/bin/sqoop create-hive-table \
--connect jdbc:mysql://bigdata-cdh01.oldlu.cn:3306/tags_dat \
--table tbl_users \
--username root \
--password 123456 \
--hive-table tags_dat.tbl_users \
--fields-terminated-by '\t' \
--lines-terminated-by '\n'
使用Sqoop将MySQL数据库表中的数据导入到Hive表中(本质就是存储在HDFS上),具体命
令如下:
用户信息表: tbl_users
/export/servers/sqoop/bin/sqoop import \
--connect jdbc:mysql://bigdata-cdh01.itcast.cn:3306/tags_dat \
--username root \
--password 123456 \
--table tbl_users \
--direct \
--hive-overwrite \
--delete-target-dir \
--fields-terminated-by '\t' \
--lines-terminated-by '\n' \
--hive-table tags_dat.tbl_users \
--hive-import \
--num-mappers 1
目标
步骤
tag-data
步骤:
MySQL 密码 : itcastmysqlroot
详细解释:
files/tags_data.sql
步骤:
详细解释:
编写 Sqoop 任务脚本
#!/bin/sh
sqoop import \
--hive-import \
--create-hive-table \
--hive-table tags_data.tbl_goods \
--connect "jdbc:mysql://master01:3306/tags_dat" \
--username root \
--password itcastmysqlroot \
--query "SELECT * FROM tags_dat.tbl_goods WHERE \$CONDITIONS" \
--split-by id \
--direct \
--target-dir /user/admin/hive/tags_dat \
--m 2
sqoop import \
--hive-import \
--create-hive-table \
--hive-table tags_data.tbl_goods_new \
--connect "jdbc:mysql://master01:3306/tags_dat" \
--username root \
--password itcastmysqlroot \
--query "SELECT * FROM tags_dat.tbl_goods_new WHERE \$CONDITIONS" \
--split-by id \
--direct \
--target-dir /user/admin/hive/tags_dat \
--m 2
sqoop import \
--hive-import \
--create-hive-table \
--hive-table tags_data.tbl_logs \
--connect "jdbc:mysql://master01:3306/tags_dat?useUnicode=true" \
--username root \
--password itcastmysqlroot \
--query "SELECT * FROM tags_dat.tbl_logs WHERE \$CONDITIONS" \
--split-by id \
--direct \
--target-dir /user/admin/hive/tags_dat \
--m 2
sqoop import \
--hive-import \
--create-hive-table \
--hive-table tags_data.tbl_orders \
--connect "jdbc:mysql://master01:3306/tags_dat" \
--username root \
--password itcastmysqlroot \
--query "SELECT * FROM tags_dat.tbl_orders WHERE \$CONDITIONS" \
--split-by id \
--direct \
--target-dir /user/admin/hive/tags_dat \
--m 2
sqoop import \
--hive-import \
--create-hive-table \
--hive-table tags_data.tbl_users \
--connect "jdbc:mysql://master01:3306/tags_dat" \
--username root \
--password itcastmysqlroot \
--query "SELECT * FROM tags_dat.tbl_users WHERE \$CONDITIONS" \
--split-by id \
--direct \
--target-dir /user/admin/hive/tags_dat \
--m 2
通过 Hue 上传脚本文件
数据抽取:
步骤:
resource
目录中
Files/hbase_conf
从目标来看, 这个工程中需要 Spark, HBase, Hive 的相关依赖, pom.xml
如下
<dependencies>
<dependency>
<groupId>org.scala-langgroupId>
<artifactId>scala-libraryartifactId>
dependency>
<dependency>
<groupId>org.apache.sparkgroupId>
<artifactId>spark-core_2.11artifactId>
dependency>
<dependency>
<groupId>org.apache.sparkgroupId>
<artifactId>spark-sql_2.11artifactId>
dependency>
<dependency>
<groupId>org.apache.sparkgroupId>
<artifactId>spark-mllib_2.11artifactId>
dependency>
<dependency>
<groupId>org.apache.sparkgroupId>
<artifactId>spark-hive_2.11artifactId>
dependency>
<dependency>
<groupId>org.apache.hbasegroupId>
<artifactId>hbase-serverartifactId>
<exclusions>
<exclusion>
<artifactId>jersey-container-servlet-coreartifactId>
<groupId>org.glassfish.jersey.containersgroupId>
exclusion>
<exclusion>
<artifactId>guice-servletartifactId>
<groupId>com.google.inject.extensionsgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.hbasegroupId>
<artifactId>hbase-mapreduceartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-simpleartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
plugin>
<plugin>
<groupId>net.alchim31.mavengroupId>
<artifactId>scala-maven-pluginartifactId>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-assembly-pluginartifactId>
plugin>
plugins>
build>
步骤
注意点
object HiveToHBase {
val defaultCF = "default"
val defaultNameSpace = "default"
val tempFileDir = "/user/admin/Spark/extra_temp/"
def main(args: Array[String]): Unit = {
if (args.length < 3) {
return
}
val sourceDBName = args(0)
val sourceTableName = args(1)
val rkeyField = args(2)
val conf = HBaseConfiguration.create
conf.set(TableOutputFormat.OUTPUT_TABLE, sourceTableName)
conf.set("hbase.mapreduce.hfileoutputformat.table.name", sourceTableName)
val job = Job.getInstance(conf)
job.setMapOutputKeyClass(classOf[ImmutableBytesWritable])
job.setMapOutputValueClass(classOf[KeyValue])
val hfilePath = tempFileDir + sourceTableName
hive2HFile(sourceDBName, sourceTableName, rkeyField, defaultCF, conf, hfilePath)
bulkLoad2Table(job, hfilePath, defaultNameSpace, sourceTableName, defaultCF)
}
def hive2HFile(sourceDB: String, sourceTable: String, rkeyField: String, cf: String, hadoopConfig: Configuration, hfilePath: String): Unit = {
val fs = FileSystem.get(hadoopConfig)
if (fs.exists(new Path(hfilePath))) {
fs.delete(new Path(hfilePath), true)
}
val spark = SparkSession.builder()
.appName("bulk load from hive")
.enableHiveSupport()
.getOrCreate()
spark.read
.table(sourceDB + "." + sourceTable)
.rdd
.filter(row => row.getAs(rkeyField) != null)
.flatMap(row => {
val cfBytes = Bytes.toBytes(cf)
val rowKeyBytes = Bytes.toBytes(row.getAs(rkeyField).toString)
row.schema
.sortBy(field => field.name)
.map(field => {
val fieldNameBytes = Bytes.toBytes(field.name)
val valueBytes = Bytes.toBytes(row.getAs(field.name).toString)
val kv = new KeyValue(rowKeyBytes, cfBytes, fieldNameBytes, valueBytes)
(new ImmutableBytesWritable(rowKeyBytes), kv)
})
})
.filter(item => item != null)
.saveAsNewAPIHadoopFile(
hfilePath,
classOf[ImmutableBytesWritable],
classOf[KeyValue],
classOf[HFileOutputFormat2],
hadoopConfig
)
}
def bulkLoad2Table(job: Job, hfilePath: String, namespace: String, name: String, cf: String): Unit = {
val connection = ConnectionFactory.createConnection(job.getConfiguration)
val admin = connection.getAdmin
val tableName = TableName.valueOf(Bytes.toBytes(namespace), Bytes.toBytes(name))
if (!admin.tableExists(tableName)) {
admin.createTable(
TableDescriptorBuilder.newBuilder(tableName)
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf)).build())
.build()
)
}
val table = connection.getTable(tableName)
val regionLocator = new HRegionLocator(tableName, connection.asInstanceOf[ClusterConnection])
HFileOutputFormat2.configureIncrementalLoad(job, table, regionLocator)
val loader = new LoadIncrementalHFiles(job.getConfiguration)
loader.doBulkLoad(new Path(hfilePath), admin, table, regionLocator)
}
}
一共有五张表需要导入
表 | Hive table name | RowKey field |
---|---|---|
商品表 | tbl_goods | id |
商品表_new | tbl_goods_new | id |
日志表 | tbl_logs | id |
订单表 | tbl_orders | id |
用户表 | tbl_users | id |
需要五个 Oozie Job 去调度执行, 创建方式如下
详细介绍如下