分享

HBase 底层的IO详解:Flush的工作原理

hyj 2019-11-25 17:13:54 发表于 介绍解说 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 1 4644
问题导读

1.Flush触发条件有哪些?
2.Flush 情况分为哪几种?
3.Flush流程分为哪几个阶段?


相关文章:HBase数据量过大变慢原因必知:Compaction的原理
https://www.aboutyun.com/forum.php?mod=viewthread&tid=28055

HBase 底层的IO详解:Flush的工作原理
https://www.aboutyun.com/forum.php?mod=viewthread&tid=28047


HBase 底层的IO详解:Region的split工作原理
https://www.aboutyun.com/forum.php?mod=viewthread&tid=28065


HBase 底层的IO详解:WAL的原理
https://www.aboutyun.com/forum.php?mod=viewthread&tid=28083


Flush的工作原理

1.Flush的触发条件:

1.(hbase.regionserver.global.memstore.size)默认;堆大小的40%
regionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%,而且regionserver级别的flush会阻塞客户端读写

2.(hbase.hregion.memstore.flush.size)默认:128M
单个region里memstore的缓存大小,超过那么整个HRegion就会flush,

3.(hbase.regionserver.optionalcacheflushinterval)默认:1h
内存中的文件在自动刷新之前能够存活的最长时间

4.(hbase.regionserver.global.memstore.size.lower.limit)默认:堆大小 * 0.4 * 0.95
有时候集群的“写负载”非常高,写入量一直超过flush的量,这时,我们就希望memstore不要超过一定的安全设置。在这种情况下,写操作就要被阻塞一直到memstore恢复到一个“可管理”的大小, 这个大小就是默认值是堆大小 * 0.4 * 0.95,也就是当regionserver级别的flush操作发送后,会阻塞客户端写,一直阻塞到整个regionserver级别的memstore的大小为 堆大小 * 0.4 *0.95为止

5.(hbase.hregion.preclose.flush.size)默认为:5M
当一个 region 中的 memstore 的大小大于这个值的时候,我们又触发 了 close.会先运行“pre-flush”操作,清理这个需要关闭的memstore,然后 将这个 region 下线。当一个 region 下线了,我们无法再进行任何写操作。 如果一个 memstore 很大的时候,flush  操作会消耗很多时间。"pre-flush" 操作意味着在 region 下线之前,会先把 memstore 清空。这样在最终执行 close 操作的时候,flush 操作会很快。

6.(hbase.hstore.compactionThreshold)默认:超过3个
一个store里面允许存的hfile的个数,超过这个个数会被写到新的一个hfile里面 也即是每个region的每个列族对应的memstore在fulsh为hfile的时候,默认情况下当超过3个hfile的时候就会 对这些文件进行合并重写为一个新文件,设置个数越大可以减少触发合并的时间,但是每次合并的时间就会越长.

Flush 情况分为以下几种:
【1、Memstore级别】
Memstore大小达到上限(hbase.hregion.memstore.flush.size,memsotre默认大小128M)时,会触发memstore flush

【2、Region级别】
当一个region中所有memstore大小总和达到了上限(hbase.hregion.memstore.block.multiplier*hbase.hregion.memstore.flush.size,默认2*128M=256M),会触发memstore flush

有一种场景是hbase在写入数据发生阻塞,原因就是这种情况,region server会在写入时检查每个region中的memstore总大小是否超过了单个memstore默认大小的2倍(hbase.hregion.memstore.block.multiplier参数决定),如果超过了则会阻塞写操作,避免产生OOM。由于在flush时还会由compact/split等操作同时进行,因此整个flush过程会比较漫长,必须要等待memstore完全flush到磁盘才会结束,默认regionserver会睡眠hbase.server.thread.wakefrequency(默认10s),再检查memstore大小是不是低于阈值。

生产环境是难以接受10s的等待时间的,因此在无法改变flush过程的时候,可以通过调整如下两个参数来避免或减少region级别的flush。

