HBase BlockCache
1. Cache 读写
调用逻辑:
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;
- }
- otected long evictBlock(CachedBlock block) {
- map.remove(block.getCacheKey());
- updateSizeMetrics(block, true);
- elements.decrementAndGet();
- stats.evicted();
- return block.heapSize();
3. HBase LruBlockCache的特点是针对不同的访问次数使用不同的策略,避免频繁的更新的Cache(便如Scan),这样更加有利于提高读的性能。
HBase BlockCache的更多相关文章
- hbase实践(十六) BlockCache
0 引言 和其他数据库一样,优化IO也是HBase提升性能的不二法宝,而提供缓存更是优化的重中之重. 根据二八法则,80%的业务请求都集中在20%的热点数据上,因此将这部分数据缓存起就可以极大地提升系 ...
- HBase 查询导致RegionServer OOM故障复盘
背景:我司作为某运营商公司的技术咨询公司,发现有第三方开发公司在使用HBase 1.1.2 (HDP 2.4.2.258版本)一段时间使用正常后,从某一天开始报OOM,从而导致RegionServer ...
- HBase的BlockCache
BlockCache 首先要明白Block,在HBase里面存储的最小单元:在memstore向硬盘刷的时候,如果目标block的大小+size之后大于MAX_SIZE,将会新创建一个block来存储 ...
- HBase之BlockCache数据读取(转)
转自:http://blog.csdn.net/u014297175/article/details/47976909 Hbase上Regionserver的内存分为两个部分,一部分作为Memstor ...
- hbase伪分布式平台搭建(centos 6.3)
搭建完<hadoop伪分布式平台>后就开始搭建hbase伪分布式平台了.有了hadoop环境,搭建hbase就变得很容易了. 一.Hbase安装 1.从官网下载最新版本Hbase安装包1. ...
- HBase change split policy on an existing table
hbase(main)::> create 'test_table_region', 'username' row(s) in 1.2150 seconds hbase(main)::> ...
- HBase的基本架构及其原理介绍
1.概述:最近,有一些工程师问我有关HBase的基本架构的问题,其实这个问题仅仅说架构是非常简单,但是需要理解.在这里,我觉得可以用HDFS的架构作为借鉴.(其实像Hadoop生态系统中的大部分组建的 ...
- HBase设计与开发性能优化(转)
本文主要是从HBase应用程序设计与开发的角度,总结几种常用的性能优化方法.有关HBase系统配置级别的优化,这里涉及的不多,这部分可以参考:淘宝Ken Wu同学的博客. 1. 表的设计 1.1 Pr ...
- hive与hbase整合过程
实现目标 Hive可以实时查询Hbase中的数据. hive中的表插入数据会同步更新到hbase对应的表中. 可以将hbase中不同的表中的列通过 left 或 inner join 方式映射到hiv ...
随机推荐
- 百度map 3.0初探
1.简介 在使用百度地图SDK为您提供的各种LBS能力之前,您需要获取百度地图移动版的开发密钥,该密钥与您的百度账户相关联.因此,您必须先有百度帐户,才能获得开发密钥.并且,该密钥与您创建的过程名称有 ...
- Dynamics CRM2013 流程拷贝
在CRM中工作流是一个非常不错的功能,在实际业务场景中能满足各种业务需求.在我们设置一个工作流的时候,同一个实体一个逻辑功能可能需要多个工作流来实现,而多个工作流的不同之处可能只是启动时间或者是步骤中 ...
- FFmpeg源代码简单分析:configure
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- 2.1、Android Studio通过Lint提升你的代码
为了测试你的Android应用符合功能需求.最重要的是确保你的代码没有结构性问题.结构差的代码影响你的Android应用的可靠性,让你的代码难以维护.比如,如果你的XML资源文件包含未使用的明明空间, ...
- Android初级教程对大量数据的做分页处理理论知识
有时候要加载的数据上千条时,页面加载数据就会很慢(数据加载也属于耗时操作).因此就要考虑分页甚至分批显示.先介绍一些分页的理论知识.对于具体用在哪里,会在后续博客中更新. 分页信息 1,一共多少条数据 ...
- UNIX网络编程——客户/服务器程序设计示范(一)
下面给出的是客户程序用于测试我们的服务器程序的各个变体. #include "unp.h" #define MAXN 16384 /* max # bytes to request ...
- SQL Server2012 AlwaysOn 无法将数据库联接到可用性组 针对主副本的连接未处于活动状态
在配置alwayson的可用性组时遇到如下截图中的错误,这里的服务器86是作为副本数据库服务器的. 解决该问题只需将SQL服务的运行账号改成管理员,并且打开防火墙中的5022端口(该端口号可在可用性组 ...
- UNIX环境高级编程——网络编程常用函数及结构
IP地址的转换 #include <arpa/inet.h> int inet_aton(const char *strptr, struct i ...
- 【UNIX网络编程第三版】阅读笔记(一):代码环境搭建
粗略的阅读过<TCP/IP详解>和<计算机网络(第五版)>后,开始啃这本<UNIX网络编程卷一:套接字联网API>,目前linux下的编程不算太了解,在阅读的过程中 ...
- MyBatis主键生成器KeyGenerator(一)
Mybatis提供了主键生成器接口KeyGenerator,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过配置的方式来完成这个功能 . 由于 ...