男
六、Hive和Hbase整合理论
1、为什么hive要和hbase整合
2、整合的优缺点
优点:
(1).Hive方便地提供了Hive QL的接口来简化MapReduce的使用,
而HBase提供了低延迟的数据库访问。如果两者结合,可以利
用MapReduce的优势针对HBase存储的大量内容进行离线的计算和分析。
(2).操作方便,hive提供了大量系统功能
缺点:
性能的损失,hive有这样的功能, 他支持通过类似sql语句的语法来操作hbase
中的数据, 但是速度慢。
3、整合需要做什么样的准备工作
4、整合后的目标
(1). 在hive中创建的表能直接创建保存到hbase中。
(2). 往hive中的表插入数据,数据会同步更新到hbase对应的表中。
(3). hbase对应的列簇值变更,也会在Hive中对应的表中变更。
(4). 实现了多列,多列簇的转化:(示例:hive中3列对应hbase中2列簇)
5、hive和Hbase整合后如果通信?
查看hive和Hbase通信图:
主要是通过hive 的lib目录下的hive-hbase-handler-1.2.1.jar来实现hive
和Hbase通信。
二、Hive和Hbase整合案例操作
案例一:
(1). 在hive中创建的表能直接创建保存到hbase中。(Hive表多个字段)
create database hbase;
create table if not exists hbase.hive_hbase01(
eID int,
eName String,
eAge int,
eSex String,
eAddress String
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf_info:eName,cf_info:eAge,cf_info:eSex,cf_beizhu:eAddress")
TBLPROPERTIES ("hbase.table.name" = "hadoop3_1:hive_hbase01");
-- select * from hbase.hive_hbase01;
说明:
1.默认情况下hbase会把hive的第一个字段作为自己的rowkey,在创建hive表时,":key"或者不写。
2.hbase的列族和列名对应hive表的字段(从第二个字段开始对应)
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf_info:eName,cf_info:eAge,cf_info:eSex,cf_beizhu:eAddress")
3.设置hbase的表名,如果下想在默认的命名空间下创建识别表,直接写hive_hbase01表名
TBLPROPERTIES ("hbase.table.name" = "hadoop3_1:hive_hbase01");
说明:
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
是创建hive和habse识别表时需要org.apache.hadoop.hive.hbase.HBaseStorageHandler进行通信
with serdeproperties("hbase.columns.mapping"=":key,cf_info:eName,cf_info:eAge,cf_info:eSex,cf_beizhu:eAddress")
指定hive表的列和hbase列族和别名的对应关系
tblproperties("hbase.table.name"="ns2:hive_hbase01");
设置在hbase中生成的表名,如果是在指定的命名空间下需要,命名空间:表名
建表提示错误。。。。???
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. org.apache.hadoop.hbase.HTableDescriptor.addFamily(Lorg/apache/hadoop/hbase/HColumnDescriptor;)V
hive版本是1.2.0
hbase版本
把hive的lib下 使用 hive-hbase-handler-1.2.1.jar 替换掉 hive-hbase-handler-1.2.0.jar 完美解决!
vi hive_hbase.txt
201705,zhangsan,18,nan,beijing
201707,lisi,20,nv,shanghai
201708,laoli,25,nan,beijing
201709,laozhang,15,nv,shanghai
使用 load 方式加载数据:
加载数据到hive和Hbase识别表:
load data local inpath'/home/hadoop/hbase/hive_hbase.txt' into table hbase.hive_hbase01;
提错误:
FAILED: SemanticException [Error 10101]: A non-native table cannot be used as target for LOAD
--只能以结果集的形式插入数据
创建普通的hive表:
create table if not exists hbase.hive_hbase01_temp(
eID int,
eName String,
eAge int,
eSex String,
eAddress String
)
row format delimited fields terminated by ',';
load data local inpath'/home/hadoop/hbase/hive_hbase.txt' into table hbase.hive_hbase01_temp;
select * from hbase.hive_hbase01_temp;
把普通表的数据添加到Hive和Hbase都能识别的表:
insert into table hbase.hive_hbase01 select * from hbase.hive_hbase01_temp;
select * from hbase.hive_hbase01;
--使用select 查询时 如果是hbase 1.0以下报错 ?? hbase1.0版本以上就不会报这个错
Failed with exception java.io.IOException:java.io.IOException: The connection has to be unmanaged. 连接不受管理
查看Hbase的有没有表
list_namespace_tables 'ns2'
scan 'ns2:hive_hbase01'
查看hive表数据:
select * from hbase.hive_hbase02;
在Hbase中添加数据到hive和Hbase识别表:
put 'hadoop3_1:hive_hbase01','20170610','cf_info:eName','zhangqi'
put 'hadoop3_1:hive_hbase01','20170610','cf_info:eAge',90
put 'hadoop3_1:hive_hbase01','20170610','cf_info:eSex','nan'
put 'hadoop3_1:hive_hbase01','20170610','cf_beizhu:eAddress','dg'
再次查看hive
select * from hive_hbase01;
案例二:
1. 创建hbase识别的表:
create table hbase.hbase_table_1(
key int,
value string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties ("hbase.columns.mapping" = ":key,cf1:val")
tblproperties ("hbase.table.name" = "ns2:xyz");
hbase.table.name 定义在hbase的table名称
hbase.columns.mapping 定义在hbase的列族
hbase中看到的表:
hbase(main):007:0> list
2.使用sql导入数据
预先准备数据
vi kv1.txt
1 val_1
2 val_2
a)新建hive的数据表
create table hbase.hbase_table_1_temp(
foo int,
bar string
)
row format delimited fields terminated by '\t'
lines terminated by '\n'
stored as textfile;
load data local inpath '/home/hadoop/hbase/kv1.txt' overwrite into table hbase.hbase_table_1_temp;
select * from hbase.hbase_table_1_temp;
使用sql导入hbase_table_1
insert overwrite table hbase.hbase_table_1 select * from hbase.hbase_table_1_temp where foo=1;
select * from hbase.hbase_table_1;
hbase 登录hbase
查看加载的数据
hbase(main):008:0> scan "ns2:xyz"
--###############################################
--Hbase 已经存在的表和hive进行整合:
--2.如果Hbase已经存在一个表,并且存储大量的数据,如何创建一个Hive表来操作这个Hbase表的数据。
1.在Hbase中先创建一个Hbase表:
create_namespace 'hadoop3_1'
create 'hadoop3_1:hbase_stu','cf_stu_baseinfo','cf_stu_other'
put 'hadoop3_1:hbase_stu','rk2017051201','cf_stu_baseinfo:stu_name','xiaowu'
put 'hadoop3_1:hbase_stu','rk2017051201','cf_stu_baseinfo:stu_age',20
put 'hadoop3_1:hbase_stu','rk2017051201','cf_stu_other:stu_like','sleep'
put 'hadoop3_1:hbase_stu','rk2017051202','cf_stu_baseinfo:stu_name','xiaolaoli'
put 'hadoop3_1:hbase_stu','rk2017051202','cf_stu_baseinfo:stu_age',1
put 'hadoop3_1:hbase_stu','rk2017051202','cf_stu_other:stu_like','cry'
put 'hadoop3_1:hbase_stu','czl20170520','cf_stu_baseinfo:stu_name','xiaoyi'
put 'hadoop3_1:hbase_stu','czl20170520','cf_stu_baseinfo:stu_age',10
put 'hadoop3_1:hbase_stu','czl20170520','cf_stu_other:stu_like','sleep'
put 'hadoop3_1:hbase_stu','czl20170521','cf_stu_baseinfo:stu_name','xiaoer'
put 'hadoop3_1:hbase_stu','czl20170521','cf_stu_baseinfo:stu_age',20
put 'hadoop3_1:hbase_stu','czl20170521','cf_stu_other:stu_like','cry'
--非结构化数据 添加到 结构化hive表中 不存在的字段 hive建表指定列族
put 'hadoop3_1:hbase_stu','czl20170521','cf_stu_other:stu_like_like','cry'
2、在Hive中创一个Hive表来识别已经存在的Hbase表:
create EXTERNAL table if not exists hbase.hbase_students(
stu_no string,
stu_name string,
stu_age int,
stu_like string
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf_stu_baseinfo:stu_name,cf_stu_baseinfo:stu_age,cf_stu_other:stu_like")
TBLPROPERTIES ("hbase.table.name" = "hadoop3_1:hbase_stu");
--####################################################
-- CREATE EXTERNAL TABLE hbase.hbase_students_emp (
-- rowkey string,
-- cf_stu_baseinfo map
-- )
-- STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
-- WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf_stu_baseinfo:")
-- TBLPROPERTIES ("hbase.table.name" = "hadoop3_1:hbase_stu");
-- select * from hbase.hbase_students_emp;
-- --hbase 插入数据
-- put 'hadoop3_1:hbase_stu','czl20170522','cf_stu_baseinfo:stu_name','xiaoyi'
-- put 'hadoop3_1:hbase_stu','czl20170522','cf_stu_baseinfo:stu_age',10
-- put 'hadoop3_1:hbase_stu','czl20170522','cf_stu_baseinfo:stu_sex','nan'
-- put 'hadoop3_1:hbase_stu','czl20170522','cf_stu_other:stu_like','sleep'
--####################################################
注意:因为Hbase已经存在Hbase表,所有创建hive识别表时必须是EXTERNAL类型!!!
查看hive表数据:
select * from hbase.hbase_students;
同样可以用insert into方式添加数据到 hive中的表hbaese_students,然后在Hbase中可以查看到添加的数据!
概念(Hive over HBase原理--加强)
Hive与Hbase和mapreduce 利用两者本身对外的API来实现整合,主要是靠HBaseStorageHandler进行通信,利用 HBaseStorageHandler,Hive可以获取到Hive表对应的HBase表名,列簇以及列,InputFormat和OutputFormat类,创建和删除HBase表等。Hive访问HBase中表数据,实质上是通过MapReduce读取HBase表数据,其实现是在MR中,使用HiveHBaseTableInputFormat完成对HBase表的切分,获取RecordReader对象来读取数据。对HBase表的切分原则是一个Region切分成一个Split,即表中有多少个Regions,MR中就有多少个Mapper读取HBase表数据都是通过构建Scanner,对表进行全表扫描,如果有过滤条件,则转化为Filter。当过滤条件为rowkey时,则转化为对rowkey的过滤;Scanner通过RPC调用RegionServer的next()来获取数据;
三、性能瓶颈分析
1. Map Task
Hive读取HBase表,通过MR,最终使用HiveHBaseTableInputFormat来读取数据,在getSplit()方法中对 HBase表进行切分,切分原则是根据该表对应的HRegion,将每一个Region作为一个InputSplit,即,该表有多少个Region,就 有多少个Map Task;
每个Region的大小由参数hbase.hregion.max.filesize控制,默认10G,这样会使得每个map task处理的数据文件太大,map task性能自然很差;
为HBase表预分配Region,使得每个Region的大小在合理的范围;
2. Scan RPC 调用:
在Scan中的每一次next()方法都会为每一行数据生成一个单独的RPC请求, 全表有2500万行记录,因此要2500万次RPC请求;
扫描器缓存(Scanner Caching):HBase为扫描器提供了缓存的功能,可以通过参数hbase.client.scanner.caching来设置;默认是100;缓存 的原理是通过设置一个缓存的行数,当客户端通过RPC请求RegionServer获取数据时,RegionServer先将数据缓存到内存,当缓存的数 据行数达到参数设置的数量时,再一起返回给客户端。这样,通过设置扫描器缓存,就可以大幅度减少客户端RPC调用RegionServer的次数;但并不 是缓存设置的越大越好,如果设置的太大,每一次RPC调用将会占用更长的时间,因为要获取更多的数据并传输到客端,如果返回给客户端的数据超出了其堆的 大小,程序就会终止并跑出OOM异常;