HBase源码解读,Store的实现

本文深入解读HBase的HStore源码,揭示其内部管理逻辑。HStore是一个接口,用于管理Region上的列簇,包括Memstore和StoreFiles。Store主要职责是管理StoreFiles,提供Compaction服务。HStore由HRegion管理,处理重建日志,并通过StoreEngine进行不同策略的管理。此外,文章介绍了HStore的构造方法、锁机制、Compaction流程及其等幂性设计,以及如何选择参与Compaction的文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一张hbase表HTable,大概是这样的管理逻辑。有N个Region,一个Region的每个列簇管理一个自己的Store,Store管理一个Memstore和至少一个StoreFile。
简单的说就是 :

Region:CF = 1:N N >= 1
CF : Store = 1 : 1
Store : Memstore = 1 : 1
Store : Storefile = 1 : N

Store是一个接口,Store.java开头的注释里写了这样一句话

Interface for objects that hold a column family in a Region. Its a memstore and a set of zero or more StoreFiles, which stretch backwards over time
这个接口会持有一个列簇在一个Region上的对象。它是一个Memstore至少一个StoreFile的集合,随着时间的向后推移,会越来越多。

因为HStore它是一个接口,并且当前只有HStore.java一个实现类,所以我们跳到HStore,从这里讲起。
HStore.java的类注释又多了几句话

There’s no reason to consider append-logging at this level; all logging and locking is handled at the HRegion level. Store just provides services to manage sets of StoreFiles. One of the most important of those services is compaction services where files are aggregated once they pass a configurable threshold.
没有理由要在HStore级别添加日志(指的是HLog,也叫WAL,Write ahead log),所有的日志和锁会在HRegion级别做处理。Store只提供管理一系列StoreFiles的服务。其中最重要的一个服务是当文件数量一旦超过一个预设的阈值,对这些文件进行一个聚合服务,叫做Compaction。

The only thing having to do with logs that Store needs to deal with is the reconstructionLog. This is a segment of an HRegion’s log that might NOT be present upon startup. If the param is NULL, there’s nothing to do. If the param is non-NULL, we need to process the log to reconstruct a TreeMap that might not have been written to disk before the process died.
唯一一件与日志产生关系的是Store需要处理重建日志。这是HRegion log的一部分,但是可能不会在启动时出现。如果这个参数为Null,什么都不做,如果参数不是Null,我们需要在进程挂掉前,使用日志重建一个TreeMap来处理还没被写到磁盘上的数据。

It’s assumed that after this constructor returns, the reconstructionLog file will be deleted (by whoever has instantiated the Store)
HStore会假定,当重建完成时,重建日志会被删除,无论谁实例化的这个Store

Locking and transactions are handled at a higher level. This API should not be called directly but by an HRegion manager.
锁和事物应该在更高的级别被处理,这个API不应该被直接调用,除了HRegion Manager。

其实看完注释,其实大致应该明白了,HStore的上面还有一级,叫HRegion,HStore是由HRegion负责管理,专门做一些聚合StoreFiles的操作(Compaction,又分为Major compaction和Minor compaction等)。

HRegion.java有三个重要的变量,其中两个应该会猜到,MemStore和StoreFile。StoreFile是被StoreEngine管理的,根据不同的策略(常见的有StripeStoreEngine,DefaultStoreEngine,还有比较特殊的DateTieredStoreEngine对日期序列有优化)。还有一个是CacheConfig,Store不光要负责写,如果有Scan或者Get,还要将block拿出来并且缓存到BlockCache中(又有LruBlockCache, CombineBlockCache, BucketCache等)。所以,重点需要看MemStore, StoreEngine和 CacheConfig这三个成员变量。

下面是StoreEngine的构造方法,通过这几个泛型就可以大致知道它都做了些什么。

public abstract class StoreEngine<SF extends StoreFlusher, CP extends CompactionPolicy, C extends Compactor, SFM extends StoreFileManager>

OK,接下来有关于HStore对锁的一段注释

RWLock for store operations
Locked in shared mode when the list of component stores is looked at:
- all reads/writes to table data
- checking for split
Locked in exclusive mode when the list of component stores is modified:
- closing
- completing a compaction

读写所在Store里面的几个操作:
符合下面条件时,锁进入共享模式
- 读写数据时
- 检查split时
符合下面条件,进入排他锁
- Store关闭时
- 完成compaction时

下面来看HStore的构造方法:

protected HStore(final HRegion region, final HColumnDescriptor family,
      final Configuration confParam) throws IOException

这解释了注释里面说的,Store是由Region,在列簇级别进行管理。
在这个构造方法最开始的一段,初始化了一些我们都很熟悉的获取文件系统,在文件系统上建立这个Region的目录(管理的是一个或多个StoreFiles,所以只能是目录),初始化BlockSize,,DataBlockEncoder等操作,HRegion构造方法太长了,这部分跳过。之后是一个有意思的配置。

long timeToPurgeDeletes = Math.max(conf.getLong("hbase.hstore.time.to.purge.deletes", 0), 0);

解释下 hbase.hstore.time.to.purge.deletes,注意不要和TTL搞混。我们应该都知道HBase在删除操作时实际上是在HLog里面添加delete标记,而真的删除是在Major compaction的时候处理。而TTL每行数据生存时间超过TTL的值,被delete掉。这个参数的意义是在TTL时,再多保留一段时间,为了照顾到两个集群间replication,put可能会出现无序的情况。另外,这个配置默认是0,就是和TTL保持同步,如果不为0时,不能超过TTL的大小,超过了这个配置会无效。

this.blockingFileCount =
        conf.getInt(BLOCKING_STOREFILES_KEY, DEFAULT_BLOCKING_STOREFILE_COUNT);

hbase.hstore.blockingStoreFiles是当MemStore在flush数据的时候,会检查这个HStore管理的StoreFile数量,默认是10,如果超过这个数量,flush会等待一个compaction完成,或者是超过hbase.hstore.blockingWaitTime,所以,结合实际情况就是,在60010观察集群性能时,Store和StoreFile的比例如果接近1:10,就要考虑对RegionServer针对业务表进行优化或者对表扩容。
接下来

this.compactionCheckMultiplier = conf.getInt(
        COMPACTCHECKER_INTERVAL_MULTIPLIER_KEY, DEFAULT_COMPACTCHECKER_INTERVAL_MULTIPLIER);
    if (this.compactionCheckMultiplier <= 0) {
      LOG.error("Compaction check period multiplier must be positive, setting default: "
          + DEFAULT_COMPACTCHECKER_INTERVAL_MULTIPLIER);
      this.compactionCheckMultiplier = DEFAULT_COMPACTCHECKER_INTERVAL_MULTIPLIER;
    }

hbase.server.compactchecker.interval.multiplier,检查compaction的时间间隔。通常compaction是在像flush这样的事情之后完成,但是如果这个Region的写入数据量比较低,或者是使用了特殊的Compaction策略,就需要定期检查是否需要进行compaction了。这个时间间隔是由hbase.server.compactchecker.interval.multiplierhbase.server.thread.wakefrequency的乘积共同得出

if (HStore.closeCheckInterval == 0) {
      HStore.closeCheckInterval = conf.getInt(
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值