2020.12.20课堂笔记(《HBase进阶》学习指导)

《HBase 进阶》学习指导

一、Phoenix 集成 HBase

详见 2020.9.25课堂笔记(phoenix:We put the SQL back in NoSQL)

二、HBase 与 Hive 的集成

该部分需要理解 HBase 和 Hive 的不同点,以及 Hive 与 HBase 集成的适用场景。

2.1 HBase 与 Hive 的对比

1.Hive

(1)数据仓库
Hive 的本质其实就相当于将 HDFS 中已经存储的文件在 Mysql 中做了一个映射关系,以方便使用 HQL 去管理查询。
(2)用于数据分析、清洗
Hive 适用于离线的数据分析和清洗,延迟较高。
(3)基于 HDFS、MapReduce
Hive 存储的数据依旧在 DataNode 上,编写的 HQL 语句终将是转换为MapReduce 代码执行。

2.HBase

(1)数据库
是一种面向列存储的非关系型数据库。
(2)用于存储结构化和非结构化的数据
适用于单表非关系型数据的存储,不适合做关联查询,类似 JOIN 等操作。
(3)基于 HDFS
数据持久化存储的体现形式是 HFile,存放于 DataNode 中,被 RegionServer以 Region 的形式进行管理。
(4)延迟较低,接入在线业务使用
面对大量的企业数据,HBase 可以直线单表大量数据的存储,同时提供了高效的数据访问速度。

2.2 HBase 与 Hive 集成使用(开发重点)

该部分内容是重点内容,项目中也会使用到 HBase 与 Hive 的集成。尤其是
代码要会写。
我们目前使用的 HBase 与 Hive 版本是 CDH5.14.2,不需要做配置即可使用,
如果采用 Apache 的版本,可能需要自己整合 HBase 一些 Jar 包到 Hive 的 lib 目录
中,这个可以查找相关资料。

1.案例一

目标:建立 Hive 表,关联 HBase 表,插入数据到 Hive 表的同时能够影响 HBase 表。
分步实现:
(1)在 Hive 中创建表同时关联 HBase

注意:-- Hive 中只支持 select 和 insert,不支持 HBase 中的版本控制。

在HBase中的建表语句如下:

# 启动hbase
启动zookeeper:   zkServer.sh start
启动hbase:       start-hbase.sh
进入hbase        shell:hbase shell
# 创建表customer  定义两个列族 addr 和 order
create 'customer' ,{ NAME=>'addr'},{NAME =>'order'}
// 插入数据  向addr列族中插入RowKey为r1 列city city列的值为NanJing
put 'customer','r1','addr:city','NanJing'
scan 'customer'
ROW         COLUMN+CELL
 r1         column=addr:city, timestamp=1608193479129, value=NanJing

在hive中创建外部表关联HBase中的customer表:

-- 在 hive 中创建外部表
create external table customer(
name string,
order_numb string,
order_date string,
addr_city string,
addr_state string)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties
("hbase.columns.mapping"=":key,order:numb,order:date,addr:city,addr:state")
tblproperties("hbase.table.name" = "customer");

提示:完成之后,可以分别进入 Hive 和 HBase 查看,都生成了对应的表
(2)向 hive 表中插入数据,在 hive 中执行如下语句。

hive> insert into table customer values ('James','1121','2018-05-31','toronto','ON');

(3)在 HBase Shell 中查看表中的记录

hbase(main):002:0> scan 'customer'
hbase(main):005:0> scan 'customer'
ROW                   COLUMN+CELL
 James                column=addr:city, timestamp=1608550468425, value=toronto
 James                column=addr:state, timestamp=1608550468425, value=ON
 James                column=order:date, timestamp=1608550468425, value=2018-05-31
 James                column=order:numb, timestamp=1608550468425, value=1121
 r1                   column=addr:city, timestamp=1608193479129, value=NanJing

(4)可以在 HBase 中插入数据,然后在 Hive 表中查看更新的数据。

hbase(main):002:0> put 'customer','3','order:numb','1800'
hive> select * from customer;
OK
3       1800    NULL         NULL      NULL
James   1121    2018-05-31  toronto    ON
r1      NULL    NULL        NanJing    NULL
2.案例二

