分享

HBase “Failed getting lock in batch put”错误的疑问

Riordon 发表于 2016-5-23 17:54:24 [显示全部楼层] 只看大图 回帖奖励 阅读模式 关闭右栏 4 16052
回帖奖励 40 云币      回复本帖可获得 5 云币奖励! 每人限 1 次
前天HBase集群突然不可读写,重启后恢复,为避免一次再次出现类似情形发生,有些疑问
查看log,发现其中一台regionserver有WARN日志,截取部分如下:
[mw_shl_code=shell,true]2016-05-21 19:21:38,770 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:22:08,770 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:22:38,771 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:23:08,771 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:23:38,771 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:24:08,771 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:24:38,772 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:25:08,772 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:25:38,772 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326
2016-05-21 19:26:08,772 WARN  [RpcServer.handler=20,port=60020] regionserver.HRegion: Failed getting lock in batch put, row=05-00009150728305-20160521181326[/mw_shl_code]
每隔半小时同一条报一次

请问:
1)这种死锁一般由于设么引起?
2)有什么方案可以避免发生?
在此,先谢谢了...

已有(4)人评论

跳转到指定楼层
nextuser 发表于 2016-5-23 21:04:13

回帖奖励 +5 云币

下面内容希望对楼主有帮助

rowlock release problem with thread interruptions in batchMutate
在region server的log中有大量的WARN日志:
WARN org.apache.hadoop.hbase.regionserver.HRegion: Failed getting lock in batch put,
row=0001558252
搜索关键字"Failed getting lock in batch put"整个hbase代码中只有一个地方出现了这个关键字

1.HRegionServer#multi()接收到multi操作,找到某个region对其操作
这里会创建mutation操作,和对应的锁,锁是用RowLock获得的,默认锁id是-1,如果是-1则返回null,这样构造出的Pair对的first就是mutation,second就是null了,再将构造好的值传给HRegion#batchMutate()处理

[mw_shl_code=bash,true]List<Pair<Mutation,Integer>> mutationsWithLocks =  
     Lists.newArrayListWithCapacity(mutations.size());  
for (Action<R> a : mutations) {  
   Mutation m = (Mutation) a.getAction();  
  
   Integer lock;  
   try {  
     lock = getLockFromId(m.getLockId());  
   } catch (UnknownRowLockException ex) {  
     response.add(regionName, a.getOriginalIndex(), ex);  
     continue;  
   }  
   mutationsWithLocks.add(new Pair<Mutation, Integer>(m, lock));  
}  
this.requestCount.addAndGet(mutations.size());  
OperationStatus[] codes =  
     region.batchMutate(mutationsWithLocks.toArray(new Pair[]{}));  [/mw_shl_code]

2.HRegion#batchMutate()再调用HRegion#doMiniBatchMutation()
  这个函数很长,第一步是批量获得锁操作

[mw_shl_code=bash,true]while (lastIndexExclusive < batchOp.operations.length) {  
        boolean shouldBlock = numReadyToWrite == 0;  
        Integer acquiredLockId = null;  
        try {  
          acquiredLockId = getLock(providedLockId, mutation.getRow(),  
              shouldBlock);  
        } catch (IOException ioe) {  
          LOG.warn("Failed getting lock in batch put, row="  
                  + Bytes.toStringBinary(mutation.getRow()), ioe);  
        }  
....  
}  [/mw_shl_code]

3.HRegion#getLock()函数是一个分支,通过debug来看,走的是if,因为lockid是null,在第一步里面有说明
[mw_shl_code=bash,true]public Integer getLock(Integer lockid, byte [] row, boolean waitForLock)  
throws IOException {  
  Integer lid = null;  
  if (lockid == null) {  
    lid = internalObtainRowLock(row, waitForLock);  
  } else {  
    if (!isRowLocked(lockid)) {  
      throw new IOException("Invalid row lock");  
    }  
    lid = lockid;  
  }  
  return lid;  
}  [/mw_shl_code]

4.最后调用HRegion#internalObtainRowLock(final byte[] row, boolean waitForLock)
[mw_shl_code=bash,true]while (true) {  
   CountDownLatch existingLatch = lockedRows.putIfAbsent(rowKey, rowLatch);  
   if (existingLatch == null) {  
     break;  
   } else {  
     // row already locked  
     if (!waitForLock) {  
       return null;  
     }  
     try {  
       if (!existingLatch.await(this.rowLockWaitDuration,  
                       TimeUnit.MILLISECONDS)) {  
         throw new IOException("Timed out on getting lock for row="  
             + Bytes.toStringBinary(row));  
       }  
     } catch (InterruptedException ie) {  
       // Empty  
     }  
   }  
}  [/mw_shl_code]


internalObtainRowLock()函数的开头会创建一个readLock(),在函数结束后会释放这个readLock()
lockedRows是一个ConcurrentHashMap,当第一次调用putIfAbsent()时候,由于map中还没有这个key,所以返回的CountDownLatch为null,于是直接返回了。
可以看到lockedRows的key就是rowkey,所有之前这个map中存在了相同的rowkey,但是没有被remove掉,之后又有请求要操作相同的key就会等待,如果等待30秒(rowLockWaitDuration值为30秒)则会抛出异常,之后向上抛被HRegion#batchMutate()捕获并打印日志,也就是日志中出现的 Failed getting lock in batch put
这个锁只对于Put和Delete操作,Get操作不受锁的影响

这个函数有一个waitForLock参数,如果为false,则不会等待直接返回
在第二步中有一个中有一个重试次数,如果不为0则传到internalObtainRowLock()函数时变量waitForLock就为false,但是不会做这个重试。而是直接返回了,所以每次再有新的请求时,都会用waitForLock=true去调用这个函数,所以也就阻塞了,而且HRegion#batchMutate()有一个循环判断,这个循环也没有退出来,也就不是不停的调用HRegion#doMiniBatchMutation(),不停的重试,获取锁。
如果锁住rowkey的这个进程卡主了或者其他原因导致lockedRows中一直有这个rowkey,那么这个重试循环就不会退出导致死循环,所以日志会会出现大量的Failed getting lock in batch put
参考:
HBASE-7711
RegionServer stuck in internalObtainRowLock forever - HBase 0.94.7
How to improve my configuration of HBase version cdh4.4.0




我是小小鸟


回复

使用道具 举报

einhep 发表于 2016-5-23 21:18:46

回帖奖励 +5 云币

回复

使用道具 举报

Riordon 发表于 2016-5-24 09:17:38
nextuser 发表于 2016-5-23 21:04
下面内容希望对楼主有帮助

rowlock release problem with thread interruptions in batchMutate

谢谢分享,在什么样的情形下,会促发这种状况呢?
回复

使用道具 举报

einhep 发表于 2016-5-24 13:55:23
Riordon 发表于 2016-5-24 09:17
谢谢分享,在什么样的情形下,会促发这种状况呢?

插入的时候,并且rowkey相同,就会出现这种情况

~~~~~~~~~~~~~~~~~~~~~~~~~~~
lockedRows的key就是rowkey,所有之前这个map中存在了相同的rowkey,但是没有被remove掉,之后又有请求要操作相同的key就会等待,如果等待30秒(rowLockWaitDuration值为30秒)则会抛出异常,之后向上抛被HRegion#batchMutate()捕获并打印日志,也就是日志中出现的 Failed getting lock in batch put
这个锁只对于Put和Delete操作,Get操作不受锁的影响
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条