HBase使用的存储结构为LSM树,它的优势是能大大提升写效率。同时由于这种特性在HBase中,它的存储会形成一个个的小文件HFile。当HFile文件数过多的时候,会导致读取效率降低,为了解决这个问题,HBase中引入了Compaction设计。(其实凡是使用LSM树作为存储结构的数据库基本都引入了类似功能)
Compaction的分类
Compaction分为Minor Compaction
和Major Compaction
,Minor Compaction是指选取部分小的、相邻的HFile,将它们合并成一个更大的HFile。Major Compaction是指将一个Store中所有的HFile合并成一个HFile,并且会清除其中的一些过期数据。
相比而言,Major Compaction持续时间会比较长。消耗的集群资源也比较大。
如下图所示,当集群写数据逐渐增多时候,读延迟也会随之增加。
如下图所示,经过Compaction后,延迟有如下变化。
Compaction的另一个重要作用是把数据都放在本地节点。也就是同一个Region的数据,尽量合并在同一个RegionServer上,减少读请求时,网络传输带来的性能损失。
Compaction的基本工作原理
合并的基本原理是先从要合并的文件中读取所有的K-V数据,然后把这些数据进行排序,再把结果写进一个新的HFile文件中,合并完成之后,将有新的HFile文件对外提供服务。
对于Compaction的工作流程可以分为以下四个步骤
- 触发
- 选取HFile
- 执行合并
触发
触发有三种情况,MemStore的Flush、后台线程周期性检查以及手动触发。
- MemStore的Flush:每次执行完f lush操作之后,都会对当前Store中的文件数进行判断,一旦Store中总文件数大于
hbase.hstore.compactionThreshold
,就会触发Compaction。 - 后台线程周期性检查: 总文件数大于
hbase.hstore.compactionThreshold
,一旦大于就会触发Compaction。 - 手动触发:手动触发的动机基本实在业务低峰期进行手动触发。
选取HFile
选取HFile进行合并,是整个Compaction流程的核心。通常有多种选取算法主要有两种Minor Compaction文件选择策略,一种是RatioBasedCompactionPolicy,另一种是ExploringCompactionPolicy
- RatioCompactionPolicy
设置Ratio,在高峰期ratio为1.2,非高峰期ratio为5。从老到新扫描所有候选文件,计算当前扫描到的文件大小,以及比它新的文件的所有文件总大小乘以ratio。如果前者小于后者,就进行选取。 - ExploringCompactionPolicy
该策略思路基本和RatioBasedCompactionPolicy相同,Ratio策略在找到一个合适的文件集合之后就停止扫描了,而Exploring策略会记录所有合适的文件集合,并在这些文件集合中寻找最优解。具体可参照文章. - StripeCompactionPolicy
- 用户自定义Policy
用户也可以通过特定接口实现自己的Compaction策略
执行合并
HBase实现中有一个专门的类CompactSplitThead负责接收Compaction请求和split请求,而且为了能够独立处理这些请求,这个类内部构造了多个线程池:largeCompactions、smallCompactions以及splits等。
选出待合并的HFile集合,再选出合适的处理线程,接下来执行合并流程。合并流程主要分为如下几步:
- 分别读出待合并HFile文件的KeyValue,进行归并排序处理,之后写到./tmp目录下的临时文件中。
- 将临时文件移动到对应Store的数据目录。
- 将Compaction的输入文件路径和输出文件路径封装为KV写入HLog日志,并打上Compaction标记,最后强制执行sync。
- 将对应Store数据目录下的Compaction输入文件全部删除。
优势和劣势
Compaction操作重写文件会带来很大的带宽压力以及短时间IO压力。它的核心操作是批量将大量小文件合并成大文件用以提高读取性能。
通常可以通过设置吞吐量下限参数hbase.hstore.compaction.throughput. lower.bound
和上限参数hbase.hstore.compaction.throughput.higher.bound
来自动调节系统的Compaction吞吐量。
也可以使用compactBwLimit
和numOfFilesDisableCompactLimit
来限制带宽,保证不会影响集群其他业务正常运行。