值得信赖的合信云 【文章来源:华为社区】
引言 为什么要集成Hive和HBase
Hive和Hbase在大数据架构中处在不同位置,Hive是一个构建在Hadoop基础之上的数据仓库,主要解决分布式存储的大数据处理和计算问题,Hive提供了类SQL语句,叫HiveQL,
通过它可以使用SQL查询存放在HDFS上的数据,sql语句最终被转化为Map/Reduce任务运行,但是Hive不能够进行交互查询——它只能够在Haoop上批量的执行Map/Reduce任务。
Hive适合用来对一段时间内的数据进行分析查询,例如,用来计算趋势或者网站的日志。Hive不应该用来进行实时的查询。因为它需要很长时间才可以返回结果。
Hbase是Hadoop database 的简称,是一种NoSQL数据库,非常适用于海量明细数据(十亿、百亿)的随机实时查询,如交易清单、轨迹行为等。
在大数据架构中,Hive和HBase是协作关系,Hive方便地提供了Hive QL的接口来简化MapReduce的使用, 而HBase提供了低延迟的数据库访问。如果两者结合,可以利用MapReduce的优势针对HBase存储的大量内容进行离线的计算和分析。
Hive和HBase的通信原理
Hive与HBase整合的实现是利用两者本身对外的API接口互相通信来完成的,
这种相互通信是通过$HIVE_HOME/lib/hive-hbase-handler-*.jar工具类实现的。通过HBaseStorageHandler,Hive可以获取到Hive表所对应的HBase表名,列簇和列,InputFormat、OutputFormat类,创建和删除HBase表等。基本通信原理如下:
clipboard.png
spacer.gif
访问
Hive访问HBase中HTable的数据,实质上是通过MR读取HBase的数据,而MR是使用HiveHBaseTableInputFormat完成对表的切分,获取RecordReader对象来读取数据的。
对HBase表的切分原则是一个Region切分成一个Split,即表中有多少个Regions,MR中就有多少个Map;
读取HBase表数据都是通过构建Scanner,对表进行全表扫描,如果有过滤条件,则转化为Filter。当过滤条件为rowkey时,则转化为对rowkey的过滤;Scanner通过RPC调用RegionServer的next()来获取数据。
简单来说,Hive和Hbase的集成就是,打通了Hive和Hbase,使得Hive中的表创建之后,可以同时是一个Hbase的表,并且在Hive端和Hbase端都可以做任何的操作。
使用场景:
(一)将ETL操作的数据通过Hive加载到HBase中,数据源可以是文件也可以是Hive中的表。
cj1.png
(二)Hbae作为Hive的数据源,通过整合,让HBase支持JOIN、GROUP等SQL查询语法。
cj2.png
(三)构建低延时的数据仓库
cj3.png
一、 配置HBase环境
修改$HBASE_HOME/conf目录下的hbase-env.sh,添加以下配置
export JAVA_HOME=/opt/java/jdk1.8
export HADOOP_HOME=/opt/hadoop/hadoop2.8
export HBASE_HOME=/opt/hbase/hbase1.2
export HBASE_CLASSPATH=/opt/hadoop/hadoop2.8/etc/hadoop
export HBASE_PID_DIR=/root/hbase/pids
export HBASE_MANAGES_ZK=false
说明:实际配置的路径以自己的为准。HBASE_MANAGES_ZK=false 是不启用HBase自带的Zookeeper集群。
修改 hbase-site.xml
编辑hbase-site.xml 文件,在添加如下配置
<!-- 存储目录 -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://test1:9000/hbase</value>
<description>The directory shared byregion servers.</description>
</property>
<!-- hbase的端口 --><property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
<description>Property from ZooKeeper'sconfig zoo.cfg. The port at which the clients will connect. </description>
</property>
<!-- 超时时间 --><property>
<name>zookeeper.session.timeout</name>
<value>120000</value>
</property>
<!-- zookeeper 集群配置。如果是集群,则添加其它的主机地址 --><property>
<name>hbase.zookeeper.quorum</name>
<value>test1</value>
</property>
<property>
<name>hbase.tmp.dir</name>
<value>/root/hbase/tmp</value>
</property>
<!-- false是单机模式,true是分布式模式 -->
<property>
<name>hbase.cluster.distributed</name>
<value>false</value>
</property>
说明:hbase.rootdir:这个目录是region server的共享目录,用来持久化Hbase 。hbase.cluster.distributed :Hbase的运行模式。false是单机模式,true是分布式模式。若为false,Hbase和Zookeeper会运行在同一个JVM里面。
二、Hive集成HBase的配置以及测试
1,配置通信接口
因为Hive与HBase集成是利用两者本身对外的API接口互相通信来完成的,其具体工作交由Hive的lib目录中的hive-hbase-handler-.jar工具类来实现。所以只需要将hive的 hive-hbase-handler-.jar 复制到hbase/lib中就可以了。
切换到hive/lib目录下
输入:
cp hive-hbase-handler-*.jar /opt/hbase/hbase1.2/lib
注: 如果在hive整合hbase中,出现版本之类的问题,那么以hbase的版本为主,将hbase中的jar包覆盖hive的jar包。
2,hive和hbase集成测试
在进行测试的时候,确保hadoop、hbase、hive环境已经成功搭建好,并且都成功启动了。
打开xshell的两个命令窗口
一个进入hive,一个进入hbase
2.1在hive中创建映射到hbase的表
通过复制上面的jar包,我们已经实现了hive和hbase底层的打通,在上层我们需要做的是使用HQL在hive中创建一个表
与hbase进行映射,为了方便,设置两边的表名都为t_employee,存储的表也是这个表名。
在hive中输入:
create table t_employee(id int,name string) stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties("hbase.columns.mapping"=":key,st1:name") tblproperties("hbase.table.name"="t_employee","hbase.mapred.output.outputtable" = "t_employee");
说明:
a、这里面出现了三个t_employee表名,第一个t_employee 是hive表中的名称,(id int,name string) 是hive表结构。
在tblproperties 语句中还出现了2个t_employee表,
"hbase.table.name"定义的是在hbase中的表名 ,这个属性是可选的,仅当你想在Hive和Hbase中使用不同名字的表名时才需要填写,如果使用相同的名字则可以省略;
"hbase.mapred.output.outputtable"定义的第三个t_employee是存储数据表的名称,指定插入数据时写入的表,如果以后需要往该表插入数据就需要指定该值,这个可以不要,表数据就存储在第二个表中了 。
b、stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' :是指定处理的存储器,就是hive-hbase-handler-*.jar包,要做hive和hbase的集成必须要加上这一句;
c、“hbase.columns.mapping” 是定义在hive表中的字段怎么与hbase的列族进行映射。
例如:st1就是列族,name就是列。它们之间通过“:”连接。
在hive中创建的t_employee表,包括两个字段(int型的id和string型的name),映射为hbase中的表t_employee,其中:key对应hbase的rowkey,value对应hbase的st1:name列。
表成功创建之后
在hive、hbase分别中查看表和表结构
hive中输入
show tables;
describe t_employee;
1.jpg
hbase输入:
list
describe ‘t_employee’
2.jpg
可以看到表t_employee在hbase中已经创建成功了
2.2数据同步测试 进入hbase之后,在t_employee中添加两条数据 然后查询该表
put 't_employee','1001','st1:name','zhaoqian' put 't_employee','1002','st1:name','sunli' scan 't_employee' 3.jpg
然后切换到hive中查询该表
select * from t_employee; 4.jpg
然后在hive中删除该表
注:这里是要让大家看到数据同步的结果,所以将表删除了。如果大家要做测试的话,是没有必要删除该表的,因为在后面还会使用该表。
在hive中将表t_employee删除
drop table t_employee; 5.jpg
在Hbase中查看:
6.jpg
可以看到在hbase中t_employee表也被删除了,hive和hbase之间的数据同步成功!
2.3 多列和列族的映射
我们来看一个更复杂一些的例子,Hive表中的3个字段与Hbase中的2个列族的映射。
Hive建表sql命令如下:
create table t_employee2(id int,name string,age,int,salary int)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties("hbase.columns.mapping"=":id,a:b,a:c,d:e") ;
hive 表中的key字段默认与hbase中的row key 对应 ,
Hive字段(name和age)对应到1个Hbase列族(列族a的列b和c,即a:b和a:c),
另一个Hive字段(salary)对应到另一个Hbase列族的单个列(d:e),这里我们并没有指定hbase中的表名。
假设我们在hive 已有一salary表,现将表salary数据插入到表t_employee2:
insert overwrite table t_employee2 select * from salary;
m1.jpg
在Hbase中查看:
m2.jpg
2.4关联查询测试 从hive映射HBase
外部表测试——创建一个指向已经存在的Hbae表的Hive表
先在hbase中建一张t_employee_info表,添加两个列族 st1,st2
然后查看表结构
输入:
create 't_employee_info','st1','st2'
describe 't_employee_info'
17.jpg
对于在hbase已经存在的表,在hive中使用CREATE EXTERNAL TABLE来建立联系
注意:创建外部表要使用EXTERNAL 关键字
create external table t_employee_info(id int,age int,sex string)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties("hbase.columns.mapping"=":key,st1:age,st2:sex")
tblproperties("hbase.table.name"="t_employee_info");
8.jpg
然后在t_employee_info 中添加数据
put 't_employee_info','1001','st2:sex','man' put 't_employee_info','1001','st1:age','32' put 't_employee_info','1002','st1:age','25' put 't_employee_info','1002','st2:sex','woman' 9.jpg
然后在hive中查询该表 输入:
select * from t_employee_info; 10.jpg
查询到数据之后,然后将t_employee 和t_employee_info进行关联查询。
输入:
select * from t_employee a join t_employee_info b where a.id=b.id ;
11.png
说明:通过关联查询,可以得出表之间是可以关联查询的。
使用Hive集成HBase表的需注意
对HBase表进行预分区,增大其MapReduce作业的并行度
合理的设计rowkey使其尽可能的分布在预先分区好的Region上
通过set hbase.client.scanner.caching设置合理的扫描缓存