前言
本篇是 HBase 相关内容的第四篇,上一篇我们整理了一下 HBase 的读写过程,这一篇继续来略微的探究一下 HBase 保存性能的关键 HFile Compaction 和 Region Split,文中如有错误欢迎指正,共同进步!
HFile Compaction
HFile Compaction 的作用
上一篇博客中有提到,HBase 的 MemStore 在满足一定的条件下会将内存中的数据刷写成 HFile,而一个 MemStore 刷写就会形成一个 HFile,随着时间的推移同一个 Store 下的 HFile 会越来越多这样会影响查询的效率,此外在 HBase 中数据无论是修改还是删除实际上都是新增一条数据而原来的数据并没有真正的被删除因此也会占据存储空间影响查询性能。
为了解决上述情况 Hbase 中使用了 Compaction 来解决,其作用主要作用有两个:
- 将多个小的 HFile 合并成一个更大的 HFile 以增加查询性能
- 在合并过程中对过期的数据(超过TTL,被删除,超过最大版本号)进行真正的删除
HFile Compaction 的分类
在 Hbase 中 Compaction 有俩种分别是 Minor Compaction 和 Major Compaction :
- Minor Compaction :会将邻近的若干个 HFile 合并,在合并过程中会清理 TTL 的数据,但不会清理超过最大版本号的数据以及被删除的数据
- Major Compaction:会将一个 store 下的所有 HFile 进行合并,并且会清理掉过期的和被删除的数据,即在 Major Compaction 会删除全部需要删除的数据。值得注意的是,一般情况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此,生产环境下通常关闭自动触发Major Compaction功能,改为手动在业务低峰期触发。
Minor Compaction 和 Major Compaction 如下图:
HFile Compaction 的触发时机
HBase触发Compaction的条件有三种:MemStore Flush、CompactionChecker、手动触发。
-
MemStore Flush:
上文提到过 Compaction 的原因就是因为 MemStore Flush 导致生成了太多的 HFile,因此在每次 MemStore Flush 之后都会检查是否满足了 Minor compaction 或 Major compaction 的条件,如果满足就会进行 Compaction
-
CompactionChecker:
Hbase 会专门启动一个 CompactionChecker 线程来周期性的检查是否需要进行 compaction
-
手动触发:
通过HBase Shell、Master UI界面或者HBase API等任一种方式 执行 compact、major_compact等命令。
HFile Compaction 对于读写的影响
对于读性能的影响
Compaction 的目的是为了减少 HFile 以增加查询性能,换句话说 Compaction 是为了增加读性能或者说是为了稳定读性能,但是从 Compaction 的示意图中可以发现 Compaction 本质实际上是通过牺牲部分 IO (磁盘与网络) 来维持读性能的稳定,但是在每次 minor compaction 或者 major compaction 的时候 IO 资源都会一定程度上占用因此,读性能会在 compaction 期间略微降低,而在 compaction 后又回到一个稳定的水平,从下图可以看到图中会有许多毛刺这是因为当进行 compaction 时读性能就会短暂的降低,而在完成后又回到正常水平。
对于写性能的影响
在数据生成速度很快 HFile 不断快速生成的场景下,Hbase 因需要进行 compaction 操作从而限制写请求速度,在 HFile 超过 hbase.hstore.blockingStoreFiles
,默认为10 的情况下 flush 操作会被阻塞,阻塞时间由 hbase.hstore.blockingWaitTime
决定默认为 1.5 分钟,当在阻塞时间内 HFile 下降到配置值之下或超过阻塞时间则会停止阻塞写请求,这是为了在一定程度上控制写请求的速度但同时也影响了写请求的效率,在极端情况下阻塞的 flush 操作可能导致 HregionServer 级别的 flush 从而完全阻塞写请求。
有关与写入数据的另一个方面就是 compaction 操作会导致写入放大,从下图可以看到一次写入的数据,被多次反复读取与写入,会导致集群 IO 资源的浪费
Region Split
说完了 compaction 我们来说说另一个机制 region split,如果我们不设定预分区那么 Hbase 在创建表的时候默认只有一个 region,这种情况下随着时间的推移同一个 Region 中的数据会越来越多显然这样会让我们的查询效率降低,因此当一个 Region 的大小过大时 Hbase 会对其进行 split 操作将其切分
Split 有三种类型:
-
pre-splitting:
这种方式就是预分区,我们可以通过提前根据 rowkey 的特点预估 rowkey 的分布来设定分区从而减少热点或者说数据倾斜的问题,也能免去自动分区带来的 IO 开销
-
auto-splitting
自动分区,Hbase在某个 region 超过一定大小之后会对其进行切分,默认 Hbase 提供了 6 种 split 策略:
-
ConstantSizeRegionSplitPolicy
当region的最大一个store达到指定的阈值时触发split,这个阈值可以使用hbase.hregion.max.filesize设置(默认10G)。0.94版本前的默认切分策略。
-
IncreasingToUpperBoundRegionSplitPolicy
也是当region的最大一个store达到一个阈值时触发split,不过这个阈值不是固定的,而是根据regionServer管理的同属一张表的region个数有关:
a)、region个数为0或者大于100:maxFilesize的选取跟ConstantSizeRegionSplitPolicy一样;
b)、region个数在0~100之间:有一个initialSize,这个值由hbase.incresing.policy.initial.size配置;若没有配置这个值,则initialSize = 2 * MEMSTORE_FLUSHSIZE(table元数据);若table没有元数据或initialSize小于0,则initialSize = 2 * hbase.hregion.memstore.flush.size(默认128M)。拿到initialSize后,maxFilesize = min (initialSize * region个数的3次方, 10G)。
0.94 ~ 2.0版本默认的切分策略,这种策略下,表的region越少,split越频繁,当region数超过4之后的maxFilesize都是10G。
-
SteppingSplitPolicy
这是IncresingToUpperBoundRegionSplitPolicy的子类,重写了getSizeToCheck方法,当region个数为1时,maxFilesize = flushSize * 2,其他情况跟父类一样。
2.0版本后的默认切分策略,修改了1个region时的切分阈值,之前是128 * 1^3 = 128M,现在是128 * 2 * 1^3 = 256M。
-
KeyPrefixRegionSplitPolicy
这是IncresingToUpperBoundRegionSplitPolicy的子类,切分条件跟父类一样,修改了splitKey的选取,会根据rowkey的前缀对数据分组,将rowkey前缀相同的数据在split时分到相同的region中,前缀位数可以使用默认的,也可以使用table元数据KeyPrefixRegionSplitPolicy.prefix_length
-
DelimitedKeyPrefixRegionSplitPolicy
跟keyPrefixRegionSplitPolicy一样继承自IncresingToUpperBoundRegionSplitPolicy,切分条件不变,也是修改了splitKey的选取,会根据指定的分隔符截取rowkey前部分字符,将该部分字符相同的数据在split时分到同一个region,分隔符可以使用table元数据DelimitedKeyPrefixRegionSplitPolicy.delimiter设置。
-
DisableSplitPolicy
禁用region自动split。
-
-
force-splitting
通过 Hbase shell 或者 API 发送命令强制 region 进行切分
与 compaction 中的 major compaction 一样 region split 也会占用大量的集群资源,因此在生产环境中也可以将 auto-splitting 关闭从而在业务高峰期不影响性能,然后在业务空闲时进行手动分区来维护集群的查询性能。
结语
Hbase 的 compaction 和 split 就整理到这,但是这两个机制的相关内容远远不止于此它们是 Hbase 性能稳定的关键因此还有许多的细节有待深入,例如 split 和 compaction 的详细流程,因此读者可以查阅资料来进一步了解。
参考文献
https://blog.csdn.net/u011598442/article/details/90632702
https://www.cnblogs.com/cnblogs-syui/p/12566642.html
https://www.cnblogs.com/niurougan/p/3976519.html