目标:在 HBase 中已经存储了某一张表 customer,然后在 Hive 中创建一个外部表来关联 HBase 中的 customer 这张表,使之可以借助 Hive 来分析 HBase 这张表中的数据。
注:该案例 2 紧跟案例 1 的脚步,所以完成此案例前,请先完成案例 1。
(1)在 Hive 中创建外部表

create external table relevance_customer(
name string,
order_numb string,
order_date string,
addr_city string,
addr_state string)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties
("hbase.columns.mapping"=":key,order:numb,order:date,addr:city,addr:state")
tblproperties("hbase.table.name" = "customer");

(2)关联后就可以使用 Hive 函数进行一些分析操作了

hive (default)> select * from relevance_customer;
OK
3       1800    NULL         NULL      NULL
James   1121    2018-05-31  toronto    ON
r1      NULL    NULL        NanJing    NULL

三、HBase 管理

3.1 Region 管理

前面介绍元数据部分的时候可以看出,一个 Region 就是一个表的一段 Rowkey 的数据集合。HBase 设计中,当某个 Region 太大的时候 HBase 会拆分它。
那么为什么要拆分 Region?因为当某个 Region 太大的时候读取效率太低了。
想想我们为什么从 MySQL、Oracle 转移到 NoSQL 来?
最根本的原因就是这些关系型数据库把数据放到一个地方,查询的本质其实也就是遍历 key;而当数据增大到上亿的时候同一个磁盘已经无法应付这些数据的读取了,因为遍历一遍数据的时间实在太长了。我们用 NoSQL 的理由就是其能把大数据分拆到不同的机器上,然后就像查询一个完整的数据一样查询他们。但是当你的 Region 太大的时候,此时这个 Region 一样会遇到跟传统关系型数据库一样的问题,所以 HBase会拆分 Region。
这也是 HBase 的一个优点,可以说 HBase 为“一个会自动分片的数据库”
Region 的拆分分为自动拆分和手动拆分。其中自动拆分可以采用不同的策略。

3.1.1 Region 的自动拆分

1. ConstantSizeRegionSplitPolicy(了解内容)
在 0.94 版本的时候 HBase 只有一种拆分策略。这个策略非常简单,从名字上就可以看出这个策略就是按照固定大小来拆分 Region。控制它的参数是:
hbase.hregion.max.filesize Region 的最大大小。默认是 10GB
当单个 Region 大小超过了 10GB,就会被 HBase 拆分成为 2 个 Region。采用这种策略后的集群中的 Region 大小很平均。由于这种策略太简单了,所以不再详细解释了。

2. IncreasingToUpperBoundRegionSplitPolicy(0.94 版本后默认)需要掌握理解。
0.94 版本之后,有了 IncreasingToUpperBoundRegionSplitPolicy 策略。
这种策略从名字上就可以看出是限制不断增长的文件尺寸的策略。依赖以下公式来计算文件尺寸的上限增长:

Math.min(tableRegionsCounts^3 * initialSize,defaultRegionMaxFileSize)

tableRegionCount
表在所有 RegionServer 上所拥有的 Region 数量总和。
initialSize
如果定义了 hbase.increasing.policy.initial.size,则使用这个数值。
如果没有定义,就用 memstore 的刷写大小的2倍
hbase.hregion.memstore.flush.size * 2。
defaultRegionMaxFileSize
ConstantSizeRegionSplitPolicy 所用到的hbase.hregion.max.filesize,即 Region 最大大小。
假如 hbase.hregion.memstore.flush.size 定义为 128MB,那么文件尺寸的上限增长将是这样:

刚开始只有一个 region 的时候,上限是 256MB ,因为 1^3 * 128 * 2= 256 MB。
当有 2 个 region 的时候,上限是 2GB,因为 2^3 * 128 * 2= 2048 MB。
当有 3 个文件的时候,上限是 6.75GB,因为 3^3 * 128 * 2= 6912 MB。
以此类推,直到计算出来的上限达到 hbase.hregion.max.filesize 所定义region 的 10GB。

在这里插入图片描述
当Region个数达到4个的时候由于计算出来的上限已经达到了16GB,已经大于10GB了,所以后面当Region数量再增加的时候文件大小上限已经不会增加了。在最新的版本里IncreasingToUpperBoundRegionSplitPolicy是默认的配置。
3.KeyPrefixRegionSplitPolicy(扩展内容)
除了简单粗暴地根据大小来拆分,我们还可以自己定义拆分点。
KeyPrefixRegionSplitPolicy是IncreasingToUpperBoundRegionSplitPolicy的子类,在前者的基础上,增加了对拆分点(splitPoint,拆分点就是Region被拆分处的rowkey)的定义。它保证了有相同前缀的rowkey不会被拆分到两个不同的Region里面。这个策略用到的参数如下:

