文章目录
概述
在HBase中数据被写入 WAL 和 MemStore 后就可以说数据已经被成功写入到 Hbase 了。MemStore 中的数据达到一定的阈值,会被 Flush 成 HDFS 中的 HFile 文件。但是随着 Flush 次数的不断增多,HFile 的文件数量也会不断增多。从多个 HFile 文件中读取记录,将导致更多的 IOPS,这会使得读取时延不断增大。
Compaction 可以将一些 HFile 文件合并成为较大的 HFile 文件,也可以把所有的 HFile 文件合并成为一个大的 HFile 文件,这个过程可以理解为:将多个 HFile 的 “交错无序状态”,变成单个 HFile 的“有序状态”,降低读取时延。
小范围的 HFile 文件合并,称之为 Minor Compaction,一个列族中将所有的 HFile 文件合并,称之为 Major Compaction。除了文件合并范围的不同之外,Major Compaction 还会清理一些 TTL 过期/版本过旧以及被标记删除的数据。
Flush
MemStore 级别限制
当 Region 中任意一个 MemStore 的大小达到了上限(hbase.hregion.memstore.flush.size,默认128MB),会触发 MemStore 刷写。
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>134217728</value>
</property>
Region 级别限制
当 Region 中所有 MemStore 的大小总和达到了上限,
hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size
默认 4* 128M = 512M,会触发 memstore 刷写。
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>134217728</value>
</property>
<property>
<name>hbase.hregion.memstore.block.multiplier</name>
<value>4</value>
</property>
RegionServer 级别限制
当一个 RegionServer 中所有 MemStore 的大小总和超过低水位阈值:
hbase.regionserver.global.memstore.size.lower.limit*hbase.regionserver.global.memstore.size
(前者默认值0.95),RegionServer 开始强制刷新;
- 先 Flush MemStore 中最大的Region,再执行大的,依次执行;
- 如写入速度大于 Flush 写出的速度,导致总 MemStore 大小超过高水位阈值
hbase.regionserver.global.memstore.size
(默认为 JVM 内存的 40%),此时 RegionServer 会阻塞更新并强制执行 Flush,直到总 MemStore 大小低于低水位阈值。(为什么会发生RegionTooBusyException?)
<property>
<name>hbase.regionserver.global.memstore.size.lower.limit</name>
<value>0.95</value>
</property>
<property>
<name>hbase.regionserver.global.memstore.size</name>
<value>0.4</value>
</property>
HLog 数量上限
当一个 RegionServer 中 HLog 数量达到上限(可通过参数hbase.regionserver.maxlogs配置)时,系统会选取最早的一个 HLog 对应的一个或多个 Region 进行 Flush。
手动 Flush
用户可以通过shell命令flush ‘tablename’
或者flush ‘region name’
分别对一个表或者一个Region进行flush。
Flush 的流程
为了减少 Flush 过程对读写的影响,将整个 Flush 过程分为三个阶段:
prepare 阶段
:遍历当前 Region 中所有的 MemStore ,将 MemStore 中当前数据集 CellSkpiListSet 做一个快照 snapshot;然后再新建一个 CellSkipListSet。后期写入的数据都会写入新的 CellSkipListSet 中。prepare 阶段需要加一把 updataLock 对写请求阻塞,结束之后会释放该锁。因为此阶段没有任何费时操作,因此锁持有时间很短。flush 阶段
:遍历所有 MemStore,将 prepare 阶段生成的 snapshot 持久化为临时文件,临时文件会统一放到目录.tmp下。这个过程因为涉及到磁盘 IO 操作,因此相对耗时。commit 阶段
:遍历所有 MemStore,将 flush 阶段生成的临时文件移动到指定的 ColumnFamily 目录下,针对 HFile 生成对应的 StoreFile 和 Reader,把 StoreFile 添加到 HStore 的 storefiles 列表中,最后再清空 prepare 阶段生成的 snapshot快照。
Compact 合并机制
HBase 为了防止小文件过多,以保证查询效率,在必要的时候会将一些小的 StroreFile 合并成相对较大的 StoreFile ,这个过程就称之为 compaction。HBase中主要存在两种类型的 compaction 合并:
- minor compaction 小合并
- major compacton 大合并
minor compaction(小合并)
将 Store 中多个 HFile 合并为一个相对较大的 HFile 过程中会选取一些小的、相邻的 StoreFile 将他们合并成一个更大的 StoreFile,对于超过 TTL 的数据、更新的数据、删除的数据仅仅只是做了标记,并没有进行屋里删除。一次 minor compaction 的结果是更少并且更大的 StoreFile。这种合并的触发频率很高。
minor compaction触发条件由以下几个参数共同决定:
<!--表示至少需要三个满足条件的store file时,minor compaction才会启动-->
<property>
<name>hbase.hstore.compactionThreshold</name>
<value>3</value>
</property>
<!--表示一次minor compaction中最多选取10个store file-->
<property>
<name>hbase.hstore.compaction.max</name>
<value>10</value>
</property>
<!--默认值为128m,
表示文件大小小于该值的store file 一定会加入到minor compaction的store file中
-->
<property>
<name>hbase.hstore.compaction.min.size</name>
<value>134217728</value>
</property>
<!--默认值为LONG.MAX_VALUE,
表示文件大小大于该值的store file 一定会被minor compaction排除-->
<property>
<name>hbase.hstore.compaction.max.size</name>
<value>9223372036854775807</value>
</property>
major compaction(大合并)
合并 Store 中所有的 HFile 为一个 HFile,将所有的 StoreFile 合并成为一个 StoreFile,这个过程中还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。合并频率比较低,默认7天执行一次,并且性能消耗非常大,建议生产关闭(设置为0),在应用空间时间手动触发。一般是可以手动控制进行合并,防止出现在业务高峰期。
- major compaction 触发时间条件:
<!--默认值为7天进行一次大合并,-->
<property>
<name>hbase.hregion.majorcompaction</name>
<value>604800000</value>
</property>
- 手动触发:
##使用major_compact命令
major_compact tableName