HBase精讲(下)

一、Phoenix 集成 HBase

1.1、Phoenix 与 HBase 集成环境搭建

Phoenix 下载及安装配置详见:Phoenix 4.14下载并安装.

Phoenix 启动

sqlline.py  localhost

查看所有表

!tables

Phoenix 安装启动成功如下图所示
在这里插入图片描述

1.2、HBase 其他API

API类别API信息
Javahttps://hbase.apache.org/apidocs/
Pythonhttps://happybase.readthedocs.org/en/latest/
ScalaThrough Java/Spark
Thrifthttps://wiki.apache.org/hadoop/Hbase/ThriftApi
RESThttp://blog.cloudera.com/blog/2013/03/how-to-use-the-apache-hbase-rest-interface-part-1/

1.3、使用 rest API操作HBase

(1)启动和停止rest 服务

hbase-daemon.sh start rest -p 9081
hbase-daemon.sh stop rest -p 9081

(2)使用示例

http://localhost:9081/version
http://localhost:9081/<table_name>/schema
http://localhost:9081/<table_name>/<row_key>

二、Phoenix概述

2.1、Phoenix简介

Phoenix使HBase更易用

  • 构建在HBase上的SQL层
  • 使用标准SQL在HBase中管理数据
  • 使用JDBC来创建表,插入数据、对HBase数据进行查询
  • Phoenix JDBC Driver容易嵌入到支持JDBC的程序中

Phoenix无法代替RDBMS

  • 缺乏完整性约束,很多领域尚不成熟

2.2、Phoenix应用场景

  • 快速而容易地构建基于HBase的应用程序
  • 需要极大的规模、性能和并发性的SQL应用程序
  • 在转换到Hadoop时重用已有的SQL技能
  • BI工具(对SQL支持较好)

2.3、Phoenix 字段类型

字段类型
integerjava.lang.Integer
unsigned_intjava.lang.Integer
bigintjava.lang.Long
unsigned_longjava.lang.Long
tinyintjava.lang.Byte
unsigned_tinyintjava.lang.Byte
smallintjava.lang.Short
unsigned_smallintjava.lang.Short
floatjava. lang.Float
unsigned_floatjava.lang.Float
doublejava.lang.Double
unsigned_doublejava.lang.Double
decimaljava.math.BigDecimal
booleanjava.lang.Boolean
timejava.sql.Time
datejava.sql.Date
timestampjava.sql.Timestamp
unsigned_timejava.sql.Time
unsigned_datejava.sql.Date
unsigned_timestampjava.sql.Timestamp
varchar(int)java.lang.String
char(int)java.lang.String
binary(int)byte[ ]
varbinarybyte[ ]

2.4、Phoenix操作HBase

2.4.1、创建表

create table company (company_id integer primary key, name varchar(225));

create table stock (company_id integer primary key, price decimal(10,2));

2.4.2、查看表

!tables

2.4.3、查看表所有的列

!columns company

2.4.4、插入数据

upsert into company values(1, 'microsoft');
upsert into company values(2, 'ibm');
upsert into company values(3, 'oracle');
upsert into company values(4, 'twitter');
upsert into company values(5, 'facebook');

upsert into stock values(1, 124.9);
upsert into stock values(2, 99);
upsert into stock values(3, 150.9);
upsert into stock values(4, 45.5);
upsert into stock values(5, 120.5);

2.4.5、查询数据

与 mysql 相同

select * from company;

2.4.6、删除数据

delete from company where company_id=5;

2.4.7、表关联操作

select s.company_id, c.name, s.price
from stock s left outer join company c
on s.company_id = c.company_id;

2.4.8、退出

!quit

三、HBase 与 Hive 的集成

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

3.1、HBase 与 Hive 的对比

3.1.1、Hive

(1)数据仓库

Hive 的本质其实就相当于将 HDFS 中已经存储的文件在 Mysql 中做了一个映射关系,以方便使用 HQL 去管理查询。

(2)用于数据分析、清洗

Hive 适用于离线的数据分析和清洗,延迟较高。

(3)基于 HDFS、MapReduce

Hive 存储的数据依旧在 DataNode 上,编写的 HQL 语句终将是转换为 MapReduce 代码执行。

3.1.2、HBase

(1)数据库

