本文共 20279 字,大约阅读时间需要 67 分钟。
#在hbase-env.sh中# The maximum amount of heap to use. Default is left to JVM default.export HBASE_HEAPSIZE=4G #原来是1G,现在修改为4G
export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xms4g -Xmx4g" export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g"
JVM的4种GC回收器
ParallelGC和CMS的组合方案
#habse-env.shexport HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g -XX:+UseParNewGCXX:+UseConcMarkSweepGC"
G1GC方案
这个方案需要你的RegionServer的内存大于4GB并且大于JDK1.7.0_04版本,因为这是jdk这个版本新加入的策略,这个方案适用于堆内存很大的情况,引入G1GC策略的原因是:就算采用CMS策略,还是不能避免FullGC,因为两种情况还是会引发CMS的Full GC
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=100"
32G,64G才算是大内存,当内存在4G或者32G之间的时候,需要测试方案的可行性来决定采用哪种方案,下面是一些参考意见
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy
现在内存越来越大,每增加一GB,平均会增加8到10秒的FullGC时间,所以当堆内存很大的时候,Full GC会消耗很多时间,对于CMS算法依旧会触发Full GC,原因是
-XX:CMSInitiatingOccupancyFraction=N
来缓解,N代表了当JVM启动垃圾回收时的堆内存占用百分比,设置的越小,JVM越早启动垃圾回收进程-XX:CMSInitiatingOccupancyFraction=N
是不起作用的,因为CMS只做回收不做合并,所以RegionServer启动久了肯定会遇到Full GC为什么会产生碎片化空间
假设红色大小为1KB,此时有2KB的新生代升级为老生代,但是JVM找不到连续的2KB内存空间去存放新对象,因为被刷写的内存只是被标记还没有释放,JVM这时候只好停止一切请求,然后将内存空间进行重新排列,这个排列的时间随着内存空间的增大而增大,当内存空间足够大的时候,暂停的时间足以让zk认为RegionServer挂了
MSLAB实现
MSLAB相关参数
hbase.hregion.memstore.mslab.enabled
:设置为true,即打开 MSLAB,默认为truehbase.hregion.memstore.mslab.chunksize
:每个chunk的大 小,默认为2048*1024 即2MBhbase.hregion.memstore.mslab.max.allocation
:能放入chunk 的最大单元格大小,默认为256KB,已经很大了hbase.hregion.memstore.chunkpool.maxsize
:在整个memstore 可以占用的堆内存中,chunkPool占用的比例,该值为一个百分 比,取值范围为0.0~1.0。默认值为0.0hbase.hregion.memstore.chunkpool.initialsize
:在 RegionServer启动的时候可以预分配一些空的chunk出来放到 chunkPool里面待使用.该值就代表了预分配的chunk占总的 chunkPool的比例,该值为一个百分比,取值范围为0.0~1.0,默 认值为0.0region自动拆分ConstantSizeRegionSplitPolicy
最早的0.94左右版本的时候只有一种拆分策略就是ConstantSizeRegionSplitPolicy
,即计算Region的到小来达到拆分的目的,用到的参数是
hbase.hregion.max.filesize 10737418240
region自动拆分IncreasingToUpperBoundRegionSplitPolicy
IncreasingToUpperBoundRegionSplitPolicy
拆分策略,该策略是限制不断增长的文件尺寸,文件尺寸限制是动态的Math.min(tableRegionCount^3 * initialsize, defaultRegionMaxFileSize)
hbase.increasing.policy.initial.size
这个数值,如果没有定义这个属性那么就用memstore的刷写大小的2倍region自动拆分KeyPrefixRegionSplitPolicy
KeyPrefixRegionSplitPolicy.prefix_length rowkey:前缀长度
region自动拆分DelimitedKeyPrefixRegionSplitPolicy
DelimitedKeyPrefixRegionSplitPolicy.delimiter : 前缀分隔符
region自动拆分BusyRegionSplitPolicy
一看名字就知道是热点region的拆分策略,那么怎么算是热点呢?其中涉及几个参数
hbase.busy.policy.blockedRequests
:请求被 阻塞的严重程度,取值范围是0.0~1.0,默认是0.2,即20%的请求被阻塞的意思hbase.busy.policy.minAge
:拆分最小年龄,当Region的年龄比这个小的时候不拆分,这是为了防止在判断是否要拆分的时候出 现了短时间的访问频率波峰,结果没必要拆分的Region被拆分 了,因为短时间的波峰会很快地降回到正常水平.单位毫秒,默认值10分钟hbase.busy.policy.aggWindow
:计算是否繁忙的时间窗口,单位毫秒,默认值5分钟,用以控制计算的频率计算region是否繁忙的计算方法
当前时间减去上次检测时间>=hbase.busy.policy.aggWindow
,则进行如下计算:这段时间的阻塞的请求/这段时间的总请求=请求的被阻塞率aggBlockedRate
aggBlocedRate>hbase.busy.policy.blockedRequests
,则判断该Region为繁忙region自动拆分DisabledRegionSplitPolicy
region预拆分
RegionSplitter
类来创建表,并传入拆分点算法就可以在建表的同时定义拆分点算法hbase(main):005:0> create 'mysplittable','cf',{NUMREGIONS=>10,SPLITALGO=>'HexStringSplit'}
STARTKEY => '', ENDKEY => '19999999'STARTKEY => '19999999', ENDKEY => '33333332'STARTKEY => '33333332', ENDKEY => '4ccccccb'STARTKEY => '4ccccccb', ENDKEY => '66666664'STARTKEY => '66666664', ENDKEY => '7ffffffd'STARTKEY => '7ffffffd', ENDKEY => '99999996'STARTKEY => '99999996', ENDKEY => 'b333332f'STARTKEY => 'b333332f', ENDKEY => 'ccccccc8'STARTKEY => 'ccccccc8', ENDKEY => 'e6666661'STARTKEY => 'e6666661', ENDKEY => ''
通过Merge类合并
hbase(main):011:0> merge_region '97fe9387f00844770619924108925ab4','4e35b33014d4d1a971059c78268b87ce'
BlockCache实现方案:LRUBlock Cache
区域名称 | 占用比例 | 说明 |
---|---|---|
single-access | 25% | 单次读取区,block被读出后先放入此区域,当被读到多次后,升级到下一个区域 |
multi-access | 50% | 多次读取区,当一个被缓存到单词读取区后又被多次访问会升级到这个区 |
in-memeory | 25% | 这个区域跟block被访问了几次没有关系,它只存放哪些被设置了IN-MEMEORY=TRUE的列族 中读取出来的block |
hfile.block.cache.size 0.4
BlockCache实现方案:SlabCache(废弃)`
堆内会产生Full GC,就需要考虑堆外内存了,堆外内存就是存放在了内存区域并且不属于JVM管理的,大小可以通过-XX:MaxDirectMe morySize=60MB
配置,最大的好处就是堆外内存回收的时候JVM几乎不会停顿,但是他也有缺点
SlabCache调用了nio的DirectByteBuffers,它把堆外内存按照80%和20%比例划分为两个区域
BlockCache实现方案:Bucket Cache
hbase.bucketcache.bucket.sizes
来定义,所以说是可以配置出很多Bucket,14种区域分别为4KB、8KB、16KB、32KB、40KB、 48KB、56KB、64KB、96KB、128KB、192KB、256KB、384KB、 512KB的Block,种类之间用逗号分隔,必须是 1024的整数倍hbase.bucketcache.ioengine
为heap、 offfheap或者file来配置alter 'test',CONFIGURATION=>{CACHE_DATA_IN_L1 => 'true'}
相关配置如下
hbase.bucketcache.ioengine
:使用的存储介质,可选值为 heap、offheap、file.默认为offheap。hbase.bucketcache.combinedcache.enabled
:是否打开组合模 式(CombinedBlockCache)默认为truehbase.bucketcache.size
:BucketCache所占的大小-XX:MaxDirectMemorySize
:这个参数是JVM启动的参数,如果不配置这个参数,JVM会按 需索取堆外内存,如果配置了这个参数,你可以定义JVM可以 获得的堆外内存上限,这个参数值必须比hbase.bucketcache.size
大组合模式
什么时候会触发刷写机制?
hbase.hregion.memstore.block.multiplier 4 hbase.hregion.memstore.flush.size 134217728
hbase.regionserver.global.memstore.size.lower.limit全局memstore刷写下 限以取值范围在0.0~1.0,默认为0.95*hbase_heapsize(RegionServer占用的堆内存大小)* hbase.regionserver.global.memstore.size
hbase.regionserver.global.memstore.size.lower.limit=0.95 hbase_heapsize* hbase.regionserver.global.memstore.size=16G*0.4 触发刷写阀值为:16*0.4*0.95=6.08,触发阻塞阀值为:16*0.4=6.4G 所以当memstore到达6.08G会触发强制刷写,当达到6.4G时会阻塞HBase集群的写入
maxLogs计算公式: Math.max(32,(regionserverHeapSize * MemStoreSizeRatiio * 2 / logRollSize))
Too many wals,counts=34,max=32,forcing flish of...
hbase.regionserver.optionalcacheflushinterval 3600000
Minor Compaction和Major Compaction
0.96之后的合并策略ExploringCompactionPolicy
该文件 < (所有文件大小总和 - 该文件大小) * 比例因子
hbase.hstore.compaction.min.size
,即最小合并大小,那么就直接进入待合并状态不需要套用公式,如果hbase.hstore.compaction.min.size
没有配置就使用刷写大小hbase.hregion.memstore.flush.size
限制,如果满足公式或者配置项任何一个就会进入待合并状态hbase.hstore.compaction.min
为3,设hbase.hstore.compaction.max
=4,所以5个HFile就进行排列组合,比如12345五个HFile,会组成12312341235125...
FIFOCompactionPolicy
FIFOCompactionPolicy策略在合并时会跳过含有未过期数据的 HFile,直接删除所有单元格都过期的块,最终
DateTieredCompactionPolicy
hbase.hstore.compaction.date.tiered.base.window.millis: 基本的时间窗口时长,默认是6小时。即从现在到6小时之内的HFile都在同一个时间窗口里 面,即这些文件都在最新的时间窗口里面,类似"时间分区"hbase.hstore.compaction.date.tiered.windows.per.tier:层 次的增长倍数。分层的时候,越老的时间窗口越宽hbase.hstore.compaction.date.tiered.max.tier.age.millis: 最老的层次时间。当文件太老了,老到超过这里所定义的时间范 围就直接不合并了
基本窗口宽度 (hbase.hstore.compaction.date.tiered.base.window.millis) = 1最小合并数量(hbase.hstore.compaction.min) = 3层次增长倍数 (hbase.hstore.compaction.date.tiered.windows.per.tier) = 2
这种策略适用于
它解决了什么问题?
适用于什么场景?
参数设置
hbase.regionserver.throughput.controller:你要限制的类型 对应的类名 控制合并相关指标: PressureAwareCompactionThroughputController:默认 控制刷写相关指标: PressureAwareFlushThroughputControllerhbase.hstore.blockingStoreFiles:当StoreFile数量达到该 值,阻塞刷写动作hbase.hstore.compaction.throughput.lower.bound:合并占用吞吐量下限hbase.hstore.compaction.throughput.higher.bound:合并占用吞吐量上限
hbase.hstore.blockingStoreFiles
memstore写入上限:hbase.hregion.memstore.block.multiplier*hbase.hregion.memstore.flush.size
合并/刷写吞吐量限制机制
HBase会计算合并/刷写时占用的吞吐量,然后当占用吞吐量过大的 时候适当地休眠,限制机制是分高峰时段和非高峰时段的,通过两个参数配置
hbase.offpeak.start.hour:每天非高峰的起始时间,取值为 0~23的整数,包含0和23hbase.offpeak.end.hour:每天非高峰的而结束时间,取值为 0~23的整数,包含0和23
lowerBound:hbase.hstore.compaction.throughput.lower.bound合并占用吞 吐量下限,默认是10 MB/secupperBound:hbase.hstore.compaction.throughput.higher.bound合并占用 吞吐量上限,默认是20 MB/secpressureRatio:压力比。限制合并时,该参数就是合并压力compactionPressure,限制刷写时该参数刷写压力 flushPressure这个数值为0~1.0公式:lowerBound + (upperBound - lowerBound) * pressureRatio
压力比
(HfileCount - minFilesToCOmpact) / (blockingFileCount - minFilesToCOmpact)HfileCount:当前storeFile数量minFilesToCOmpact:单词合并文件数量下线,即hbase.hstore.compaction.minblockingFileCount:即hbase.hstore.blockingStoreFiles
globalMemstoreSize / memstoreLowerLimitSizeglobalMemstoreSize:当前的memstore大小memstoreLowerLimitSize:memstore刷写下线,当全局 memstore达到这个内存占用数量的时候就会开始刷写
获取需要合并的HFile列表
用户正在scan查询:上Region读锁(region read lock)Region正在切分(split):此时Region会先关闭,然后上 Region写锁(region write lock)Region关闭:上Region写锁(region write lock)Region批量导入:上Region写锁(region write lock)
由列表创建出StoreFileScanner
把数据从这些HFile中读出,并放到tmp目录
用合并后的HFile来替换合并前的那些HFile
为什么只有majorCompaction可以真正删除数据
为什么达到TTL的数据可以被Minor Compaction删除
nowtime - celltimestamp >TTL
来判断cell 是否过期,如果过期了就不返回这条数据。这样当合并完成后,过期的数据因 为没有被写入新文件,自然就消失了阻塞急救:出现了服务器数据无法写入、RegionServer频频宕机,参考下面的配置
hbase.hstore.blockingStoreFiles
hbase.hregion.memstore.flush.size*hbase.hregion.memstore.block
这两参数hbase.regionserver.global.memstore.size
是一个0~1 的数字,代表可占内存的百分比,可以适当调大,但是这个调大,就必须把hfile.block.cache.size
调小,因为两个参数不可以超过0.8RegionServer自杀(朱丽叶暂停):可能发生的原因有
解决参考方案
hbase.hregion.memstore.mslab.enabled:设置为true即打开 MSLAB,默认为truehbase.hregion.memstore.chunkpool.maxsize:在整个Memstore 可以占用的堆内存中,chunkPool占用的比例。默认值为0.0。把这个值设置成非0.0 的值,才能真正开启MSLABhbase.hregion.memstore.chunkpool.initialsize:在 RegionServer启动的时候可以预分配 一些空的chunk出来,放到chunkPool里面待使用。该值就代表了预分配的chunk占总的chunkPool的比例。默认值为0.0。如果设置了预分配性能曲线在一开始会更平滑
读取性能调优
hfile.block.cache.size
的值,但同时要注意BlockCache和MemStore的 总和不能超过0.8,因为至少要留20%的堆内存空间给JVM进行必要的操作转载地址:http://mqxym.baihongyu.com/