HBase BucketAllocatorException 異常剖析

近日,觀察到HBase集羣出現以下WARN日誌:java

2020-04-18 16:17:03,081 WARN [regionserver/xxx-BucketCacheWriter-1] bucket.BucketCache:Failed allocation for 604acc82edd349ca906939af14464bcb_175674734;
org.apache.hadoop.hbase.io.hfile.bucket.BucketAllocatorException: Allocation too big size=1114202; adjust BucketCache sizes hbase.bucketcache.bucket.sizes to accomodate if size seems reasonable and you want it cached.

大概意思是說:因爲block塊太大(size=1114202)致使BucketAllocator沒法爲其分配空間,若是想要被緩存而且以爲這樣作合理,能夠調整參數hbase.bucketcache.bucket.sizes。apache

默認狀況下,HBase BucketCache 可以緩存block的最大值爲512KB,即hbase.bucketcache.bucket.sizes=5120,9216,17408,33792,41984,50176,58368,66560,99328,132096,197632,263168,394240,525312,默認14種size標籤。若是想要緩存更大的block塊,咱們能夠調整參數爲 hbase.bucketcache.bucket.sizes=5120,9216,17408,33792,41984,50176,58368,66560,99328,132096,197632,263168,394240,525312,1049600,2098176,此時最大允許2MB的block。數組

下面咱們簡單看一下對應源代碼,涉及相關類爲:
/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/bucket/BucketAllocator.java
BucketAllocator主要實現對bucket的組織管理,爲block分配內存空間。緩存

/**
   * Allocate a block with specified size. Return the offset
   * @param blockSize size of block
   * @throws BucketAllocatorException
   * @throws CacheFullException
   * @return the offset in the IOEngine
   */
  public synchronized long allocateBlock(int blockSize) throws CacheFullException,
      BucketAllocatorException {
    assert blockSize > 0;
    BucketSizeInfo bsi = roundUpToBucketSizeInfo(blockSize);
    if (bsi == null) {
      throw new BucketAllocatorException("Allocation too big size=" + blockSize +
        "; adjust BucketCache sizes " + BlockCacheFactory.BUCKET_CACHE_BUCKETS_KEY +
        " to accomodate if size seems reasonable and you want it cached.");
    }
    long offset = bsi.allocateBlock();

    // Ask caller to free up space and try again!
    if (offset < 0)
      throw new CacheFullException(blockSize, bsi.sizeIndex());
    usedSize += bucketSizes[bsi.sizeIndex()];
    return offset;
  }

在調用roundUpToBucketSizeInfo()方法後,返回結果若是爲null則拋出BucketAllocatorException異常。看一下roundUpToBucketSizeInfo()方法:微信

/**
 * Round up the given block size to bucket size, and get the corresponding
 * BucketSizeInfo
*/
public BucketSizeInfo roundUpToBucketSizeInfo(int blockSize) {
    for (int i = 0; i < bucketSizes.length; ++i)
      if (blockSize <= bucketSizes[i])
        return bucketSizeInfos[i];
    return null;
}

該方法將傳入的blockSize與數組bucketSizes從索引0開始取值進行比較,一旦小於bucketSize[i],則爲該block分配bucketSizeInfos[i]大小的空間存放該block。oop

咱們看一下數組bucketSizes的初始化過程:this

private static final int DEFAULT_BUCKET_SIZES[] = { 4 * 1024 + 1024, 8 * 1024 + 1024,
  16 * 1024 + 1024, 32 * 1024 + 1024, 40 * 1024 + 1024, 48 * 1024 + 1024,
  56 * 1024 + 1024, 64 * 1024 + 1024, 96 * 1024 + 1024, 128 * 1024 + 1024,
  192 * 1024 + 1024, 256 * 1024 + 1024, 384 * 1024 + 1024,
  512 * 1024 + 1024 };

private final int[] bucketSizes;
BucketAllocator(long availableSpace, int[] bucketSizes)
  throws BucketAllocatorException {
  this.bucketSizes = bucketSizes == null ? DEFAULT_BUCKET_SIZES : bucketSizes;
  Arrays.sort(this.bucketSizes);
  ...
}

能夠看到,若是bucketSizes == null默認取數組DEFAULT_BUCKET_SIZES的值,並對該數組進行排序。這一步的排序爲上一步的循環比較奠基了基礎。spa

而數組DEFAULT_BUCKET_SIZES的值,也就是參數hbase.bucketcache.bucket.sizes的默認值。日誌

掃描二維碼關注博主公衆號

轉載請註明出處!歡迎關注本人微信公衆號【HBase工做筆記】
相關文章
相關標籤/搜索