MemStore 是 HBase 非常重要的组成部分MemStore 作为 HBase 的写缓存保存着数据的最近一次更新同时是HBase能够实现高性能随机读写的重要组成。
MemStore
HBase Table 的每个 Column family 维护一个 MemStore当满足一定条件时 MemStore 会执行一次 flush文件系统中生成新的 HFile。而每次 Flush 的最小单位是 Region。
MemStore的主要作用
更新数据存储在 MemStore 中使用 LSMLog-Structured Merge Tree数据结构存储在内存内进行排序整合。即保证写入数据有序HFile中数据都按照RowKey进行排序同时可以极大地提升HBase的写入性能。
作为内存缓存读取数据时会优先检查 MemStore根据局部性原理新写入的数据被访问的概率更大。
在持久化写入前可以做某些优化例如保留数据的版本设置为1持久化只需写入最新版本。
如果一个 HRegion 中 MemStore 过多Column family 设置过多每次 flush 的开销必然会很大并且生成大量的 HFile 影响后续的各项操作因此建议在进行表设计的时候尽量减少 Column family 的个数。
Flush 时机
MemStore 无论是对 HBase 的写入还是读取性能都至关重要其中 flush 操作又是 MemStore 最核心的操作。MemStore 在多种情况下会执行一次 Flush 操作 再次注意MemStore 的最小 flush 单元是 HRegion 而不是单个 MemStore。
hbase.hregion.memstore.flush.size 默认值128M MemStore 级别限制当 Region 中任意一个 MemStore 的大小压缩后的大小达到了设定值会触发 MemStore flush。
hbase.hregion.memstore.block.multiplier 默认值2 Region 级别限制当 Region 中所有 MemStore 的大小总和达到了设定值hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size默认 2* 128M 256M会触发 MemStore flush。
hbase.regionserver.global.memstore.upperLimit 默认值0.4 Region Server 级别限制当一个 Region Server 中所有 MemStore 的大小总和达到了设定值hbase.regionserver.global.memstore.upperLimit * hbase_heapsize默认 0.4 * RS堆内存大小会触发全部 MemStore flush。
hbase.regionserver.global.memstore.lowerLimit 默认值0.38 与 hbase.regionserver.global.memstore.upperLimit 类似区别是当一个 Region Server 中所有 MemStore 的大小总和达到了设定值hbase.regionserver.global.memstore.lowerLimit * hbase_heapsize默认 0.38 * RS堆内存大小会触发部分 MemStore flush。
Flush 顺序是按照 Region 的总 MemStore 大小由大到小执行先操作 MemStore 最大的 Region再操作剩余中最大的 Region直至总体 MemStore 的内存使用量低于设定值hbase.regionserver.global.memstore.lowerLimit hbase_heapsize。
hbase.regionserver.maxlogs 默认值32 当一个 Region Server 中 HLog 数量达到设定值系统会选取最早的一个 HLog 对应的一个或多个 Region 进行 flush。
当增加 MemStore 的大小以及调整其他的 MemStore 的设置项时也需要去调整 HLog 的配置项。否则WAL的大小限制可能会首先被触发。因而将利用不到其他专门为Memstore而设计的优化。
需要关注的 HLog 配置是 HLog 文件大小由参数 hbase.regionserver.hlog.blocksize 设置默认512MHLog 大小达到上限或生成一个新的 HLog
通过WAL限制来触发Memstore的flush并非最佳方式这样做可能会会一次flush很多Region尽管“写数据”是很好的分布于整个集群进而很有可能会引发flush“大风暴”。
hbase.regionserver.optionalcacheflushinterval 默认值3600000 HBase 定期刷新 MemStore默认周期为1小时确保 MemStore 不会长时间没有持久化。为避免所有的 MemStore 在同一时间都进行 flush定期的 flush 操作有 20000 左右的随机延时。
手动触发 用户可以通过shell命令一下分别对一个 Table 或者一个 Region 进行 flush hbase> flush TABLENAME hbase> flush REGIONNAME
其他 执行 Compact 和 Split 之前会进行一次 flush。
Flush 阻止更新的情况
出现上述2的情况Region 下所有 Memstore 的总大小超过了 MemStore 默认大小的倍数该 Region 在 flush 完成前会 block 新的更新请求。
出现上述3的情况RegionServer 所有 MemStore 占整个堆的最大比例超过 hbase.regionserver.global.memstore.upperLimit 设置值该 RegionServer 的更新请求会被 block一直到 MemStore 恢复阈值一下。
更新被阻塞对单个节点和整个集群的影响都很大需要关注 MemStore 的大小和 Memstore Flush Queue 的长度。
Memstore Flush 流程
为了减少 flush 过程对读写的影响HBase 采用了类似于两阶段提交的方式将整个 flush 过程分为三个阶段
-
prepare 阶段遍历当前 Region 中的所有 MemStore将 MemStore 中当前数据集 kvset 做一个快照 snapshot然后再新建一个新的 kvset后期的所有写入操作都会写入新的 kvset 中。整个 flush 阶段读操作读 MemStore 的部分会分别遍历新的 kvset 和 snapshot。prepare 阶段需要加一把 updateLock 对写请求阻塞结束之后会释放该锁。因为此阶段没有任何费时操作因此持锁时间很短。
-
flush 阶段遍历所有 MemStore将 prepare 阶段生成的 snapshot 持久化为临时文件临时文件会统一放到目录.tmp下。这个过程因为涉及到磁盘IO操作因此相对比较耗时。
-
commit 阶段遍历所有的 MemStore将 flush 阶段生成的临时文件移到指定的 Column family 目录下生成对应的 StorefileHFile 和 Reader把 Storefile 添加到 HStore 的 Storefiles 列表中最后再清空 prepare 阶段生成的 snapshot。
上述 flush 流程可以通过日志信息查看
/******* prepare 阶段 ********/2018-07-06 18:33:31,329 INFO [MemStoreFlusher.1] regionserver.HRegion: Started memstore flush for [table],,1528539945017.80ab9764ae70fa97b75057c376726653., current region memstore size 21.73 MB, and 1/1 column families memstores are being flushed./******* flush 阶段 ********/2018-07-06 18:33:31,696 INFO [MemStoreFlusher.1] regionserver.DefaultStoreFlusher: Flushed, sequenceid40056, memsize21.7 M, hasBloomFiltertrue, into tmp file hdfs://ns/hbase/data/default/[table]/80ab9764ae70fa97b75057c376726653/.tmp/f71e7e8c15774da683bdecaf7cf6cb99/******* commit 阶段 ********/2018-07-06 18:33:31,718 INFO [MemStoreFlusher.1] regionserver.HStore: Added hdfs://ns/hbase/data/default/[table]/80ab9764ae70fa97b75057c376726653/d/f71e7e8c15774da683bdecaf7cf6cb99, entries119995, sequenceid40056, filesize7.3 M
整个 flush 过程可能涉及到 compact 操作和 split 操作因为过于复杂不做详细讲解。
MemStore 对业务的影响
正常情况下大部分 Memstore Flush 操作都不会对业务读写产生太大影响比如定期刷新 MemStore、手动触发、单个 MemStore flush、Region 级别的 flush 以及超过 HLog 数量限制等情况这几种场景只会短暂的阻塞对应 Region 上的写请求阻塞时间很短毫秒级别。
然而一旦触发 Region Server 级别的限制导致 flush就会对用户请求产生较大的影响。会阻塞所有落在该 RegionServer 上的更新操作阻塞时间很长甚至可以达到分钟级别。
导致触发 RegionServer 级别限制的主要因素
- Region Server 上运行的 Region 总数 Region 越多Region Server 上维护的 MemStore 就越多。根据业务表读写请求量和 RegionServer 可分配内存大小合理设置表的分区数量预分区的情况。
- Region 上的 Store 数表的 Column family 数量 每个 Column family 会维护一个 MemStore每次 MemStore Flush会为每个 Column family 都创建一个新的 HFile。当其中一个CF的 MemStore 达到阈值 flush 时所有其他CF的 MemStore 也会被 flush因此不同CF中数据量的不均衡将会导致产生过多 HFile 和小文件影响集群性能。很多情况下一个CF是最好的设计。
频繁的 MemStore Flush
频繁的 MemStore Flush 会创建大量的 HFile。在检索的时候就不得不读取大量的 HFile读性能会受很大影响。为预防打开过多 HFile 及避免读性能恶化读放大HBase 有专门的 HFile 合并处理HFile Compaction Process根据一定的策略合并小文件和删除过期数据。后续的文章会有详细介绍。
【本文由:高防服务器ip http://www.558idc.com/gfip.html 复制请保留原URL】