我是靠谱客的博主 高兴钻石,最近开发中收集的这篇文章主要介绍HFile的合并,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一.之前说到了BlockBache的优化以及MemStore的优化
这篇文章主要介绍一下HFIle的合并
我们首先要明白的是,为什么HFile要进行合并?
1.StoreFile是HFile的抽象,MemStore的每一次刷写都会产生一个HFile,如果HFile数量过多会产生什么问题?读取速度下降,因为读取数据涉及到一个操作:寻址
如果是传统硬盘那就是磁头的移动。
寻址,这是一个很慢的动作。当HFile一多,你每次读取数据的时候寻址的动作就多了,效率就低了。所以为了防止寻址的动作过多,我们要适当地减少碎片文件,所以需要进行合并这些HFile文件
问题是:如果有很多的HFile文件,应该合并那些文件呢?

接下来说一下合并的策略

二.合并策略

2.1.Minor Compaction和Major Compaction

这里的合并分为两种类型:

minor Compaction:这个是用得比较频繁,主要是移除一些TTL到期的文件,对于已经删除的带有墓碑标记的不能被移除。
major Compaction :用得不是很频繁,默认是七天触发一次。主要删除之前已经删除的数据,以及版本号超过当前版本的数据。触发时消耗性能比较到,最好手动触发。
major Compactio把一个Store的Hfile合并为一个HFile

2.2. 0.96版本之前的合并策略

在Hbase0.96之前的版本,Minor Compaction 的策略是RatioBasedCompactionPolicy
0.96版本之后才出现了很多中策略
RatioBasedCompactionPolicy其实很简单,主要使用下面条件:

该文件大小<比它更新的所有文件大小总和 * hbase.store.copaction.ratio

如果满足该条件,则把该文件以及比它更新的所有文件合并成以一个新的HFile

对于这种策略,一般情况下,所有的文件如果按照越新越小的顺序排列是没有任何问题的,关键是,能够和我们详细的一样吗?答案是肯定的。我们知道有很多种情况可以导致MemStore的刷写,除了定期的刷写,以及我们要关闭这个Region时,MemeStore也是会被刷写,不管MemStore有多大。
因此在实际情况下,RatioBasedCompactionPolicy策略的效果极差,经常会导致大面积的合并,并且要知道,合并文件是不能写入数据的,从而影响IO。

2.3. 0.96版本之后的合并策略

2.2.1.ExploringCompactionPolicy

0.96版本之后的策略是ExploringCompactionPolicy 这个策略是对RatioBasedCompactionPolicy的改进,不在强调顺序性,比较灵活。并且会对每一个文件进行便利,符合条件的进入代合并列表
条件是:

该文件大小<(所有文件大小 - 该文件大小) * hbase.store.copaction.ratio

并且如果文件大小小于最小合并大小(minCompactSize),直接进入待合并列表

minCompactSize的配置是由hbase.hstore.compaction.min.size。如果没设定该配置项,则使用hbase.hregion.memstore.flush.size。

这个方法的核心是是以组合为计算单元多个文件进行组合

  • 被挑选的文件的组合文件数目必须大于hbase.hstore.compaction.min(默认3),小于
    hbase.hstore.compaction.max(默认5) 主要是因为如果文件数目太少,合并浪费资源,文件过多机器可能受不了

  • 挑选完组合后,比较哪个文件组合包含的文件更多,就合并哪个组合。如果出现平局,就挑选那个文件尺寸总和更小的组合。

2.3.2.FIFOCompactionPolicy

这个策略是比较简单的,更为正确的说,不应该是一种合并算法。在HBase中Minor Compaction和MajorCompaction是一定会发生的,只是策略和频率不同而已。

  • FIFOCompactionPolicy策略主要合并(就是删除)TTL过期的数据,没有过期的直接跳过,对于IO,CPU没有压力
  • 如果表没有设置TTL或者TTL=FOREVER,以及你设置了MIN_VERSIONS>0,那么就不能够使用该策略,MIN_VERSIONS主要是约束TTL的,当版本达到TTL需要删除的时候,会看一下你的单元格的版本数是否==MIN_VERSIONS,如果是,则取消删除操作,TTL失效
2.3.3.DateTieredCompactionPolicy

对于这个策略,我们需要关注策略名称第一个单词Date,说明一定和时间有关系。
此策略不会把问价年至分为新的或者旧的,新旧和读取频率有关。
以下是配置参数:

1.时间窗口,默认是6小时。如果是默认的,意思是,从现在开始到再过6小时的HFile都会在一个时间窗口里,即最新的时间窗口里

hbase.hstore.compaction.date.tiered.base.window.millis

2.层次增长倍数,分层的时候,越老的时间窗口越宽

hbase.hstore.compaction.date.tiered.windows.per.tier
  • 如果基本时间窗口是1h,层次增长倍数是2,那么时间窗口的范围就是now… 1-3,3-7,7-15…

  • 如果在同一时间窗口达到最小合并数hbase.hstore.compaction.min则会进行合并,是根据hbase.hstore.compaction.date.tiered.window.policy进行合并。默认是 ExploringCompactionPolicy
    3.最老层次时间,如果文件比较老,超过了此值,那么就不会合并了,如果Store的HFile的文件过于老,并且没有超过TTL,那么将不会发生Major Compaction,永远不会被删除