Hbase 是一种面向列存储的非关系型数据库。

(2)用于存储结构化和非结构化的数据

适用于单表非关系型数据的存储,不适合做关联查询,类似 JOIN 等操作。

(3)基于 HDFS

数据持久化存储的体现形式是 HFile,存放于 DataNode 中,被 RegionServer 以 Region 的形式进行管理。

(4)延迟较低,接入在线业务使用

面对大量的企业数据,HBase 可以直线单表大量数据的存储,同时提供了高效的数据访问速度。

3.2 HBase 与 Hive 集成使用

我们目前使用的 HBase 与 Hive 版本是 CDH5.14.2,不需要做配置即可使用,如果采用 Apache 的版本,可能需要自己整合 HBase 一些 Jar 包到 Hive 的 lib 目录中,这个可以查找相关资料。

案例一

目标:建立 Hive 表,关联 HBase 表,插入数据到 Hive 表的同时能够影响 HBase 表。

分步实现:

(1)在 Hive 中创建表同时关联 HBase

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 中只支持 select 和 insert,不支持 HBase 中的版本控制。
提示:完成之后,可以分别进入 Hive 和 HBase 查看,都生成了对应的表

(2)向 hive 表中插入数据,在 hive 中执行如下语句

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

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

scan 'customer'

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

put 'customer','3','order:numb','1800'
select * from customer;

案例二

目标:在 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 函数进行一些分析操作了

 select * from relevance_customer;

四、HBase管理

4.1、Region管理

前面介绍元数据部分的时候可以看出,一个 Region 就是一个表的一段 Rowkey 的数据集合。HBase 设计中,当某个 Region 太大的时候 HBase 会拆分它。

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

Region 的拆分分为自动拆分和手动拆分。其中自动拆分可以采用不同的策略。

4.1.1、Region 的自动拆分

1)ConstantSizeRegionSplitPolicy

在 0.94 版本的时候 HBase 只有一种拆分策略。这个策略非常简单,从名字上就可以看出这个策略就是按照固定大小来拆分 Region。控制它的参数是:

hbase.hregion.max.filesizeRegion 的最大大小。默认是 10GB

当单个 Region 大小超过了 10GB,就会被 HBase 拆分成为 2 个 Region。采用这种策略后的集群中的 Region 大小很平均。由于这种策略太简单了,所以不再详细解释了。

2)IncreasingToUpperBoundRegionSplitPolicy

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,那么文件尺寸的上限增长将是这样:

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

走势图如下图
Region 大小上限
当 Region 个数达到 4 个的时候由于计算出来的上限已经达到了 16GB,已经大于 10GB 了,所以后面当 Region 数量再增加的时候文件大小上限已经不会增加了。在最新的版本里 IncreasingToUpperBoundRegionSplitPolicy 是默认的配置。

3)KeyPrefixRegionSplitPolicy

除了简单粗暴地根据大小来拆分,我们还可以自己定义拆分点。KeyPrefixRegionSplitPolicy 是IncreasingToUpperBoundRegionSplitPolicy 的子类,在前者的基础上,增加了对拆分点(splitPoint,拆分点就是 Region 被拆分处的 rowkey)的定义。它保证了有相同前缀的 rowkey 不会被拆分到两个不同的 Region 里面。这个策略用到的参数如下:

KeyPrefixRegionSplitPolicy.prefix_lengthrowkey 的前缀长度

该策略会根据 KeyPrefixRegionSplitPolicy.prefix_length 所定义的长度来截取 rowkey 作为分组的依据,同一个组的数据不会被划分到不同的 Region 上。

比如 rowKey 都是 16 位的,指定前 5 位是前缀,那么前 5 位相同的 rowKey 在进行 region split 的时候会分到相同的 region 中。用默认策略拆分跟用 KeyPrefixRegionSplitPolicy 拆分的区别如下。

使用默认策略拆分的结果如图
默认策略拆分结果图
用 KeyPrefixRegionSplitPolicy(前 2 位)拆分的结果如图
KeyPrefixRegionSplitPolicy 拆分结果
如果你的所有数据都只有一两个前缀,那么 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)和强制拆分(forced splits)。

4.1.2、Region 的预拆分

