项目场景:
项目场景:使用hbase1.2.0发起批写入请求,很容易出现RegionServerTooBuzyException,问题描述:
项目场景:使用hbase1.2.0发起批写入请求,很容易看到RegionTooBusyException, 出现这种问题:一般先百度一下,发现百度回来的方案,由于hbase有多个版本0.96,0.98,1.x,2.x,版本间的参数不一样。由于水平不足,百度回来的方案,基本不可用。 如何破解? 只能从源码种找答案
下图是hbase.1.2.0对应的hbase put数据流程
原因分析:
RegionTooBusyException是由put操作引起的,从hbase put流程源码入手,分析源码时,把客户端,服务端的交互,重要具体细节画出来
带着问题去源码找答案:
1.什么是RegionTooBusyException,是在哪抛出来的?
看源码思路:方法1:从请求路径开始client put 到server端
方法2:直接看异常抛出来的栈,分析栈的调用顺序,直接找到相应的类
2.什么时候flush,怎样触发的?
3.什么时候split? 触发条件?
这个图很大,需要直接看,不清晰,可以下载回来,进行拖动看
图1:hbase put流程图
17/12/07 11:49:41 INFO client.AsyncProcess: #70, table=www:person_dist, attempt=10/35 failed=826ops, last exception: org.apache.hadoop.hbase.RegionTooBusyException: org.apache.hadoop.hbase.RegionTooBusyException: Above memstore limit, regionName=www:person_dist,,1512617928531.a5bc9f2b05e93ca73beb7b1057d83e29., server=bigdata01.hzjs.co,16020,1510713472687, memstoreSize=216421096, blockingMemStoreSize=209715200
at org.apache.hadoop.hbase.regionserver.HRegion.checkResources(HRegion.java:3647)
at org.apache.hadoop.hbase.regionserver.HRegion.batchMutate(HRegion.java:2872)
at org.apache.hadoop.hbase.regionserver.HRegion.batchMutate(HRegion.java:2823)
at org.apache.hadoop.hbase.regionserver.RSRpcServices.doBatchOp(RSRpcServices.java:758)
at org.apache.hadoop.hbase.regionserver.RSRpcServices.doNonAtomicRegionMutation(RSRpcServices.java:720)
at org.apache.hadoop.hbase.regionserver.RSRpcServices.multi(RSRpcServices.java:2168)
at org.apache.hadoop.hbase.protobuf.generated.ClientProtos$ClientService$2.callBlockingMethod(ClientProtos.java:33656)
at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2188)
at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:112)
at org.apache.hadoop.hbase.ipc.RpcExecutor.consumerLoop(RpcExecutor.java:133)
at org.apache.hadoop.hbase.ipc.RpcExecutor$1.run(RpcExecutor.java:108)
at java.lang.Thread.run(Thread.java:745)
栈分析:
RSRpcServices 接收到batchMutate事件,对HRegion进行写入,写入前进行资源检查HRegion.checkResources() 发出的异常,直接看这个方法
private void checkResources() throws RegionTooBusyException {
// If catalog region, do not impose resource constraints or block updates.
if (this.getRegionInfo().isMetaRegion()) return;
if (this.memstoreSize.get() > this.blockingMemStoreSize) {
blockedRequestsCount.increment();
requestFlush();
throw new RegionTooBusyException("Above memstore limit, " +
"regionName=" + (this.getRegionInfo() == null ? "unknown" :
this.getRegionInfo().getRegionNameAsString()) +
", server=" + (this.getRegionServerServices() == null ? "unknown" :
this.getRegionServerServices().getServerName()) +
", memstoreSize=" + memstoreSize.get() +
", blockingMemStoreSize=" + blockingMemStoreSize);
}
}
分析源码: 当this.memstoreSize.get() > this.blockingMemStoreSize) 就flush,发起RegionTooBusyException,this是当前region, 就是把 this.blockingMemStoreSize 调大就能解决问题,哪怎样调大它呢? 继续分析blockingMemStoreSize 是什么东西
this.blockingMemStoreSize = this.memstoreFlushSize *
conf.getLong(HConstants.HREGION_MEMSTORE_BLOCK_MULTIPLIER,
HConstants.DEFAULT_HREGION_MEMSTORE_BLOCK_MULTIPLIER);
public static final String HREGION_MEMSTORE_BLOCK_MULTIPLIER =
"hbase.hregion.memstore.block.multiplier";
public static final int DEFAULT_HREGION_MEMSTORE_BLOCK_MULTIPLIER = 4;
HREGION_MEMSTORE_BLOCK_MULTIPLIER是 hbase.hregion.memstore.block.multiplier=4
追查:memstoreFlushSize 的大小是多少
memstoreFlushSize = conf.getLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE,
HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE);
hbase.hregion.memstore.flush.size=1024*1024*128L 即128M
总结:blockingMemStoreSize 就是memstoreSize * block乘数 = 默认的128M*4
对应的参数是:hbase.hregion.memstore.flush.size 和 hbase.hregion.memstore.block.multiplier
解决方案:
<font
color=#999AAA >提示:这里填写该问题的具体解决方案:
调大hbase.hregion.memstore.flush.size 和 hbase.hregion.memstore.block.multiplier
增大这2个只,又需要增大jvm大小。
还需要结合put流程图中分析的上水位,低水位进行调整
getGlobalMemstoreSize() >= globalMemStoreLimitLowMark()
是否大于下水位 具体分析流程跟上面分析的memtore乘数一样,自己试试分析源码
put过程不要产生compact和split 如何控制,还是看图看源码