- 浏览: 37298 次
- 来自: 杭州
最新评论
1. Cache 读写
调用逻辑:
hmaster.handleCreateTable->HRegion.createHRegion-> HRegion. initialize->initializeRegionInternals->instantiateHStore
->Store.Store->new CacheConfig(conf, family)-> CacheConfig.instantiateBlockCache->new LruBlockCache
传入参数
new LruBlockCache时除了设置默认的参数外,还会创建evictionThread并wait和一个定时打印的线程StatisticsThread
当执行HFileReaderV2的readBlock时,会先看判断是否开户了Cache ,如果开启,则使用cache中block
若是第一次读,则将block加入Cache.
2. LRU evict
写入cache时就是将block加入到 一个 ConcurrentHashMap中,并更新Metrics,之后判断if(newSize > acceptableSize() && !evictionInProgress), acceptableSize是初始化时给的值(long)Math.floor(this.maxSize * this.acceptableFactor),acceptableFactor是一个百分比,是可以配置的:"hbase.lru.blockcache.acceptable.factor"(0.85f), 这里的意思就是判断总Size是不是大于这个值,如果大于并且没有正在执行的eviction线程, 那么就执行evict。
在evict方法中,
1. 计算总size和需要free的size, minsize = (long)Math.floor(this.maxSize * this.minFactor);其中minFactor是可配置的"hbase.lru.blockcache.min.factor"(0.75f);
2. 初始化三种BlockBucket:bucketSingle,bucketMulti,bucketMemory并遍历map,按照三种类型分别add进各自的queue(MinMaxPriorityQueue.expectedSize(initialSize).create();)中, 并按照访问的次数逆序。
三种类型的区别是:
SINGLE对应第一次读的
MULTI对应多次读
MEMORY是设定column family中的IN_MEMORY为true的
其中三种BlockBuckt Size大小分配比例默认是:
static final float DEFAULT_SINGLE_FACTOR = 0.25f;
static final float DEFAULT_MULTI_FACTOR = 0.50f;
static final float DEFAULT_MEMORY_FACTOR = 0.25f;
并将三种BlockBuckt 加入到优先队列中,按照totalSize - bucketSize排序,,再计算需要free大小,执行free:
free方法中一个一个取出queue中block,由于是按照访问次数逆序,所以从后面取出就是先取出访问次数少的,将其在map中一个一个remove, 并更新Mertrics.
3. HBase LruBlockCache的特点是针对不同的访问次数使用不同的策略,避免频繁的更新的Cache(便如Scan),这样更加有利于提高读的性能。
调用逻辑:
hmaster.handleCreateTable->HRegion.createHRegion-> HRegion. initialize->initializeRegionInternals->instantiateHStore
->Store.Store->new CacheConfig(conf, family)-> CacheConfig.instantiateBlockCache->new LruBlockCache
传入参数
/** * Configurable constructor. Use this constructor if not using defaults. * @param maxSize maximum size of this cache, in bytes * @param blockSize expected average size of blocks, in bytes * @param evictionThread whether to run evictions in a bg thread or not * @param mapInitialSize initial size of backing ConcurrentHashMap * @param mapLoadFactor initial load factor of backing ConcurrentHashMap * @param mapConcurrencyLevel initial concurrency factor for backing CHM * @param minFactor percentage of total size that eviction will evict until * @param acceptableFactor percentage of total size that triggers eviction * @param singleFactor percentage of total size for single-access blocks * @param multiFactor percentage of total size for multiple-access blocks * @param memoryFactor percentage of total size for in-memory blocks */ public LruBlockCache(long maxSize, long blockSize, boolean evictionThread, int mapInitialSize, float mapLoadFactor, int mapConcurrencyLevel, float minFactor, float acceptableFactor, float singleFactor, float multiFactor, float memoryFactor)
new LruBlockCache时除了设置默认的参数外,还会创建evictionThread并wait和一个定时打印的线程StatisticsThread
当执行HFileReaderV2的readBlock时,会先看判断是否开户了Cache ,如果开启,则使用cache中block
// Check cache for block. If found return. if (cacheConf.isBlockCacheEnabled()) { // Try and get the block from the block cache. If the useLock variable is true then this // is the second time through the loop and it should not be counted as a block cache miss. HFileBlock cachedBlock = (HFileBlock) cacheConf.getBlockCache().getBlock(cacheKey, cacheBlock, useLock); if (cachedBlock != null) { BlockCategory blockCategory = cachedBlock.getBlockType().getCategory(); getSchemaMetrics().updateOnCacheHit(blockCategory, isCompaction); if (cachedBlock.getBlockType() == BlockType.DATA) { HFile.dataBlockReadCnt.incrementAndGet(); } validateBlockType(cachedBlock, expectedBlockType); // Validate encoding type for encoded blocks. We include encoding // type in the cache key, and we expect it to match on a cache hit. if (cachedBlock.getBlockType() == BlockType.ENCODED_DATA && cachedBlock.getDataBlockEncoding() != dataBlockEncoder.getEncodingInCache()) { throw new IOException("Cached block under key " + cacheKey + " " + "has wrong encoding: " + cachedBlock.getDataBlockEncoding() + " (expected: " + dataBlockEncoder.getEncodingInCache() + ")"); } return cachedBlock; } // Carry on, please load. }在getBlock方法中,会更新一些统计数据,重要的时更新
BlockPriority.SINGLE为BlockPriority.MULTI public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat) { CachedBlock cb = map.get(cacheKey); if(cb == null) { if (!repeat) stats.miss(caching); return null; } stats.hit(caching); cb.access(count.incrementAndGet()); return cb.getBuffer(); }---------------------
若是第一次读,则将block加入Cache.
// Cache the block if necessary if (cacheBlock && cacheConf.shouldCacheBlockOnRead( hfileBlock.getBlockType().getCategory())) { cacheConf.getBlockCache().cacheBlock(cacheKey, hfileBlock, cacheConf.isInMemory()); }
2. LRU evict
写入cache时就是将block加入到 一个 ConcurrentHashMap中,并更新Metrics,之后判断if(newSize > acceptableSize() && !evictionInProgress), acceptableSize是初始化时给的值(long)Math.floor(this.maxSize * this.acceptableFactor),acceptableFactor是一个百分比,是可以配置的:"hbase.lru.blockcache.acceptable.factor"(0.85f), 这里的意思就是判断总Size是不是大于这个值,如果大于并且没有正在执行的eviction线程, 那么就执行evict。
/** * Cache the block with the specified name and buffer. * <p> * It is assumed this will NEVER be called on an already cached block. If * that is done, an exception will be thrown. * @param cacheKey block's cache key * @param buf block buffer * @param inMemory if block is in-memory */ public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory) { CachedBlock cb = map.get(cacheKey); if(cb != null) { throw new RuntimeException("Cached an already cached block"); } cb = new CachedBlock(cacheKey, buf, count.incrementAndGet(), inMemory); long newSize = updateSizeMetrics(cb, false); map.put(cacheKey, cb); elements.incrementAndGet(); if(newSize > acceptableSize() && !evictionInProgress) { runEviction(); } }
在evict方法中,
1. 计算总size和需要free的size, minsize = (long)Math.floor(this.maxSize * this.minFactor);其中minFactor是可配置的"hbase.lru.blockcache.min.factor"(0.75f);
long currentSize = this.size.get(); long bytesToFree = currentSize - minSize();
2. 初始化三种BlockBucket:bucketSingle,bucketMulti,bucketMemory并遍历map,按照三种类型分别add进各自的queue(MinMaxPriorityQueue.expectedSize(initialSize).create();)中, 并按照访问的次数逆序。
三种类型的区别是:
SINGLE对应第一次读的
MULTI对应多次读
MEMORY是设定column family中的IN_MEMORY为true的
// Instantiate priority buckets BlockBucket bucketSingle = new BlockBucket(bytesToFree, blockSize, singleSize()); BlockBucket bucketMulti = new BlockBucket(bytesToFree, blockSize, multiSize()); BlockBucket bucketMemory = new BlockBucket(bytesToFree, blockSize, memorySize());
其中三种BlockBuckt Size大小分配比例默认是:
static final float DEFAULT_SINGLE_FACTOR = 0.25f;
static final float DEFAULT_MULTI_FACTOR = 0.50f;
static final float DEFAULT_MEMORY_FACTOR = 0.25f;
private long singleSize() { return (long)Math.floor(this.maxSize * this.singleFactor * this.minFactor); } private long multiSize() { return (long)Math.floor(this.maxSize * this.multiFactor * this.minFactor); } private long memorySize() { return (long)Math.floor(this.maxSize * this.memoryFactor * this.minFactor); }
并将三种BlockBuckt 加入到优先队列中,按照totalSize - bucketSize排序,,再计算需要free大小,执行free:
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--; }
free方法中一个一个取出queue中block,由于是按照访问次数逆序,所以从后面取出就是先取出访问次数少的,将其在map中一个一个remove, 并更新Mertrics.
public long free(long toFree) { CachedBlock cb; long freedBytes = 0; while ((cb = queue.pollLast()) != null) { freedBytes += evictBlock(cb); if (freedBytes >= toFree) { return freedBytes; } } return freedBytes; } protected long evictBlock(CachedBlock block) { map.remove(block.getCacheKey()); updateSizeMetrics(block, true); elements.decrementAndGet(); stats.evicted(); return block.heapSize(); }
3. HBase LruBlockCache的特点是针对不同的访问次数使用不同的策略,避免频繁的更新的Cache(便如Scan),这样更加有利于提高读的性能。
发表评论
-
HBase中Lease创建、失效、及常见问题
2013-11-07 11:52 6364HBase通过租约来控制每个scanner的操作时间。 1 ... -
HBase HFile和Hlog的cleaner执行流程和配置项
2013-06-09 14:50 5857HFile和Hlog是HBase中两大文件存在格式,HFile ... -
HLog代码分析及与HBase replication延时
2013-02-19 19:51 2764在分享replication时,有同事提出replicatio ... -
HBase replication 代码分析
2013-01-28 17:23 2965随着HBase的大规模应用,HBase的容灾显得特别的重要。 ... -
HBase大集群
2013-01-28 14:02 1228为什么HBase没有大集群? 因为如果一个HBase集群很大, ... -
HBase MVCC基本原理
2012-11-28 16:21 3261HBase MVCC(Multi Version Consi ... -
flush后split和compact后split
2012-10-11 17:51 1585什么时候split? 当某store所有文件总大小大于某个值时 ... -
HBase rpc调用
2012-10-10 18:47 2541HBase rpc 0.94中 例如在client put ... -
HBase keyvalue大小导致OOM
2012-09-27 12:11 1467在HBase上传时,会通过配置参数hbase.client.k ... -
HBase什么时候做minor major compact
2012-10-09 18:11 3794我们都知道compact分为两类,一类叫Minor compa ... -
HBase Put及flush
2012-09-21 10:50 17831. Put及flush a. ...
相关推荐
源码分析: 1. **目录结构**: 解压后的`hbase-book-master`包含项目的基本目录结构,如`src/main/java`用于存放Java源代码,`src/main/resources`存储资源配置文件,`pom.xml`是Maven项目对象模型,定义了项目的...
例如,`org.apache.hadoop.hbase.regionserver.HStore`类实现了MemStore和BlockCache,它们分别缓存内存中的新写入数据和硬盘上的热数据,提高读写效率。同时,HBase还支持Compaction操作,通过`org.apache.hadoop....
源码分析是理解HBase工作原理和技术细节的重要途径。HBase在大数据领域扮演着关键角色,它能够处理海量数据并提供实时访问。下面,我们将深入探讨HBase的核心概念和源码中的关键组件。 1. **HBase架构**:HBase基于...
HBase 0.94.4的源码分析有助于我们深入了解其内部机制,从而更好地进行系统设计和优化。无论是对于开发者还是管理员,掌握HBase的核心原理都将极大地提升在大数据领域的实践能力。通过不断学习和实践,我们可以更好...
HBase 1.2.0是该数据库的一个稳定版本,包含了众多优化和改进,对于想要深入理解HBase工作原理或者进行大数据分析的学习者来说,研究其源码是非常有价值的。 一、HBase架构与核心概念 1. 表与Region:HBase中的...
通过研究这些源码,读者可以了解到HBase的内部工作原理,如MemStore、HLog、BlockCache等关键组件的作用,以及它们如何协同工作以实现高效的数据存储和检索。此外,还能学习到如何根据业务需求来设计合理的表结构,...
11. **优化策略**:包括合理设置Region大小、预分区表、选择合适的Column Family、启用BlockCache等,以提升HBase的性能。 12. **安全配置**:在生产环境中,可能需要配置HBase与Kerberos进行集成,以实现身份验证...
根据业务需求调整HBase配置,如Region大小、Compaction策略、BlockCache设置等,提升系统性能。 五、学习资源 参考链接:[博客教程](https://blog.csdn.net/haobindayi/article/details/82948123),该博客提供了...
"HBaseTest"的源码中可能包含对预读取(BlockCache)、压缩、过滤器等优化手段的使用,这些都对提升HBase的性能至关重要。 通过分析"HBaseTest"源码,我们可以更直观地理解HBase的工作原理和使用方式,为实际项目...
3. **实时查询**:HBase支持实时读写操作,通过内存缓存和BlockCache机制,提供了亚秒级的查询响应速度。 4. **稀疏性**:HBase可以存储大量的稀疏数据,即许多行或列可能存在大量缺失值,只存储有实际数据的位置,...
- **缓存机制**:HBase利用内存缓存来加速读取操作,包括MemStore(内存中存储未刷新到磁盘的数据)和BlockCache(缓存经常访问的数据块)。 #### 四、HBase的应用场景 - **实时数据分析**:由于HBase提供了低延迟...
3. 性能调优:通过调整HBase的配置参数,如MemStore大小、BlockCache设置等,可以优化读写性能。 4. 监控与故障排查:Ambari提供了丰富的监控工具,包括HBase的CPU使用、磁盘I/O、网络流量等关键指标,帮助你及时...
8. **性能优化**:在开发过程中,了解和利用HBase的预读取(BlockCache)、MemStore和Compaction等特性可以显著提升性能。 9. **异常处理**:Java开发时,需要处理HBase特有的异常,如`IOException`、`...
在性能优化方面,可以通过调整Region大小、预分区表、使用BlockCache和MemStore来提升读写性能。HBase还支持 Coprocessors,这是一种在Region Server端运行的插件机制,可以用于实现自定义的业务逻辑,比如数据过滤...
HBase性能优化包括Region大小调整、BlockCache配置、Compaction策略优化、WAL(Write-Ahead Log)管理等。通过对这些参数的调整,可以显著提高读写性能和系统稳定性。 总之,HBase 2.2.6的源码提供了深入理解...
9. **查询优化**:虽然HBase主要面向随机读写,但通过预读(BlockCache)和Bloom Filter等机制,可以优化查询性能,减少磁盘I/O。 10. **监控与管理**:HBase提供了一套监控和管理工具,包括JMX、Web UI和命令行...
监控是运维的关键部分,HBase 提供了丰富的 Metrics,如 RegionServer 的 BlockCache 统计、读写延迟、内存使用情况等,这些指标有助于诊断和优化集群性能。 总结来说,HBase 是一个强大的大数据存储解决方案,尤其...
- **BlockCache**: 缓存机制,提高读取性能。 - **Replication**: 数据冗余,提供容错和高可用性。 - ** Coprocessors**: 在Region Server上运行的用户自定义代码,可以扩展HBase的功能。 ### 7. 文件名称解析 ...
- 性能优化:如改进的BlockCache机制,提升了读取性能;优化了写入流程,降低了延迟。 - 功能扩展:支持更多的过滤器和索引,便于复杂查询操作。 - 安全性提升:增强了用户认证和授权机制,提供了更完善的安全...