KeyPrefixRegionSplitPolicy.prefix_length      //rowkey的前缀长度

该策略会根据KeyPrefixRegionSplitPolicy.prefix_length所定义的长度来截取rowkey作为分组的依据,同一个组的数据不会被划分到不同的Region上。比如rowKey都是16位的,指定前5位是前缀,那么前5位相同的rowKey在进行regionsplit的时候会分到相同的region中。用默认策略拆分跟用KeyPrefixRegionSplitPolicy拆分的区别如下。
使用默认策略拆分的结果如图。
在这里插入图片描述用 KeyPrefixRegionSplitPolicy(前 2 位)拆分的结果如图。
在这里插入图片描述

如果你的所有数据都只有一两个前缀,那么 KeyPrefixRegionSplitPolicy 就无效了,此时采用默认的策略较好。如果你的前缀划分的比较细,你的查询就比较容易发生跨 Region 查询的情况,此时采用 KeyPrefixRegionSplitPolicy 较好。
所以这个策略适用的场景是:数据有多种前缀。查询多是针对前缀,比较少跨越多个前缀来查询数据。
4.DelimitedKeyPrefixRegionSplitPolicy(扩展内容)
该策略也是继承自IncreasingToUpperBoundRegionSplitPolicy,它也是根据你的rowkey前缀来进行切分的。唯一的不同就是:KeyPrefixRegionSplitPolicy是根据rowkey的固定前几位字符来进行判断,而DelimitedKeyPrefixRegionSplitPolicy是根据分隔符来判断的。有时候rowkey的前缀可能不一定都是定长的,比如你拿服务器的名字来当前缀,有的服务器叫host12有的叫host1。这些场景下严格地要求所有前缀都定长可能比较难,而且这个定长如果未来想改也不容易。
DelimitedKeyPrefixRegionSplitPolicy就给了你一个定义长度字符前缀的自由。使用这个策略需要在表定义中加入以下属性:
DelimitedKeyPrefixRegionSplitPolicy.delimiter:前缀分隔符。比如你定义了前缀分隔符为_,那么host1_001和host12_999的前缀就分别是host1和host12。
5.BusyRegionSplitPolicy(扩展内容)
此前的拆分策略都没有考虑热点问题。所谓热点问题就是数据库中,的Region被访问的频率并不一样,某些Region在短时间内被访问的很频繁,承载了很大的压力,这些Region就是热点Region。BusyRegionSplitPolicy就是为了解决这种场景而产生的。它是如何判断哪个Region是热点的呢先要介绍它用到的参数:
hbase.busy.policy.blockedRequests:请求阻塞率,即请求被阻塞的严重程度。
取值范围是0.0~1.0,默认是0.2,即20%的请求被阻塞的意思。
hbase.busy.policy.minAge:拆分最小年龄,当Region的年龄比这个小的时候不拆分,这是为了防止在判断是否要拆分的时候出现了短时间的访问频率波峰,结果没必要拆分的Region被拆分了,因为短时间的波峰会很快地降回到正常水平。单位毫秒,默认值是600000,即10分钟。
hbase.busy.policy.aggWindow:计算是否繁忙的时间窗口,单位毫秒,默认值是300000,即5分钟。用以控制计算的频率。计算该Region是否繁忙的计算方法如下:
如果“当前时间–上次检测时间>=hbase.busy.policy.aggWindow”,则进行如下计算:这段时间被阻塞的请求/这段时间的总请求=请求的被阻塞率(aggBlockedRate)如果“aggBlockedRate>hbase.busy.policy.blockedRequests”,则判断该Region为繁忙。
如果你的系统常常会出现热点Region,而你对性能有很高的追求,那么这种策略可能会比较适合你。它会通过拆分热点Region来缓解热点Region的压力,但是根据热点来拆分Region也会带来很多不确定性因素,因为你也不知道下一个被拆分的Region是哪个。
6.DisabledRegionSplitPolicy
这种策略其实不是一种策略。如果你看这个策略的源码会发现就一个方法shouldSplit,并且永远返回false。所以设置成这种策略就是Region永不自动拆分。
如果使用DisabledRegionSplitPolicy让Region永不自动拆分之后,你依然可以通过手动拆分来拆分Region。
这个策略有什么用?无论你设置了哪种拆分策略,一开始数据进入Hbase的时候都只会往一个Region塞数据。必须要等到一个Region的大小膨胀到某个阀值的时候才会根据拆分策略来进行拆分。但是当大量的数据涌入的时候,可能会出现一边拆分一边写入大量数据的情况,由于拆分要占用大量IO,有可能对数据库造成一定的压力。如果你事先就知道这个Table应该按怎样的策略来拆分Region的话,你也可以事先定义拆分点(SplitPoint)。所谓拆分点就是拆分处的rowkey,比如你可以按26个字母来定义25个拆分点,这样数据一到HBase就会被分配到各自所属的Region里面。这时候我们就可以把自动拆分关掉,只用手动拆分。
手动拆分有两种情况:预拆分(pre-splitting)和强制拆分(forcedsplits)。