预拆分(pre-splitting)就是在建表的时候就定义好了拆分点的算法,所以叫预拆分。使用org.apache.hadoop.hbase.util.RegionSplitter 类来创建表,并传入拆分点算法就可以在建表的同时定义拆分点算法。

1)快速入门

我们要新建一张表,并且规定了该表的 Region 数量永远只有 10 个。在 Linux 下执行:

hbase org.apache.hadoop.hbase.util.RegionSplitter my_split_table HexStringSplit -c 10 -f mycf
  • my_split_table:我们指定要新建的表名
  • HexStringSplit:指定的拆分点算法为 HexStringSplit
  • -c:要拆分的 Region 数量
  • -f:要建立的列族名称

上面这 条命 令的 意 思就是 新建 一个 叫 my_split_table 的表, 并根据 HexStringSplit 拆分点算法预拆分为 10 个 Region,同时要建立的列族叫 mycf。建完后用 hbase shell 看一下结果。执行命令查出所有 10 个 Region 的信息:

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 是 new byte[ ] {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']

上述语句在 HBase shell 中执行,执行完成后,可以通过 HBase Web UI 中查看相关信息,如下图。
手动分区表的信息
预分区表详细分区信息
上面的手动分区是使用类似数组的形式指定的,除了这种方式外,还可以使用指定预分区文件的方式来操作。
(1)准备文件 splits.txt
(2)创建预分区表

create 'students','baseinfo',SPLITS_FILE => '/home/hadoop/data/splits.txt'

(3)通过 WebUI,查看分区结果
使用文件分区结果图

4)Region 的强制拆分

除了预拆分和自动拆分以外,有时候可以对运行了一段时间的 Region 进行强制地手动拆分(forced splits)。方法是调用 hbase shell 的 split 方法,比如:对前面的 students 表中的 region 进行强制拆分。

split '1bb4e6fef4002ad49946a6b13c0391a2','b'

这个就是把 students 表中 1bb4e6fef4002ad49946a6b13c0391a2 这个 Region 从新的拆分点’b’处拆成 2 个 Region
强制拆分 Region
split 方法的调用方式:

➢ ssplit ‘tableName’
➢ split ‘namespace:tableName’
➢ split ‘regionName’ # format: ‘tableName,startKey,id’
➢ split ‘tableName’, ‘splitKey’
➢ split ‘regionName’, ‘splitKey’

5)推荐方案
一开始可以先定义拆分点,但是当数据开始工作起来后会出现热点不均的情况,所以推荐的方法是:

(1)用预拆分导入初始数据

(2)然后用自动拆分来让 HBase 来自动管理 Region

建议:不要关闭自动拆分。

6)总结

Region 的拆分对性能的影响还是很大的,默认的策略已经适用于多数情况。如果要调整,尽量不要调整到特别不适合你的策略,比如设置成 KeyPrefixRegionSplitPolicy,然后还用时间戳来做 rowkey。 一种策略的选择要看多方面因素,有可能你的集群同时适合多种策略,这样就要看哪种策略效果最好了。如果无法计算出来,就一个一个地尝试过去,用实践来检验真理。

4.1.3、Region 的合并

Region 可以被拆分,也可以被合并。不过 Region 的合并(merge)并不是为了性能考虑的,而更多地是出于维护的目的被创造出来的。

1)通过 Merge 类合并 Region

合并通过使用 org.apache.hadoop.hbase.util.Merge 类来实现,具体做法如下。
举个例子,比如我想把以下两个 Region 合并:
原始表的 Region 列表图

students,,1576734174477.0d9f2bedc502b84929196eefc60a5130. 
students,aaaa,1576735993384.82fe8c88c99d789dcc424cd18daaea30.

就需要在 Linux shell 下(不需要进入 hbase shell)执行以下命令:

hbase org.apache.hadoop.hbase.util.Merge students 
students,,1576734174477.0d9f2bedc502b84929196eefc60a5130. 
students,aaaa,1576735993384.82fe8c88c99d789dcc424cd18daaea30.

注意:RegionName 的.符号要带上。

在一大串的输出之后,用 Web UI 看下信息,发现没有合并,这是咋回事呢?这是因为该操作先把集群给下线了才行,所以我们先把 HMaster 和所有的 HRegionServer 全部都停掉,再执行就可以了。不过每次 merge 都要关闭整个 HBase 这也太麻烦了,好在后来 HBase 又增加了 online_merge。通过 Merge 类来合并叫冷合并,oneline_merge 叫热合并。