hbase.hstore.compaction.date.tiered.max.tier.age.millis:

适用场景:

  • 经常读写最近的数据系统
  • 适用于基本不删除的系统,由于该策略可能不会引发Major Compaction
  • 如果数据按照时间排序,或者修改频率极低也是可以的
  • 经常改动,甚至老的数据都会改,则不适用
2.3.4.StripeCompactionPolicy

此策略是借鉴levelDB的compaction策略。
它把一个Store的数据分为很多层,开始从MemStore的数据是到level 0,随着时间推移,level 0 大小达到阈值,则会引发一次合并,根据KeyValue把level 0 的数据插入得到level 0 中去。而level 1的块是根
据键位范围(KeyRange)来划分的。如果我们根据rowkey的首字母来划分键位范围。如果level 1大小达到阈值,也是一样会引发合并,数据往level 2合并等等。每一层的大小是上一层的10倍。

仔细一想,如果在Hbase实现结构过于复杂,划得块过多,导致compaction次数增多降低了IO使用率。
因此在Hbase level 1~N的level统一为Strips层
好处:

  • 通过增加level 0层,相当于i一层缓冲使合并更为缓和,稳定

  • 按照键位划分Strips,提高查询的速度的稳定性。当你执行scan的时候,跨越的HFile数量保持在了一个比较稳定的数值

  • 之前说到上一个策略,有的过于老的数据永远不能够被删除,此策略可以避免这个情况,Major Compaction可以分Strips进行,比如a-f这个strip就可以独立执行MajorCompaction而不牵涉g-m。

  • 大部分场景下写的性能都更糟,可能是因为写的时候发生了很多
    次的L0区合并。
    读的性能都普遍会快一些。

  • L0层的文件越多,写的性能越高,但是让读操作更慢了。
    在没有删除操作(no dd就是no drop-delete的缩写)的前提
    下,12个stripes似乎可以提升写的性能。

  • 虽然12个Stripes可以提升读性能,但是3个Stripes也得到了相同的读性能,所以需要再验证。
    适合场景:

  • Region要够大:这种策略实际上就是把Region给细分成一个个
    Stripe。Stripe可以看做是小Region,我们可以管它叫subregion。所以如果Region不大,没必要用Stripe策略。小Region
    用Stripe反而增加IO负担。多大才算大?建议Region小于2G不要使用StripeCompactionPolicy。

  • Rowkey要具有统一格式,能够均匀分布。由于要划分KeyRange,
    所以key的分布必须得均匀,比如用26个字母打头来命名rowkey,就可以保证数据的均匀分布。如果使用timestamp来做rowkey,那么数据就没法均匀分布了,肯定就不适合使用这个策略。

三.Hbase合并流程:

3.1获取 选哟合并的HFile列表

获取列表时候,不会获取带有锁的列表,在这里,锁分为读锁和写锁当Hbase进行一下操作时候会上锁:

用户正在scan查询:上Region读锁(region read lock)。
Region正在切分(split):此时Region会先关闭,然后上 Region写锁(region write lock)。
Region关闭:上Region写锁(region write lock)。
Region批量导入:上Region写锁(region write lock)

3.2.由列表创建出StoreFileScanner

HRegion会创建出一个Scanner,用这个Scanner来读取本次要合并
的所有StoreFile上的数据

3.3.从HFile读出数据,刚到临时目录/tmp

HBase会在临时目录中创建新的HFile,并使用之前建立的Scanner
从旧HFile上读取数据,放入新HFile。以下两种数据不会被读取出来:

  • 如果数据过期了(达到TTL所规定的时间),那么这些数据不会
    被读取出来。
  • 如果是majorCompaction,那么数据带了墓碑标记也不会被读取出来。
3.4.合并后的HFile替换原来的HFile

最后用临时文件夹内合并后的新HFile来替换掉之前的那些HFile文
件。过期的数据由于没有被读取出来,所以就永远地消失了。如果本次
合并是Major Compaction,那么带有墓碑标记的文件也因为没有被读取
出来,就真正地被删除掉了。

4.Major Compaction

最后重点说一下Major Compaction
Major Compaction和Minor Compaction的最大的优势在于,Major Compaction是可以真正地删除数据的。即带有墓碑标记的数据。Major Compaction没有出来之前是真的做不到把数据真正删除。
现在的用户删除操作底层是有新增实现,删除也是属于新增的一种

  • 用户如果新增一条数据,则会在HFile新一条KeyValue,类型为PUT
  • 用户如果删除一条数据和新增一样,只不过类型是DELETE,和Value值为空。

其实在我们scan的是和为什么没有出现带有墓碑标记的数据,其Scan指针是把所有的HFile都扫过一遍,他清楚每一条数据是否带有墓碑标记,只不过返回给用户的时候,不把带有墓碑标记的数据返回给用户。上我们可以通过RAW=>true参数来Scan来查看

最后

以上就是高兴钻石为你收集整理的HFile的合并的全部内容,希望文章能够帮你解决HFile的合并所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部