HBase 文件合并
HBase
在存储时, 使用了LSM
树来进行数据存储, 会定期将文件进行合并, 以提升数据的查询效率, LSM
树都是这么处理的. 那么到这里就有一个问题了, HBase
在进行文件合并的时候, 势必会占用大量 IO, 难道不会对正常的业务产生影响么? 抱着这个疑问, 我去找了找HBase
文件合并的方式.
在HBase
中, 负责文件合并的模块叫做: 'Compaction'. 分别看了看合并的类型、触发条件、执行过程、优缺点等, 算是简单了解了一下吧.
合并类型
根据文件合并的规模, 可以分为两种.
Minor
规模较小的合并, 选取相邻的几个小的 HFile, 合并成一个更大的 HFile.
Minor
合并的时候, 将多个小文件进行合并, 那么在执行之前, 需要进行待合并文件的选择, 选取的文件一般来说不能太大, 同时也不能太多, 否则会占用过多系统资源. 最好的情况是把文件较小查询较多的文件进行合并, 这样才能达到最好的效果.
Major
将一个 store
中的所有HFile 合并为一个大的 HFile.
这里问了, store
是是什么呢? 在HBase
中, 根据row key
, 会将表水平切分为多个 region
, 在每个region
中, 又会根据列族对表进行垂直切分为多个store
.
这里多说一句, 在每个store
中, 并不是所有数据都存在HFile
中, 其中部分数据在内存中, 还没有进行落盘, 所以每个store
由两部分组成: 1. 内存中的有序结构 2. 磁盘中的HFile
同时, 在进行所有文件合并的时候, 还会进行数据清理, 以减少文件占用空间, 清理内容包括:
- 被删除的数据
- TTL过期的数据
- 版本号过期的数据
所以可以通过执行全文件合并来进行存储空间的优化.
优缺点
文件合并也就意味着需要进行文件的读写以及生成等操作, 势必会占用系统资源及网络带宽(读写要经过 HDFS), 尤其是Major
全文件合并也意味着会占用大量系统资源, 所以在合并过程中, 会对上层业务造成一定的影响.
而合并文件的优点也很明显:
- 优化查询速度. 毕竟查询的时候, 读取1个文件和读取100个文件的速度自然不一样.
- 减少文件体积. 可以减少文件占用磁盘空间
- 提高文件的本地化率. 在进行文件合并的时候, 合并后的文件先放到本地, 然后再更新的 HDFS 上, 也就意味着查询可以直接读取本地文件. 极端情况下,
Major
后可以达到100%的本地化. 就剩一个文件了嘛
其中优化查询速度是合并文件最主要的目的了.
触发条件
文件合并虽好, 但也不能一直进行合并, 否则占用太多资源, 根本吃不住来自业务的压力. 那么什么时候会触发文件合并呢?
1. 文件落盘
store
中的内存数据进行落盘的时候, 会触发文件合并检查, 当store
下的HFile
数量超过 n
时, 会触发Minor
.
其中数量n
由配置: hbase.hstore.compaction.min
2. 周期性检查
有一个线程在后台周期性的进行检查, 会进行一系列检查, 比如文件数量、最早文件的更新时间等. 当符合条件的时候, 就会触发文件合并.
3. 手动触发
可以在业务低峰期手动触发Major
来进行优化.
合并流程
文件合并一般分为以下几步:
- 分别读取待合并文件的数据, 进行归并处理, 写到临时文件中
- 将临时文件挪到
store
的数据目录中 - 将合并信息存到 HLog 中, 并推送文件到 HDFS
- 将合并前的小文件删除
其中在步骤1和2出错的话, 不用任何处理, 因为数据还没有落盘, 下一次重新合并即可. 在后面出错, 可以根据HLog
继续执行后面的任务.
你要是问我知道这玩意有什么用的话, 我想了想, 唯一的用处就是, 下次如果遇到HBase
占用资源突然剧增的时候, 可以多一个查找的方向吧.