2)online_merge(热合并)

hbase shell 提供了一个命令叫 online_merge,通过这个方法可以进行热合并(online_merge)

online_merge 的传参是 Region 的 hash 值,Region 的 hash 值就是 Region 名最后那段在两个“.”号之间的字符串

(1)Region 的名字叫students,,1576734174477.0d9f2bedc502b84929196eefc60a5130. 那么它的哈希值就是0d9f2bedc502b84929196eefc60a5130。在 hbase shell(这回要进入 hbase shell 了)中执行以下命令:

merge_region 
'0d9f2bedc502b84929196eefc60a5130','82fe8c88c99d789dcc424cd18daaea30'

执行完了之后再去看 Web UI,就会看到这两个 Region 被合并成一个 Region 了。如图所示。
热合并 Region 列表图

4.2、HFile 的合并

4.2.1、为什么要有 HFile 的合并

我们都知道 HBase 是一个可以随机读写的数据库,而它所基于的持久化层 HDFS 却是要么新增,要么整个删除,不能修改的系统。那 HBase 怎么实现我们的增删查改的?真实的情况是这样的:HBase 是一种 Log-Structured Merge Tree 架构模式,HBase 几乎总是在做新增操作。当你新增一个单元格的时候,HBase 在 HDFS 上新增一条数据。当你修改一个单元格的时候,HBase 在 HDFS 又新增一条数据,只是版本号比之前那个大(或者你自己定义)。 当你删除一个单元格的时候,HBase 还是新增一条数据!只是这条数据没有 value,类型为 DELETE,这条数据叫墓碑标记 (Tombstone)。真正的删除发生在什么时候,由于数据库在使用过程中积累了很多增删查改操作,数据的连续性 和顺序性必然会被破坏。为了提升性能,HBase 每间隔一段时间都会进行一次合并(Compaction),合并的对象为 HFile 文件。另外随着数据写入不断增多,Flush 次数也会不断增多,进而 HFile 数据文件就会越来越多。然而,太多数据文件会导致数据查询 IO 次数增多,因此 HBase 尝试着不断对这些文件进行合并。

合并分为两种 minor compaction 和 major compaction

  • Minor Compaction:将 Store 中多个 HFile 合并为一个 HFile。在这个过程中达到 TTL 的数据会被移除,但是被手动删除的数据不会被移除。这种合并触发频率较高。
  • Major Compaction:合并 Store 中的所有 HFile 为一个 HFile。在这个过程中被手动删除的数据会被真正地移除。同时被删除的还有单元格内超过 MaxVersions 的版本数据。这种合并触发频率较低,默认为 7 天一次。不过由于 Major Compaction 消耗的性能较大,你不会想让它发生在业务高峰期,建议手动控制 MajorCompaction 的时机。

注意:Major Compaction 是把一个 Store 中的 HFile 合并为一个 HFile。并不是把一个 Region 中的所有 HFile 合并成一个文件。

4.2.2、Compaction 执行时间

触发 Compaction 的时机有以下几种:

  • 通过 CompactionChecker 线程来定时检查是否需要执行 compaction(RegionServer 启动时在 initializeThreads() 中初始化),每隔 10000 秒(可配置)检查一次
  • 每当 RegionServer 发生一次 Memstore flush 操作之后也会进行检查是否需要进行 Compaction 操作
  • 手动触发,执行命令 major_compact 、 compact

4.2.3、Compaction 相关控制参数

1)Minor Compaction

属性值默认值含义
hbase.hstore.compaction.max10表示一次 minor compaction 中最多选取10个 store file
hbase.hstore.compaction.min3表示至少需要三个满足条件的 store file 时,minor compaction 才会启动
hbase.hstore.compaction.min.size表示文件大小小于该值的store file 一定会加入到minor compaction 的 store file 中
hbase.hstore.compaction.max.size表示文件大小大于该值的StoreFile,一定会被 minor compaction 排除
hbase.hstore.compaction.ratio1.2将 store file 按照文件年龄排序(older to younger),minor compaction 总是从older store file 开始选择

