HBase
Compaction(压实)机制
- 在实际过程中,由于memStore的flush条件的问题,所以容易产生大量的小文件落地到HDFS上。因此HBase针对这个问题,提供了compaction机制
- 所谓的compaction机制,本质上就是将小文件进行merge(合并)操作
- 在HBase中,提供了两种合并机制
- minor compaction:初次紧缩。将相邻的一些小文件合并成一个大文件,如果本身就是一个大文件,则不参与合并。所以合并完成之后,HStore中依然存在多个HFile
- major compaction:主要紧缩。无论文件大小,全部合并,因此合并完成之后,HStore中只存在1个HFile
- 相对而言,major compaction会涉及到大量数据的读写,所以效率相对较低。HBase默认采用的是minor compaction
- 需要注意的是:major compaction过程中,会舍弃掉被标记为删除或者过时的数据
HRegionServer读写流程
写流程
-
当HRegionServer接收到写命令之后,会先将这个命令记录到WAL中,记录成功之后会将数据更新到memStore中
-
数据在memStore中会进行排序,按照行键字典序 -> (列族字典序) -> 列字典序 -> 时间戳倒序的顺序排序
-
当memStore达到条件的时候,会将数据冲刷到HFile中。因为数据在memStore中是有序的,所以冲刷出来的HFile中的数据也是有序的。但是多次冲刷之后,多个HFile之间的数据是局部有序的
-
HFile的v1格式包含了六部分:DataBlock、MetaBlock、DataIndex、MetaIndex、FileInfo和Trailer
-
DataBlock:数据块,用于存储数据的
-
一个HFile中会包含1到多个DataBlock
-
因为HFile中的数据是有序的,所以DataBlock之间的数据也是不交叉的
-
DataBlock大小默认是64KB。小的DataBlock利于查询(get),大的DataBlock利于扫描(scan)
-
BlockCache中的空间局部性就是以DataBlock为单位来缓存:当DataBlock中某一条数据被读取的时候,这个DataBlock就会被放入BlockCache中
-
每一个DataBlock都是由1个Magic以及多个KeyValue来构成的
-
Magic:魔数,本质上就是一个随机数,用于来进行校验的。当生成Block的时候,会伴随生成Magic,如果数据发生变化,Magic也会随机变化
-
KeyValue:键值对。用于存储数据的,而数据最终都是以键值对形式来存储
-
-
MetaBlock:元数据块,用于存储元数据的。不是每一个HFile中都会包含MetaBlock,一般是
hbase:meta
文件中会包含MetaBlock-
FileInfo:文件信息,用于描述HFile的文件信息,例如文件大小等
-
DataIndex:数据索引,记录DataBlock的索引位置
-
MetaIndex:元数据索引,记录MetaBlock的索引位置
-
Trailer:在文件末尾占用固定字节大小,记录DataIndex、MetaIndex和FileInfo在文件的起始位置的
-
-
在HFile中读取数据的时候,需要先通过Trailer来锁定DataIndex的位置,通过DataIndex确定DataBlock的位置,最后从DataBlock中来读取对应的数据
-
在HFile的v2版本中,引入了BloomFilter(布隆过滤器)
- BloomFilter在使用的时候,需要定义一个字节数组和三个不同的哈希函数。针对同一个值利用三个哈希函数来进行计算,计算之后将结果映射到字节数组的某一个位置上
- 当获取数据的时候,可以利用BloomFilter来进行校验,如果计算出的结果为0,那么说明这个数据一定不存在!如果映射到的值全部是1,说明这个数据有可能存在 - BloomFilter只能确定数据不存在,但是不能保证数据存在!
- 随着添加到元素越来越多,那么此时数组中的空位会越来越少,此时误判率会越来越高,解决方案:数组扩容
读流程
- 当HRegionServer接收到读请求的时候,会先试图从BlockCache中来读取数据
- 如果BlockCache中没有指定的数据,那么会试图从memStore中来读取数据
- 如果memStore中也没有指定的数据,那么会试图从StoreFile中来读取数据。在读取StoreFile的时候,会先根据行键范围来筛选掉不符合范围的StoreFile。再利用布隆过滤器来筛选掉不符合的HFile。筛选完成之后,被过滤掉的HFile中一定不包含要找的数据,但是剩余的HFile中不一定包含要找的数据
设计与优化
设计原则
- 行键设计原则
- 行键在设计的时候要尽量散列,避免请求过于集中到某一个节点上,实现请求的负载均衡。例如可以对行键计算哈希值之后再进行存储
- 行键设计最好有意义,例如
video_xxx
,log_xxx
等。但是行键有意义,就意味着行键可能会密集分布,所以可以考虑将行键翻转存储,还可以考虑在行键之前来添加随机值 - 行键必须唯一
- 列族设计原则
- 在HBase中,虽然理论上不限制列族的数量,但是实际过程中,列族的数量最好不超过3个
- 在添加数据的时候,尽量将具有相同性质的列,或者经常查询的列放到同一个列族中,尽量避免跨列族查询
优化
-
调节DataBlock的大小。大的DataBlock利于扫描,小的DataBlock利于查询,所以可以根据实际使用场景来确定DataBlock的大小调节
# 建表的时候来指定DataBlock的大小 create 'test', {NAME => 'a', BLOCKSIZE => '65536'} # 修改DataBlock的大小 alter 'test', {NAME => 'a', BLOCKSIZE => '65536'}
-
关闭BlockCache。如果表被扫描的次数更多,此时BlockCache的作用就不大。因此可以考虑关闭BlockCache
create 'test', {NAME => 'a', BLOCKCACHE => 'true'}
-
开启布隆过滤器。布隆过滤器是对数据的反向校验。HBase中的BloomFilter默认是对行键进行校验 ,支持三个值:
NONE
,ROW
,ROWCOL
。开启BloomFilter需要消耗一定的内存,因此BloomFilter是典型的"以空间换时间"的产物create 'test', {NAME => 'a', BLOOMFILTER => 'ROW'}
-
开启数据的压缩机制。HBase支持将HFile进行压缩之后再存储到HDFS上。支持四个值:
NONE
,LZO
,SNAPPY
,GZIP
。实际过程中,使用的比较多的是LZO和SNAPPYcreate 'test', {NAME => 'a', COMPRESSION => 'NONE'}
-
显式的指定列。在进行get或者scan操作的时候,指定的越详细,读取的数据量会越少,效率会越高
-
使用批量读写。在向HBase来进行大量的读写的时候,可以使用批量操作
-
关闭WAL。在能够接收一定程度的数据丢失的时候,可以考虑关闭WAL
put.setWriteToWAL(false);
-
预创建HRegion。HRegion可以进行分裂和转移,实际上会一定程度的降低写入效率(HRegion在分裂期间,暂时停止写入数据)。在能够预估数据量的前提下,可以在建表的时候先创建好一定数量的HRegion
hbase org.apache.hadoop.hbase.util.RegionSplitter 表名 HexStringSplit -c HRegion个数 -f 列族名
-
调整Zookeeper的有效Session时长。在HBase中,所有的节点都要注册到Zookeeper上。HRegionServer默认情况下,是每隔180s会向Zookeeper发送一次心跳,那么就意味着如果HRegionServer宕机,那么最坏情况下,Zookeeper需要180s才能知道这个结果,会影响集群对外服务的效率,因此可以通过
zookeeper.session.timeout
来调节 -
内存设置。HBase在运行过程中会占用大量的内存,但是给HBase设置内存的时候,不是越大越好。因为HBase使用Java语言书写的,所以在运行过程中会进行GC操作。在GC操作的时候,HRegionServer会暂停对外服务,因此内存越大,GC的时间就越长;同时HBase占用的内存过大,此时还会影响其他框架的运行效率。实际过程中,给HRegionServer分配的内存是16~32G
# hbase-env.sh # HBase所能占用的最大内存(HMaster+HRegionServer) export HBASE_HEAPSIZE=1G # HMaster占用的内存 export HBASE_MASTER_OPTS=1G # HRegionServer占用的内存 export HBASE_REGIONSERVER_OPTS=1G
扩展
HBase和Hive的整合
-
HBase和Hive的比较
- Hive本身不存储数据,而是去管理HDFS上的数据,因此Hive不强调的读写性能,而是强调分析能力
- HBase作为非关系型数据库,强调的是读写性能,HBase对于数据的分析能力非常差
-
因此,如果需要去对HBase中的数据进行处理和分析,那么需要利用Hive来完成
-
步骤
-
进入Hive的安装目录,查看是否有操作HBase的jar包
# 进入Hive的lib目录 cd /opt/software/hive-3.1.3/lib/ # 查看是否有对应的jar包 ls hive-hbase-handler-3.1.3.jar
-
将HBase的依赖jar包放到Hive的lib目录下
cd /opt/software/hive-3.1.3/lib/ cp /opt/software/hbase-2.5.5/lib/hbase-common-2.5.5.jar ./ cp /opt/software/hbase-2.5.5/lib/hbase-server-2.5.5.jar ./ cp /opt/software/hbase-2.5.5/lib/hbase-client-2.5.5.jar ./ cp /opt/software/hbase-2.5.5/lib/hbase-protocol-2.5.5.jar ./ cp /opt/software/hbase-2.5.5/lib/hbase-it-2.5.5.jar ./ cp /opt/software/hbase-2.5.5/lib/hbase-hadoop-compat-2.5.5.jar ./ cp /opt/software/hbase-2.5.5/lib/hbase-hadoop2-compat-2.5.5.jar ./
-
修改Hive的配置文件
# 进入Hive的配置目录 cd /opt/software/hive-3.1.3/conf/ # 编辑文件 vim hive-site.xml
在文件中添加
<!-- Zookeeper的连接地址 --> <property> <name>hive.zookeeper.quorum</name> <value>hadoop01,hadoop02,hadoop03</value> </property> <!-- Zookeeper的连接端口 --> <property> <name>hive.zookeeper.client.port</name> <value>2181</value> </property>
-
启动
# 三个节点启动Zookeeper zkServer.sh start # 在第一个节点上启动HDFS start-dfs.sh # 在第三个节点上启动YARN start-yarn.sh # 在第一个节点上启动HBase start-hbase.sh # 启动Hive hive --service metastore & hive --service hiveserver2 &
-
-
在Hive中建表,映射到HBase中
-- Hive中建表 create table if not exists students ( id int, -- 学号 name string, -- 姓名 age int, -- 年龄 gender string, -- 性别 grade int, -- 年级 class int -- 班级 ) stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties ( "hbase.columns.mapping" = ":key,basic:name,basic:age,basic:gender,info:grade,info:class" ) tblproperties ( "hbase.table.name" = "students" ); -- HBase中查看表是否存在 list -- 插入数据。因为数据是落地到HBase中,所以不支持load,只能使用insert方式来插入 insert into table students values (1, 'Alice', 10, 'female', 3, 5); -- 在HBase中查看 scan 'students'
-
利用Hive来管理HBase上已经存在的表
-- 在HBase中建表 create 'person', 'basic', 'other' -- 在HBase中添加数据 put 'person', 'p1', 'basic:name', 'Adair' put 'person', 'p1', 'basic:age', 15 put 'person', 'p1', 'basic:gender', 'female' put 'person', 'p1', 'other:height', 162.5 put 'person', 'p1', 'other:weight', 52.4 put 'person', 'p1', 'other:address', 'beijing' -- 在Hive中建表管理HBase中已经存在的数据 drop table if exists person; create external table person ( id string, name string, age int, gender string, height double, weight double, address string ) stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties ( "hbase.columns.mapping" = ":key,basic:name,basic:age,basic:gender,other:height,other:weight,other:address" ) tblproperties ( "hbase.table.name" = "person" ); -- 查询数据 select * from person;
Phoenix
概述
- Phoenix是Apache提供的基于HBase的JDBC的工具,提供了类SQL语言来操作HBase
- Phoenix进行数据分析的OLTP的框架,可以预HBase、Flume、Hive、Spark、Flink等框架进行集成
- 特点
- 优点:提供了类SQL语言来操作HBase的数据,降低了学习HBase的成本
- 缺点:提供的语言并不是标准的SQL;底层是将SQL转化为HBase API操作,所以效率不如直接操作HBase
- HBase和Phoenix的版本问题:HBase2.0之前的版本适配Phoenix4.X,HBase2.0及以后版本适配Phoenix5.X
安装
-
进入软件预安装目录
cd /opt/presoftware/ # 上传或者下载Phoenix的安装包
-
解压
tar -xvf phoenix-hbase-2.5-5.1.3-bin.tar.gz -C /opt/software/
-
重命名
cd /opt/software/ mv phoenix-hbase-2.5-5.1.3-bin/ phoenix-5.1.3
-
进入Phoenix的安装目录,将Phoenix的serverjar包复制到各个节点的HBase目录中
cd phoenix-5.1.3/ cp phoenix-server-hbase-2.5-5.1.3.jar /opt/software/hbase-2.5.5/lib/ scp phoenix-server-hbase-2.5-5.1.3.jar root@hadoop02:/opt/software/hbase-2.5.5/lib/ scp phoenix-server-hbase-2.5-5.1.3.jar root@hadoop03:/opt/software/hbase-2.5.5/lib/
-
配置环境变量
# 编辑文件 vim /etc/profile.d/phoenixhome.sh # 在文件中添加 export PHOENIX_HOME=/opt/software/phoenix-5.1.3 export PHOENIX_CLASSPATH=$PHOENIX_HOME export PATH=$PATH:$PHOENIX_HOME/bin # 保存退出,生效 source /etc/profile.d/phoenixhome.sh
-
先启动Zookeeper,然后启动HDFS,启动HBase,最后启动Phoenix
sqlline.py hadoop01:2181
rofile.d/phoenixhome.sh
在文件中添加
export PHOENIX_HOME=/opt/software/phoenix-5.1.3
export PHOENIX_CLASSPATH=
P
H
O
E
N
I
X
H
O
M
E
e
x
p
o
r
t
P
A
T
H
=
PHOENIX_HOME export PATH=
PHOENIXHOMEexportPATH=PATH:$PHOENIX_HOME/bin
保存退出,生效
source /etc/profile.d/phoenixhome.sh
6. 先启动Zookeeper,然后启动HDFS,启动HBase,最后启动Phoenix
```sh
sqlline.py hadoop01:2181