JVM调优

内存调优




  



  • 2GB:留给系统进程。

  • 8GB:MapReduce服务。平均每1GB分配6个Map slots + 2个Reduce slots。

  • 4GB:HBase的RegionServer服务

  • 1GB:TaskTracker

  • 1GB:DataNode



Full GC调优



  • 串行回收器(SerialGC)。

  • 并行回收器(ParallelGC),主要针对年轻带进行优化(JDK 8 默认策略)。

  • 并发回收器(ConcMarkSweepGC,简称CMS),主要针对年老代进行优化。

  • G1GC回收器,主要针对大内存(32GB以上才叫大内存)进行优化。



  1. ParallelGC和CMS的组合方案

    export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g -XX:+UseParNewGC -XX:+UseConMarkSweepGC"

  2. G1GC方案

    export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=100"



MSLAB和In Memory Compaction(HBase2.X才有)



  • hbase.hregion.memstore.mslab.enabled:设置为true,即打开 MSLAB,默认为true。

  • hbase.hregion.memstore.mslab.chunksize:每个chunk的大 小,默认为2048 * 1024 即2MB。

  • hbase.hregion.memstore.mslab.max.allocation:能放入chunk 的最大单元格大小,默认为256KB,已经很大了。

  • hbase.hregion.memstore.chunkpool.maxsize:在整个memstore 可以占用的堆内存中,chunkPool占用的比例。该值为一个百分 比,取值范围为0.0~1.0。默认值为0.0。hbase.hregion.memstore.chunkpool.initialsize:在 RegionServer启动的时候可以预分配一些空的chunk出来放到 chunkPool里面待使用。该值就代表了预分配的chunk占总的 chunkPool的比例。该值为一个百分比,取值范围为0.0~1.0,默认值为0.0。



Region自动拆分



拆分策略

ConstantSizeRegionSplitPolicy



IncreasingToUpperBoundRegionSplitPolicy(默认)



  • tableRegionCount:表在所有RegionServer上所拥有的Region数量总和。

  • initialSize:如果你定义了 hbase.increasing.policy.initial.size,则使用这个数值;如果没有定义,就用memstore的刷写大小的2倍,即 hbase.hregion.memstore.flush.size * 2。

  • defaultRegionMaxFileSize:ConstantSizeRegionSplitPolicy 所用到的hbase.hregion.max.filesize,即Region最大大小。



  1. 刚开始只有一个文件的时候,上限是256MB,因为1^3 1282 = 256MB。

  2. 当有2个文件的时候,上限是2GB,因为2^3 128 2 2048MB。

  3. 当有3个文件的时候,上限是6.75GB,因为3^3 128 2 = 6912MB。

  4. 以此类推,直到计算出来的上限达到 hbase.hregion.max.filesize所定义的10GB。

KeyPrefixRegionSplitPolicy



  • 数据有多种前缀。

  • 查询多是针对前缀,比较少跨越多个前缀来查询数据。

DelimitedKeyPrefixRegionSplitPolicy



BusyRegionSplitPolicy



DisabledRegionSplitPolicy



推荐方案



  1. 用预拆分导入初始数据。

  2. 然后用自动拆分来让HBase来自动管理Region。



BlockCache优化



  • LRU BLOCKCACHE

  • SLAB CACHE

  • Bucket CACHE

LRU BLOCKCACHE



Slab Cache



Bucket Cache

  • 相比起只有2个区域的SlabeCache,BucketCache一上来就分配了 14种区域。注意:我这里说的是14种区域,并不是14块区域。这 14种区域分别放的是大小为4KB、8KB、16KB、32KB、40KB、 48KB、56KB、64KB、96KB、128KB、192KB、256KB、384KB、 512KB的Block。而且这个种类列表还是可以手动通过设置 hbase.bucketcache.bucket.sizes属性来定义(种类之间用逗号 分隔,想配几个配几个,不一定是14个!),这14种类型可以分 配出很多个Bucket。

  • BucketCache的存储不一定要使用堆外内存,是可以自由在3种存 储介质直接选择:堆(heap)、堆外(offheap)、文件 (file,这里的文件可以理解成SSD硬盘)。通过设置hbase.bucketcache.ioengine为heap、 offfheap或者file来配置。

  • 每个Bucket的大小上限为最大尺寸的block 4,比如可以容纳的最大的Block类型是512KB,那么每个Bucket的大小就是512KB 4 = 2048KB。

  • 系统一启动BucketCache就会把可用的存储空间按照每个Bucket 的大小上限均分为多个Bucket。如果划分完的数量比你的种类还少,比如比14(默认的种类数量)少,就会直接报错,因为每一种类型的Bucket至少要有一个Bucket。



  • hbase.bucketcache.ioengine:使用的存储介质,可选值为 heap、offheap、file。不设置的话,默认为offheap。

  • hbase.bucketcache.combinedcache.enabled:是否打开组合模 式(CombinedBlockCache),默认为true

  • hbase.bucketcache.size:BucketCache所占的大小

  • hbase.bucketcache.bucket.sizes:定义所有Block种类,默认 为14种,种类之间用逗号分隔。单位为B,每一种类型必须是 1024的整数倍,否则会报异常:java.io.IOException: Invalid HFile block magic。默认值为:4、8、16、32、40、48、56、 64、96、128、192、256、384、512。

  • -XX:MaxDirectMemorySize:这个参数不是在hbase-site.xml中 配置的,而是JVM启动的参数。如果你不配置这个参数,JVM会按 需索取堆外内存;如果你配置了这个参数,你可以定义JVM可以获得的堆外内存上限。显而易见的,这个参数值必须比 hbase.bucketcache.size大。