将 StoreFile 按照文件年龄排序,minor compaction 总是从 older store file 开始选择,计算公式:该文件<(所有文件大小总和-该文件大小)*比例因子。也就是说如果该文件的 size 小于后面 hbase.hstore.compaction.max 个 store file size 之和乘以 ratio 的值,那么该 store file 将加入到 minor compaction 中。如果满足 minor compaction 条件的文件数量大于 hbase.hstore.compaction.min,才会启动。hbase.hstore.compaction.min.size 和 hbase.hstore.compaction.max.size 参数用于控制特殊大小的文件直接判断是否加入 minor compaction。

如果该文件大小小于最小合并大小(minCompactSize),则连上面那个公式都不需要套用,直接进入待合并列表。最小合并大小的配置项 :hbase.hstore.compaction.min.size 。如果没设定该配置项,则使用 hbase.hregion.memstore.flush.size。被挑选的文件必须能通过以上提到的筛选条件,并且组合内含有的文件数必须大于 hbase.hstore.compaction.min,小于hbase.hstore.compaction.max。文件太少了没必要合并,还浪费资源;文件太多了太消耗资源,怕机器受不了。

上面的选择方式,会形成多个满足条件的 StoreFile 组合,然后再比较哪个文件组合包含的文件更多,就合并哪个组合。如果出现平局,就挑选那个文件尺寸总和更小的组合。

2)Major Compaction

hbase.hregion.majorcompactionmajorcompacttion 发生的周期,单位是毫秒,默认值是 7 天

注意:虽然有以上机制控制 Major Compaction 的发生时机,但是由于 Major Compaction 时对系统的压力是非常大的,所以建议关闭自动 Major Compaction(hbase.hregion.majorcompaction=0),采用手动触发的方式,定期进行 Major Compaction。

手动 Major Compaction 命令为:major_compact

用法:

Examples:
Compact all regions in a table:
hbase> major_compact 't1'
hbase> major_compact 'ns1:t1'
Compact an entire region:
hbase> major_compact 'r1'
Compact a single column family within a region:
hbase> major_compact 'r1', 'c1'
Compact a single column family within a table:
hbase> major_compact 't1', 'c1'

五、HBase 优化

5.1、高可用

在 HBase 中 HMaster 负责监控 RegionServer 的生命周期,均衡 RegionServer 的负载,如果 HMaster 挂掉了,那么整个 HBase 集群将陷入不健康的状态,并且此时的工作状态并不会维持太久。所以 HBase 支持对 HMaster 的高可用配置。

(1)关闭 HBase 集群

stop-hbase.sh

(2)在 conf 目录下创建 backup-masters 文件

touch hbase/conf/backup-masters

(3)在 backup-masters 文件中配置高可用 HMaster 节点

echo hostname > hbase/conf/backup-masters

(4)将整个 conf 目录 scp 到其他节点

scp -r /opt/hbase/conf/ root@hadoop:/opt/hbase/

(5)启动 HBase 并打开页面测试查看,如图所示

http://hadooo102:60010

HBase 高可用配置结果图

5.2、RowKey 设计

一条数据的唯一标识就是 rowkey,那么这条数据存储于哪个分区,取决于 rowkey 处于哪个一个预分区的区间内,设计 rowkey 的主要目的,就是让数据均匀的分布于所有的 region 中,在一定程度上防止数据倾斜(数据热点)。下面 rowkey 常用的设计方案。

(1)生成随机数、hash、散列值

//原本 rowKey 为 1001 的,SHA1 后变成:
dd01903921ea24941c26a48f2cec24e0bb0e8cc7
//原本 rowKey 为 3001 的,SHA1 后变成:
49042c54de64a1e9bf0b33e00245660ef92dc7bd
//原本 rowKey 为 5001 的,SHA1 后变成:
7b61dec07e02c188790670af43e717f0f46e8913
//在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的 rowKey来 Hash 后作为每个分区的临界值

(2)字符串反转

20170524000001 转成 10000042507102
20170524000002 转成 20000042507102

这样也可以在一定程度上散列逐步 put 进来的数据

(3)字符串拼接

20170524000001_a12e
20170524000001_93i7

5.3、内存优化

HBase 操作过程中需要大量的内存开销,毕竟 Table 是可以缓存在内存中的,一般会分配整个可用内存的 70%给 HBase 的 Java 堆。但是不建议分配非常大的堆内存,因为 GC 过程持续太久会导致 RegionServer 处于长期不可用状态。

