HBase-遇到的问题

时间:2022-11-28 08:28:34

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()处理

  1. List<Pair<Mutation,Integer>> mutationsWithLocks =  
  2.      Lists.newArrayListWithCapacity(mutations.size());  
  3.  for (Action<R> a : mutations) {  
  4.    Mutation m = (Mutation) a.getAction();  
  5.   
  6.    Integer lock;  
  7.    try {  
  8.      lock = getLockFromId(m.getLockId());  
  9.    } catch (UnknownRowLockException ex) {  
  10.      response.add(regionName, a.getOriginalIndex(), ex);  
  11.      continue;  
  12.    }  
  13.    mutationsWithLocks.add(new Pair<Mutation, Integer>(m, lock));  
  14.  }  
  15.  this.requestCount.addAndGet(mutations.size());  
  16.  OperationStatus[] codes =  
  17.      region.batchMutate(mutationsWithLocks.toArray(new Pair[]{}));  

 2.HRegion#batchMutate()再调用HRegion#doMiniBatchMutation()

  这个函数很长,第一步是批量获得锁操作

  1. while (lastIndexExclusive < batchOp.operations.length) {  
  2.         boolean shouldBlock = numReadyToWrite == 0;  
  3.         Integer acquiredLockId = null;  
  4.         try {  
  5.           acquiredLockId = getLock(providedLockId, mutation.getRow(),  
  6.               shouldBlock);  
  7.         } catch (IOException ioe) {  
  8.           LOG.warn("Failed getting lock in batch put, row="  
  9.                   + Bytes.toStringBinary(mutation.getRow()), ioe);  
  10.         }  
  11.  ....  
  12. }  

 3.HRegion#getLock()函数是一个分支,通过debug来看,走的是if,因为lockid是null,在第一步里面有说明

  1. public Integer getLock(Integer lockid, byte [] row, boolean waitForLock)  
  2. throws IOException {  
  3.   Integer lid = null;  
  4.   if (lockid == null) {  
  5.     lid = internalObtainRowLock(row, waitForLock);  
  6.   } else {  
  7.     if (!isRowLocked(lockid)) {  
  8.       throw new IOException("Invalid row lock");  
  9.     }  
  10.     lid = lockid;  
  11.   }  
  12.   return lid;  
  13. }  

 4.最后调用HRegion#internalObtainRowLock(final byte[] row, boolean waitForLock)

  1. while (true) {  
  2.    CountDownLatch existingLatch = lockedRows.putIfAbsent(rowKey, rowLatch);  
  3.    if (existingLatch == null) {  
  4.      break;  
  5.    } else {  
  6.      // row already locked  
  7.      if (!waitForLock) {  
  8.        return null;  
  9.      }  
  10.      try {  
  11.        if (!existingLatch.await(this.rowLockWaitDuration,  
  12.                        TimeUnit.MILLISECONDS)) {  
  13.          throw new IOException("Timed out on getting lock for row="  
  14.              + Bytes.toStringBinary(row));  
  15.        }  
  16.      } catch (InterruptedException ie) {  
  17.        // Empty  
  18.      }  
  19.    }  
  20.  }  

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



WARN org.apache.hadoop.hbase.regionserver.HRegion: Failed getting lock in batch put, row=0001558252

这个是因为有一个Delete或Put操作,已经将rowkey锁住了,之后又有Delete或Put操作这个rowkey触发了一个CountDownLatch等待超时抛出的异常。








参考:

HBASE-7711

RegionServer stuck in internalObtainRowLock forever - HBase 0.94.7

How to improve my configuration of HBase version cdh4.4.0