总结



  • 因为BucketCache自己控制内存空间,碎片比较少,所以GC时间 大部分都比LRUCache短。

  • 在缓存全部命中的情况下,LRUCache的吞吐量是BucketCache的 两倍;在缓存基本命中的情况下,LRUCache的吞吐量跟 BucketCache基本相等。

  • 读写延迟,IO方面两者基本相等。

  • 缓存全部命中的情况下,LRUCache比使用fiile模式的 BucketCache CPU占用率低一倍,但是跟其他情况下差不多。



HFile合并



  • Minor Compaction:将Store中多个HFile合并为一个HFile。在 这个过程中达到TTL的数据会被移除,但是被手动删除的数据不 会被移除。这种合并触发频率较高。

  • Major Compaction:合并Store中的所有HFile为一个HFile。在 这个过程中被手动删除的数据会被真正地移除。同时被删除的还 有单元格内超过MaxVersions的版本数据。这种合并触发频率较 低,默认为7天一次。不过由于Major Compaction消耗的性能较 大,你不会想让它发生在业务高峰期,建议手动控制Major Compaction的时机。

Compaction合并策略

RatioBasedCompactionPolicy



ExploringCompactionPolicy



FIFOCompactionPolicy



  • 过期的块被整个删除掉了。

  • 没过期的块完全没有操作。



  1. 表没有设置TTL,或者TTL=FOREVER。

  2. 表设置了MIN_VERSIONS,并且MIN_VERSIONS > 0

DateTieredCompactionPolicy



  • hbase.hstore.compaction.date.tiered.base.window.millis:基本的时间窗口时长。默认是6小时。拿默认的时间窗口举例:从现在到6小时之内的HFile都在同一个时间窗口里 面,即这些文件都在最新的时间窗口里面。

  • hbase.hstore.compaction.date.tiered.windows.per.tier:层 次的增长倍数。分层的时候,越老的时间窗口越宽。在同一个窗口里面的文件如果达到最小合并数量(hbase.hstore.compaction.min)就会进行合并,但不 是简单地合并成一个,而是根据 hbase.hstore.compaction.date.tiered.window.policy.class 所定义的合并规则来合并。说白了就是,具体的合并动作 使用的是用前面提到的合并策略中的一种(我刚开始看到 这个设计的时候都震撼了,居然可以策略套策略),默认是ExploringCompactionPolicy。

  • hbase.hstore.compaction.date.tiered.max.tier.age.millis:最老的层次时间。当文件太老了,老到超过这里所定义的时间范 围(以天为单位)就直接不合并了。不过这个设定会带来一个缺 点:如果Store里的某个HFile太老了,但是又没有超过TTL,并 且大于了最老的层次时间,那么这个Store在这个HFile超时被删 除前,都不会发生Major Compaction。没有Major Compaction, 用户手动删除的数据就不会被真正删除,而是一直占着磁盘空间。



  • 经常读写最近数据的系统,或者说这个系统专注于最新的数据。

  • 因为该策略有可能引发不了Major Compaction,没有Major Compaction是没有办法删除掉用户手动删除的信息,所以更适用 于那些基本不删除数据的系统。



  • 数据根据时间排序存储。

  • 数据的修改频率很有限,或者只修改最近的数据,基本不删除数据。



  • 数据改动很频繁,并且连很老的数据也会被频繁改动。

  • 经常边读边写数据。

StripeCompactionPolicy



  • Region要够大:这种策略实际上就是把Region给细分成一个个 Stripe。Stripe可以看做是小Region,我们可以管它叫sub- region。所以如果Region不大,没必要用Stripe策略。小Region 用Stripe反而增加IO负担。多大才算大?作者建议如果Region大 小小于2GB,就不适合用StripeCompactionPolicy。

  • Rowkey要具有统一格式,能够均匀分布。由于要划分KeyRange, 所以key的分布必须得均匀,比如用26个字母打头来命名 rowkey,就可以保证数据的均匀分布。如果使用timestamp来做 rowkey,那么数据就没法均匀分布了,肯定就不适合使用这个策略。

总结



  • 如果你的数据有固定的TTL,并且越新的数据越容易被读到,那么DateTieredCompaction一般是比较适合你的。

  • 如果你的数据没有TTL或者TTL较大,那么选择StripeCompaction会比默认的策略更稳定。

  • FIFOCompaction一般不会用到,这只是一种极端情况,比如用于 生存时间特别短的数据。如果你想用FIFOCompaction,可以先考虑使用DateTieredCompaction。

HBase比较高阶的调优指南-LMLPHP

本文分享自微信公众号 - 浪尖聊大数据(bigdatatip)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

03-14 13:46