5.4、基础优化

5.4.1、允许在 HDFS 的文件中追加内容

hdfs-site.xml、hbase-site.xml
属性:dfs.support.append

解释:开启 HDFS 追加同步,可以优秀的配合 HBase 的数据同步和持久化。Hadoop2.0 默认值为 true

5.4.2、优化 DataNode 允许的最大文件打开数

hdfs-site.xml
属性:dfs.datanode.max.transfer.threads

解释:HBase 一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为 4096 或者更高。默认值:4096。该操作前提是 Linux 的文件最大数已经设置完成

5.4.3、优化延迟高的数据操作的等待时间

hdfs-site.xml
属性:dfs.image.transfer.timeout

解释:如果对于某一次数据操作来讲,延迟非常高,socket 需要等待更长的时间,建议把该值设置为更大的值(默认 60000 毫秒),以确保 socket 不会被 timeout 掉

5.4.4、优化数据的写入效率

mapred-site.xml
mapreduce.map.output.compress
mapreduce.map.output.compress.codec

解释:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为 true ,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec 或者其他压缩方式

5.4.5、设置 RPC 监听数量

hbase-site.xml
属性:hbase.regionserver.handler.count

解释:默认值为 30,用于指定 RPC 监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

5.4.6、优化 HStore 文件大小

hbase-site.xml
属性:hbase.hregion.max.filesize

解释:默认值 10737418240(10GB),如果需要运行 HBase 的 MR 任务,可以减小此值,因为一个 region 对应一个 map 任务,如果单个 region 过大,会导致 map 任务执行时间过长。该值的意思就是,如果 HFile 的大小达到这个数值,则这个 region 会被切分为两个 Hfile

5.4.7、优化 hbase 客户端缓存

客户端配置
属性:hbase.client.write.buffer

解释:用于指定 HBase 客户端缓存,增大该值可以减少 RPC 调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少 RPC 次数的目的

5.4.8、指定 scan.next 扫描 HBase 所获取的行数

客户端配置
属性:hbase.client.scanner.caching

解释:用于指定 scan.next 方法获取的默认行数,值越大,消耗内存越大

5.4.9、flush、compact、split 机制

当 MemStore 达到阈值,将 Memstore 中的数据 Flush 进 Storefile;compact机制则是把 flush 出来的小文件合并成大的 Storefile 文件。split 则是当 Region 达到阈值,会把过大的 Region 一分为二

涉及属性:128M 就是 Memstore 的默认阈值

hbase.hregion.memstore.flush.size:134217728

即:这个参数的作用是当单个 HRegion 内所有的 Memstore 大小总和超过指定值时,flush 该 HRegion 的所有 memstore。RegionServer 的 flush 是通过将请求添加一个队列,模拟生产消费模型来异步处理的。那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发 OOM

hbase.regionserver.global.memstore.size:默认整个堆大小的 40%

regionServer 的全局 memstore 的大小,超过该大小会触发 flush 到磁盘的操作,默认是堆大小的 40%,而且 regionserver 级别的 flush 会阻塞客户端读写

hbase.regionserver.global.memstore.size.lower.limit:默认堆大小 * 0.4 * 0.95

