本文简单介绍 HBase 的数据导入工具 ImportTSV 。通过一次将 hive 大表导入 HBase 的实战案例,梳理期间遇到的问题,调研更优的导入方式。本文着重关注:
- 如何借助 ImportTSV 工具将数据(文件:tsv、csv、hive 表) 导入 HBase,有哪些坑需要考虑?
- HBase 如何建表,如何创建预分区?
- Hive 数据导入 HBase 是否有其他方式,更有的方式?
1 ImportTSV 介绍
ImportTsv 是 HBase 提供的一个命令行工具,将存储在 HDFS 上的数据文件,通过指定的分隔符解析后,导入到 HBase 表中。(TSV :Tab-separated values)
这样的方式导入数据与正常写入流程不同的是,跳过了 WAL、Memcache 与 Flush 的过程,直接将 HFile 文件移动到 HBase 表空间目录下即可,不影响 RegionServer 的性能。
ImportTsv 提供两种导入的方式:
- 直接 MR 任务写入:这对小数据量,可以直接一行命令导入
- 先导出 hfile 再 bulkload:针对大数据量,高效导入
方案 1 :直接导入
首先创建 hbase 表:user (大表一定要预分区,不然全部会写到一个 region),然后执行命令导入:
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv -Dimporttsv.separator="," -Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:gender,info:age,info:idNumber,info:address,info:birthday user /tmp/user.txt
- 指定分隔符为逗号
- 指定导入的列:第一列为 HBASE_ROW_KEY,其他列都是 info列族下的name,gender,age,idNumber,address,birthday列
- 指定需要导入的表名:user
- 指定数据文件在HDFS上的目录地址:/tmp/user.txt
方案 2:hfile + bulkload
- 建 HBase 表(大表一定要预分区,不然全部会写到一个 region)
- 生成 hfile
- bulkload
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv -Dimporttsv.separator="," -Dimporttsv.bulk.output=/louisvv/hfile_tmp -Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:gender,info:age,info:idNumber,info:address,info:birthday user /yw/user.txt
2 实战案例
2.1 需求描述
Hive 表 42 亿行数据导入 HBase,采用上述提到的方案 2 : hfile + bulkload
Hive 表信息:
表名:hive_pub.dim_ip_cover_all_info_20220801_001
行数:42 亿
rowkey 为表第一个字段 ip_num,是 ip 转出的数值,保证唯一。
数据样例如下:
ip_num ip begin_ip end_ip country province_name city_name
1214810642 72.104.138.18 72.55.192.0 72.135.255.255 美国 美国
1214810654 72.104.138.30 72.55.192.0 72.135.255.255 美国 美国
137497864 8.50.13.8 8.47.158.0 8.127.255.255 美国 美国
137497876 8.50.13.20 8.47.158.0 8.127.255.255 美国 美国
137497888 8.50.13.32 8.47.158.0 8.127.255.255 美国 美国
137497900 8.50.13.44 8.47.158.0 8.127.255.255 美国 美国
137497912 8.50.13.56 8.47.158.0 8.127.255.255 美国 美国
137497924 8.50.13.68 8.47.158.0 8.127.255.255 美国 美国
3699562708 220.130.216.212 220.130.216.0 220.130.217.255 中国 台湾 彰化县
3699562720 220.130.216.224 220.130.216.0 220.130.217.255 中国 台湾 彰化县
2.2 实现方案
2.2.1 HBase 创建带预分区的表
这一步非常重要,hbase 建表如果不预分区,所有数据默认会写到一个分区,导入后需要长时间的 split ,compaction。 以下是我们的建表语句,指定压缩,预分区文件为手动生成的: /tmp/split.txt。
create 'ns:xx', {NAME => 'cf',COMPRESSION => 'snappy' },SPLITS_FILE => '/tmp/split.txt'
下面的重点的就是如何创建预分区,预分区的目的是让数据均衡分布在不同了 region - 分区。理解预分区需要理解 HBase rowkey 的字典排序,可以参考:[HBase] - 理解 HBase Rowkey 字典排序 - 简书
需要基于 rowkey 分布特征,划分分区,让数据均衡, hbase 提供三种预分区算法,注意DecimalStringSplit 算法 HBase 低版本1.4 以下不支持:
- UniformSplit: rowkey 前缀完全随机
- HexStringSplit: rowkey 是十六进制的字符串作为前缀的
- DecimalStringSplit: rowkey 是 10 进制数字字符串作为前缀的,范围 0-9999999 (HBase 1.4 以下版本不支持)
了解 rowkey 特征,如果适用以上算法,可以直接采用这种方式建表。例如以下是创建一个 50 个 region 的表,采用 UniformSplit 分区算法。
create 'ns:xx', {NAME => 'cf',COMPRESSION => 'snappy' }, { NUMREGIONS => 50, SPLITALGO => 'UniformSplit' }
如果 rowkey 特征不适用于上述三种算法,需要自己生成分区区间,语法为:
# 直接指定
create 'ns:xx', {NAME => 'cf',COMPRESSION => 'snappy' }, SPLITS => ['10','20','30','40']
# 通过文件指定
create 'ns:xx', {NAME => 'cf',COMPRESSION => 'snappy' }, SPLITS_FILE => '/tmp/split.txt'
分析本案例:rowkey 的特点为:数值型,范围为:0-9999999,数据分布较为均衡。
数据行数:42亿,数据量 1.2 T。
根据数据分布,输出 split 分区文件如下,按照这个粒度,一共有 200+ 分区。这个可以通过手工或者脚本生成。
100|
105|
110|
115|
...
995|
具体分多少个分区,这个不一定需要绝对精准,可以大概估算,分区多,粒度细,分区少,粒度粗。 region个数估算,大致可以依据公示 :<region 个数> = <总数据量> / <单个region 的大小>(5-8G)
来估算。
上述数据分粗一点,可以以1开头,2开头, 3开头, 4开头...9开头,一共 10 个分区。如果数据量大了 10 个分区可能太少。
1
2
3
4
5
6
7
8
9
一个 todo 疑问,是否有其他生成 splits 的方式,更优的方式?
2.2.2 导出 hive 数据
导出 hive 数据到 hdfs(字段逗号分隔)
2.2.3 生成 hfile
利用 importTsv 命令生成 hfile,需要指定列分隔符,HBASE_ROW_KEY 标识第一个字段为 rowkey,最后一个参数是数据文件的位置。
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv -Dimporttsv.separator="|" \
-Dimporttsv.bulk.output=/data/hfile_tmp/ \
-Dimporttsv.columns=HBASE_ROW_KEY,cf:ip,cf:begin_ip,cf:end_ip,cf:country,cf:province_name,cf:city_name \
-Dmapreduce.map/reduce.memory.mb=5120 \
-Dmapreduce.map/reduce.java.opts=-Xmx4096m \
ns:xx /path/to/hdfs/tsvfile
2.2.4 bulkload 导入 HBase
bulkload 的实现原理可以参考之前的文章:HBase Bulkload 迁移数据及问题思考 - 简书
命令如下:
hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /path/to/hfile hbase_table
2.2.5 major compact
导入后执行一次 major compact 有助于提高数据本地化率, 合并小文件。操作建议在闲时执行。命令在 hbase shell 执行:
major_compact 'ns:table'
3 其他导入方式
上述流程稍显麻烦,是否还有其他更优的方式?
可以基于 Hive-HBase Integration 来导入 (https://cwiki.apache.org/confluence/display/Hive/HBaseIntegration)。 步骤如下:
-
创建 HBase 表(同样注意创建预分区)
-
创建 hive 表 ,目的是为了生成 hfile,
需要注意,hive 下需要添加 HBase 相关的 jar:
add jar /lib/hive-hbase-handler-2.3.3.jar;
add jar /lib/hbase-protocol-1.1.1.jar;
add jar /lib/hbase-common-1.1.1.jar;
add jar /lib/hbase-client-1.1.1.jar;
add jar /lib/hbase-server-1.1.1.jar;
创建表:
create table stu_info{
name string comment '名字',
age int comment'年龄'
}
STORED AS
INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.hbase.HiveHFileOutputFormat'
TBLPROPERTIES ('hfile.family.path' = '/user/hive-hbase/info');
输出格式一定要为:HiveHFileOutputFormat。/user/hive-hbase/info 是生成的 hfile 在 HDFS 上的路径,其中 info 为 Hbase 的 family。
- 导入数据到 Hive 表:生成 hfile
insert overwrite table stu_info select xxx from xxx
到 hfile.family.path 目录查看生成的 hfile
- bulkload hfile 到 hbase 表
bin/hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /user/hive-hbase/info/ hbase_table
参考致謝:
使用ImportTSV向HBase中导入数据 | LouisvV's Blog
hive表数据导入到Hbase - CodeAntenna
Creating HBase HFiles From a Hive Table - Cloudera Community - 244627
理解 HBase Rowkey 字典排序 - 简书
HBase Bulkload 迁移数据及问题思考 - 简书
网友评论