由于BlockCache采用的是LRU策略,因此BlockCache达到上限(heapsize * hfile.block.cache.size * 0.85)后,会启动淘汰机制,淘汰掉最老的一批数据。
hbase在操作Block Cache的LRU淘汰过程中:
看如下函数:
- /**
- * Eviction method.
- */
- void evict() {
-
- // Ensure only one eviction at a time
- if(!evictionLock.tryLock()) return;
-
- try {
- evictionInProgress = true;
- long currentSize = this.size.get();
- long bytesToFree = currentSize - minSize();
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Block cache LRU eviction started; Attempting to free " +
- StringUtils.byteDesc(bytesToFree) + " of total=" +
- StringUtils.byteDesc(currentSize));
- }
-
- if(bytesToFree <= 0) return;
-
- // Instantiate priority buckets
- BlockBucket bucketSingle = new BlockBucket(bytesToFree, blockSize,
- singleSize());
- BlockBucket bucketMulti = new BlockBucket(bytesToFree, blockSize,
- multiSize());
- BlockBucket bucketMemory = new BlockBucket(bytesToFree, blockSize,
- memorySize());
-
- // Scan entire map putting into appropriate buckets
- for(CachedBlock cachedBlock : map.values()) {
- switch(cachedBlock.getPriority()) {
- case SINGLE: {
- bucketSingle.add(cachedBlock);
- break;
- }
- case MULTI: {
- bucketMulti.add(cachedBlock);
- break;
- }
- case MEMORY: {
- bucketMemory.add(cachedBlock);
- break;
- }
- }
- }
-
- PriorityQueue<BlockBucket> bucketQueue =
- new PriorityQueue<BlockBucket>(3);
-
- bucketQueue.add(bucketSingle);
- bucketQueue.add(bucketMulti);
- bucketQueue.add(bucketMemory);
-
- int remainingBuckets = 3;
- long bytesFreed = 0;
-
- BlockBucket bucket;
- while((bucket = bucketQueue.poll()) != null) {
- long overflow = bucket.overflow();
- if(overflow > 0) {
- long bucketBytesToFree = Math.min(overflow,
- (bytesToFree - bytesFreed) / remainingBuckets);
- bytesFreed += bucket.free(bucketBytesToFree);
- }
- remainingBuckets--;
- }
-
- if (LOG.isDebugEnabled()) {
- long single = bucketSingle.totalSize();
- long multi = bucketMulti.totalSize();
- long memory = bucketMemory.totalSize();
- LOG.debug("Block cache LRU eviction completed; " +
- "freed=" + StringUtils.byteDesc(bytesFreed) + ", " +
- "total=" + StringUtils.byteDesc(this.size.get()) + ", " +
- "single=" + StringUtils.byteDesc(single) + ", " +
- "multi=" + StringUtils.byteDesc(multi) + ", " +
- "memory=" + StringUtils.byteDesc(memory));
- }
- } finally {
- stats.evict();
- evictionInProgress = false;
- evictionLock.unlock();
- }
- }
复制代码
1)首先获取锁,保证同一时刻只有一个淘汰线程运行;
2)计算得到当前Block Cache总大小currentSize及需要被淘汰释放掉的大小bytesToFree,如果bytesToFree小于等于0则不进行后续操作;
3) 初始化创建三个BlockBucket队列,分别用于存放Single、Multi和InMemory类Block Cache,其中每个BlockBucket维护了一个CachedBlockQueue,按LRU淘汰算法维护该BlockBucket中的所有CachedBlock对象;
4) 遍历记录所有Block Cache的全局ConcurrentHashMap,加入到相应的BlockBucket队列中;
5) 将以上三个BlockBucket队列加入到一个优先级队列中,按照各个BlockBucket超出bucketSize的大小顺序排序(见BlockBucket的compareTo方法);
6) 遍历优先级队列,对于每个BlockBucket,通过Math.min(overflow, (bytesToFree - bytesFreed) / remainingBuckets)计算出需要释放的空间大小,这样做可以保证尽可能平均地从三个BlockBucket中释放指定的空间;具体实现过程详见BlockBucket的free方法,从其CachedBlockQueue中取出即将被淘汰掉的CachedBlock对象:
总结:
明白了上面内容,很明显是我们在启用淘汰机制的时候,发生了掉线,可以从原理上来解决,根据个人推测,这个应该可以自动修复。
|