3.1.2Region的预拆分

预拆分(pre-splitting)就是在建表的时候就定义好了拆分点的算法,所以叫预拆分。使用org.apache.hadoop.hbase.util.RegionSplitter类来创建表,并传入拆分点算法就可以在建表的同时定义拆分点算法。
1.快速入门
我们要新建一张表,并且规定了该表的Region数量永远只有10个。在Linux下执行:
[root@hadoop101~]$hbaseorg.apache.hadoop.hbase.util.RegionSplitter
my_split_tableHexStringSplit-c10-fmycf
my_split_table:我们指定要新建的表名。
HexStringSplit:指定的拆分点算法为HexStringSplit。
-c:要拆分的Region数量。
-f:要建立的列族名称。
上面这条命令的意思就是新建一个叫my_split_table的表,并根据HexStringSplit拆分点算法预拆分为10个Region,同时要建立的列族叫mycf。建完后用hbaseshell看一下结果。执行命令查出所有10个Region的信息:

hbase(main):013:0>scan'hbase:meta',{STARTROW=>'my_split_table',LIMIT=>10}

可以看到已经建立的10个Region,由于输出信息太多,我只截取其中关于每一个Region的起始rowkey和结束rowkey的信息,这10个Region的范围分别是:

STARTKEY=>'',ENDKEY=>'19999999'
STARTKEY=>'19999999',ENDKEY=>'33333332'
STARTKEY=>'33333332',ENDKEY=>'4ccccccb'
STARTKEY=>'4ccccccb',ENDKEY=>'66666664'
STARTKEY=>'66666664',ENDKEY=>'7ffffffd'
STARTKEY=>'7ffffffd',ENDKEY=>'99999996'
STARTKEY=>'99999996',ENDKEY=>'b333332f'
STARTKEY=>'b333332f',ENDKEY=>'ccccccc8'
STARTKEY=>'ccccccc8',ENDKEY=>'e6666661'
STARTKEY=>'e6666661',ENDKEY=>''

这就是你预定了拆分点后的Region。
2.拆分算法(扩展内容)
(1)HexStringSplit拆分算法
在快速入门例子中使用的算法就是HexStringSplit算法。HexStringSplit把数据从“00000000”到“FFFFFFFF”之间的数据长度按照n等分之后算出每一段的起始rowkey和结束rowkey,以此作为拆分点。就是这么简单。
(2)UniformSplit拆分算法
UniformSplit有点像HexStringSplit的byte版,传参还是n,唯一不一样的是起始和结束不是String,而是byte[]。起始rowkey是ArrayUtils.EMPTY_BYTE_ARRAY。
结束rowkey是newbyte[]{xFF,xFF,xFF,xFF,xFF,xFF,xFF,xFF}。最后调用Bytes.split方法把起始rowkey到结束rowkey之间的长度n等分,然后取每一段的起始和结束作为拆分点。默认的拆分点算法就这两个。还可以通过实现SplitAlgorithm接口实现自己的拆分算法。或者干脆手动定出拆分点。
3.手动指定拆分点
手动指定拆分点的方法就是在建表的时候跟上SPLITS参数,比如:
create’test_split2’,‘mycf2’,SPLITS=>[‘aaa’,‘bbb’,‘ccc’,‘ddd’,‘eee’,‘fff’]
上述语句在HBaseshell中执行,执行完成后,可以通过HBaseWebUI中查看相关信息,如下图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值