hbase memstore 的flush

region server的内存用于读写缓存主要有memstore和blockcache,其中memstore是写缓存。region server收的到写请求,实际上访问的是该server的region。每个region包含多个store,一个store对应着一个列族。每个store中又包含一个memstore和多个Hfile文件。memstore位于region server的主内存中,而HFiles被持久化到HDFS中。当region server处理写请求的时候,数据首先写入到memstore中去,然后当到达一定的阀值的时候,memstore中的数据会被flush到HFile中,此时的数据才完成持久化。

memstore flush机制

为了减少flush过程对读写的影响,HBase采用了类似于两阶段提交的方式,将整个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。

memstore刷新策略

  1. 当region中任意一个memstore的大小达到了上限(hbase.hregion.memstore.flush.size,默认为134217728即128MB),会触发这个region中所有的memstore刷新到磁盘。

  2. region级别限制:当region中所有memstore的大小总和达到了上限(hbase.hregion.memstore.block.multiplier hbase.hregion.memstore.flush.size,默认 2 128M = 256M),会触发memstore刷新并阻塞数据更新的请求。

  3. region Server级别限制:当一个region Server中所有memstore的大小总和达到了上限hbase.regionserver.global.memstore.upperLimit HBASE_HEAPSIZE,会触发部分memstore刷新。Flush顺序是按照memstore由大到小执行,先Flush memstore最大的region,再执行次大的,直至总体memstore内存使用量低于阈值hbase.regionserver.global.memstore.lowerLimit HBASE_HEAPSIZE。

  4. 当一个region Server中WAL数量达到上限hbase.regionserver.maxlogs时,包含最早的memstore的region会开始flush到磁盘,以减少WAL日志的数量。

  5. HBase定期刷新memstore:周期为hbase.regionserver.optionalcacheflushinterval,默认值为3600000ms即1小时,通过这个参数来确保memstore不会长时间没有持久化。设置该值为0时可关闭自动刷新。

可以手动执行flush,通过{hbase_dir}/bin/hbase shell命令, flush ‘tablename’或者flush ‘region_name’分别对一个表或者一个region进行flush。

避免过度flush

  • 当一个region中的memstore数量过大时,每次的flush无疑开销是巨大的,所以应该尽量避免同一张表中设计过多的列族。

  • 避免表的热点现象发生,即多个Region集中分布在一个region server上,在设计Rowkey的时候尽量随机一点,使Region分布的均衡一点