hbase.hregion.memstore.block.multiplier=10(默认是2,当节点内存充足时可调大此值)

habse.server.thread.wakefrequency=100(默认时10000ms)

【3、Region Server级别】
一个regionserver上会有很多region,意味着大量的memstore,很有可能单个region并没有超过阈值,但regionserver整体的内存占用达到阈值。

当一个region server上所有region中memstore的大小总和达到了head内存的低水位上限(hbase.regionserver.global.memstore.lowerlimit*hbase_heapsize,heap内存的低水位线,默认0.35),会触发部分memstore的flush,flush顺序是按照memstore由大到小执行,先执行memstore最大region的flush操作,再执行次大的,循环执行直到总体memstore内存使用量低于heap*0.35,以降低阻塞全部写操作flush带来的影响;

而当一个region server上所有region中memstore的大小总和达到了heap内存的上限(hbase.regionserver.global.memstore.upperlimit*hbase_heapsize,heap内存的高水位线,默认0.4),会阻塞所有的写操作,将所有memstore都进行flush。

【4、WAL数量达到上限,region级别】
设计这个触发条件的初衷是为了在region server宕掉时,通过WAL恢复的时间不要太久。

WAL的最大值由hbase.regionserver.hlog.blocksize*hbase.regionserver.maxlogs决定。一旦达到这个值,memstroe flush就会被触发。

WAL数量触发的flush策略是找到最早的un-archived WAL文件,将其对应的Region进行flush。

值得一提的是,blocksize (128 mb) * hbase.regionserver.maxlogs大小与hbase.regionserver.global.memstore.upperLimit * HBASE_HEAPSIZE两者之间谁大谁小,个人觉得前者应小于后者,因为若大于后者的话,将会优先做region server级别的flush,阻塞所有写操作,而这个阻塞往往是分钟级别。但cloudera给出的建议是前者大小应略大于后者,以保证不会提前发生flush,这点有待商榷。

【5、定期自动flush】
Region Server在启动时会启动一个线程PeriodicMemStoreFlusher,该线程每隔habse.server.thread.wakefrequency(默认10s)会检查该regeion Server的全部在线Region,当满足以下条件将会触发flush:

memstore中最老记录的时间戳与当前时间的时间间隔超过配置值hbase.regionserver.optionalcacheflushinterval(默认1小时),如果是meta表的region则为5分钟。

如果该参数为0,即为关闭自动刷写。同时,为了避免同时提交的flush太多,会有3~23秒的随机延迟。

【6、数据更新达到阈值】
同样由PeriodicMemStoreFlusher探测,当最后一次flush后的变更次数超过hbase.regionserver.flush.per.changes(默认3千万),也会触发flush。

【7、手工flush】
在hbase shell中调用flush,可以对某张表或某个region进行flush:

flush 'tablename'或flush 'region name'

Flush流程:
prepare阶段:遍历当前Region中的所有Memstore,将Memstore中当前数据集kvset做一个快照snapshot,然后再新建一个新的kvset。后期的所有写入操作都会写入新的kvset中,而整个flush阶段读操作会首先分别遍历kvset和snapshot,如果查找不到再会到HFile中查找。prepare阶段需要加一把updateLock对写请求阻塞,结束之后会释放该锁。因为此阶段没有任何费时操作,因此持锁时间很短。

flush阶段:遍历所有Memstore,将prepare阶段生成的snapshot持久化为临时文件,临时文件会统一放到目录.tmp下。这个过程因为涉及到磁盘IO操作,因此相对比较耗时。

commit阶段:遍历所有的Memstore,将flush阶段生成的临时文件移到指定的ColumnFamily目录下,针对HFile生成对应的storefile和Reader,把storefile添加到HStore的storefiles列表中,最后再清空prepare阶段生成的snapshot。




————————————————
原文链接:https://blog.csdn.net/qq_42316200/article/details/103210837


本帖被以下淘专辑推荐:

已有(1)人评论

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条