有时候集群的“写负载”非常高,写入量一直超过 flush 的量,这时,我们就希望 MemStore 不要超过一定的安全设置。在这种情况下,写操作就要被阻塞一直到 MemStore 恢复到一个“可管理”的大小, 这个大小就是默认值是堆大小 * 0.4 * 0.95,也就是当 HRegionserver 级别的 flush 操作发送后,会阻塞客户端写,一直阻塞到整个 HRegionserver 级别的 MemStore 的大小为 堆大小 * 0.4 * 0.95 为 止

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
⼤数据全样⽽⾮抽样原理_⼀⽂带你了解什么是⼤数据 科技是第⼀⽣产⼒。进⼊世纪的第⼀个20年以来,⼈们越来越多地将关注的领域集中在⼤数据、⼈⼯智能、云计算、物联⽹、移动互联 ⽹、GIS、AR与VR、5G、区块链、数字化与智慧化等,尤其为最近的风⼝"ABC"。笔者也⼀直在关注这⽅⾯的研究与学习,最近趁着 有时间,将把⼀些科普性的概念写出来,以帮助关注该领域的⼈更好地理解这⼏个热点领域的知识,本次分享将介绍⼀下⼤数据的产⽣、概 念、影响以及技术⽀撑。 1、Why.为什么会产⽣⼤数据? 我们遇到⼀个概念或者⼀个问题的思路就是去问"为什么?"同样,提起到⼤数据,我们会想,之前为什么不是⼤数据时代(DT),为什么现 在是?这⾥我分享⼏点我的看法。⼀个⽅⾯,产⽣⼤数据的⼀个基础是我们的计算存储技术发⽣了⾰命性的变化,从数据⼤⼩的单位来看, 数据⼤⼩的单位可以分为Bit 现在我们称为⼤数据,我相信单位⾄少是PB级别的,因为TB已经在我们的⽣活中很常见。存储技术的发展使得计算机的存储能⼒得到了飞 速的进步,我们不会再像以前那样为了节省空间会清理掉部分的数据,⽽是基本上在那个地⽅放着。基于⾜够性价⽐、⾜够低成本的存储技 术,这使得数据变得"⼤"有了最基本的⽀撑。另⼀个⽅⾯,数据产⽣的主体与范围发⽣了重要的变化,之前数据的产⽣只靠计算⼯作⼈员 与运营⼈员的输⼊,⽽现在随着⾃媒体的发展,⼈⼈都是数据的⽣产者,数据的量呈指数增长,最近⼜随着物联⽹、感知监测设备、GIS等 技术的发展,不仅⼈是数据产⽣的组成部分,其他⾮⼈物体、地⾯信息、空⽓检测信息都能作为数据产⽣源,并且⽆时⽆刻都在产⽣数据。 总结来说,过去我们对数据做"减法",现在我们不减,⽽且持续在做"加法"。 2、what,⼤数据的概念及特征 ⼤数据主要体现在⼀个"⼤"⼤字上⾯,谈及⼤数据,我们经常⽤"4V"来描述,第⼀,Volume,即容量⼤、体积⼤,正如前⾯所说,⼤ 数据的单位应该以PB起步,企业甚⾄可以到EB。第⼆个,Velocity,即⾼速,速率快,⼤数据产⽣的速度是很快的,有个知名的说法,即⼤ 数摩尔定律,据测算,现在每两年数据就会翻⼀倍,这个增长量是及其可怕的。第三个,Variety多样性,之前产⽣的数据多半是结构化的 数据,⽐如多是数值型,⽽现在越来越多产⽣图⽚,⾳频,视频,⽹页等半结构化的数据,数据类型的多样性也是⼤数据的重要体现。第四 个,Value,即有价值但⼜密度低,⼤数据的背后藏着丰富的商业价值,但是因为海量数据,真正有价值的数据却很难挖掘,数据的价值密度 很低。 3、⼤数据的影响 ⼤数据的影响可以主要概括为,全样⽽⾮抽样,效率⽽⾮准确,相关⽽⾮推断。以前我们获得数据很难,我们会抽样作分析,现在随着⼤数 据的⽀撑,我们做全样研究很简洁⽅便。基于之前的抽样研究,我们往往追求模型的准确性,⽽忽略了效率,⼤数据的时代,分秒必争,在 这⼀秒,数据是有价值的,⽽到下⼀秒,数据就会失去价值,所以⼤数据时代,效率是王道。最后我们不会再关注特征与特征之间,或者说 变量与变量之间的因果推断,⽽是发现他们相关即可,这在智能推送过程中显得尤为重要。 4、⼤数据的技术⽀撑 ⼤数据的技术⽀撑主要体现在四个⽅⾯,主要是数据采集,数据存储与管理、数据处理与分析、数据隐私与安全。其中最为核⼼的是存储与 处理,两者都采⽤分布式原理,即分布式存储,主要有HDFS,NoSQL,NewSQL;分布式处理,即MapReduce。数据的存储利⽤分布式⽂ 件系统,云数据库,实现对结构化、半结构化和⾮结构化海量数据进⾏存储。⽽数据处理利⽤分布式并⾏编程模型,集合机器学习与数据挖 掘算法,实现对海量数据的处理与分析,并对分析结构进⾏可视化呈现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值