Hbase——运行原理
一、Hbase的架构
架构角色
-
Region Server
Region Server 为 Region 的管理者,其实现类为 HRegionServer,主要作用如下:- 对于数据的操作:get, put, delete;
- 对于 Region 的操作:splitRegion、compactRegion。
-
Master
Master 是所有 Region Server 的管理者,其实现类为 HMaster,主要作用如下:- 对于表的操作:create, delete, alter
- 对于 RegionServer的操作:分配 regions到每个RegionServer,监控每个 RegionServer的状态,负载均衡和故障转移。
-
Zookeeper
HBase 通过 Zookeeper 来做 Master 的高可用、RegionServer 的监控、元数据的入口以及集群配置的维护等工作。 -
HDFS
HDFS 为 HBase 提供最终的底层数据存储服务,同时为 HBase 提供高可用的支持。
数据存储角色
- StoreFile:保存实际数据的物理文件,StoreFile以HFile的形式存储在HDFS上。每个Store会有一个或多个StoreFile(HFile),数据在每个StoreFile中都是有序的。
- MemStore:写缓存,由于HFile中的数据要求是有序的,所以数据是先存储在MemStore中,排好序后,等到达刷写时机才会刷写到HFile,每次刷写都会形成一个新的HFile。
- WAL:预写日志由于数据要经过MemStore排序后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入MemStore中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。
每个RegionServer 可以服务多个Region,每个RegionServer中有多个Store、1个WAL,和1个BlockCache,每个Store对应一个列族,包含MemStore 和 StoreFile.
二、hbase 写数据流程
- 1、Client先访问zookeeper,获取hbase:meta表位于哪个Region Server。
- 2、访问对应的Region Server,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问。
- 3、与目标Region Server进行通讯;
- 4、将数据顺序写入(追加)到WAL;
- 5、将数据写入对应的MemStore,数据会在MemStore进行排序;
- 6、向客户端发送ack;
- 7、等待达到MemStore的刷写时机后,将数据刷写到HFile。
- 8、在web页面查看的时候会随机的给每一个Region生成一个随机编号。
说明:写入数据时,逻辑顺序是先写入到WAL(HLog),再写入memStore,但实际源码流程如下:使用事务回滚机制来确保WAL和memStore同步写入。
- 1)先获取锁(JUC),保证数据不会写入成功前数据不会被查询到
- 2)更新时间戳(数据中没定义时间戳则使用系统时间),集群中个HRegionServer的系统时间误差不能超过配置时间,否则集群启动不成功
- 3)内存中构建WAL
- 4)将构建的WAL追加到最后写入的WAL,此时不会将WAL同步到HDFS中的HLog中
- 5)将数据写入到memStore
- 6)释放锁
- 7)同步WAL到HLog,如果同步失败,会回滚memStore(通过doRollBackMemstore=false控制)
MemStore刷写(flush)
自动触发机制:HBase 2.0之前参数
第一种触发条件:(Region级别Flush)
- 当某个 memstroe 的大小达到了 hbase.hregion.memstore.flush.size(默认值 128M),其所在 region 的所有 memstore 都会刷写。
- 如果写入速度太快超过了刷写速度,当 memstore 的大小达到了 hbase.hregion.memstore.flush.size * hbase.hregion.memstore.block.multiplier(默认值 4)大小时,会触发所有memstore 刷写并阻塞 Region 所有的写请求,此时写数据会出现 RegionTooBusyException 异常。
<!-- 单个region里memstore的缓存大小,超过那么整个HRegion就会flush,默认128M -->
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>134217728</value>
<description>
Memstore will be flushed to disk if size of the memstore
exceeds this number of bytes. Value is checked by a thread that runs
every hbase.server.thread.wakefrequency.
</description>
</property>
<!-- 当一个HRegion上的memstore的大小满足hbase.hregion.memstore.block.multiplier *
hbase.hregion.memstore.flush.size, 这个HRegion会执行flush操作并阻塞对该HRegion的写入 -->
<property>
<name>hbase.hregion.memstore.block.multiplier</name>
<value>4</value>
<description>
Block updates if memstore has hbase.hregion.memstore.block.multiplier
times hbase.hregion.memstore.flush.size bytes. Useful preventing
runaway memstore during spikes in update traffic. Without an
upper-bound, memstore fills such that when it flushes the
resultant flush files take a long time to compact or split, or
worse, we OOME.
</description>
</property>
第二种触发条件:(RegionServer级别Flush)
- 当 regionServer 中 memstore 的总大小达到 java_heapsize(堆内存)* hbase.regionserver.global.memstore.size(默认值 0.4)* hbase.regionserver.global.memstore.size.lower.limit(默认值 0.95),region 会按照其所有 memstore 的大小顺序(由大到小)依次进行刷写。直到 regionServer 中所有 memstore 的总大小减小到上述值以下。
- 当 region server 中 memstore 的总大小达到 java_heapsize * hbase.regionserver.global.memstore.size(默认值 0.4)时,会阻止继续往所有的 memstore 写数据。
<!-- regionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%,而且regionserver级别的
flush会阻塞客户端读写。如果RegionServer的堆内存设置为2G,则memstore总内存大小为 2 * 0.4 = 0.8G-->
<property>
<name>hbase.regionserver.global.memstore.size</name>
<value></value>
<description>Maximum size of all memstores in a region server before
new
updates are blocked and flushes are forced. Defaults to 40% of heap (0.4).
Updates are blocked and flushes are forced until size of all
memstores
in a region server hits
hbase.regionserver.global.memstore.size.lower.limit.
The default value in this configuration has been intentionally left
emtpy in order to
honor the old hbase.regionserver.global.memstore.upperLimit property if
present.
</description>
</property>
<!--可以理解为一个安全的设置,有时候集群的“写负载”非常高,写入量一直超过flush的量,这时,我们就希望memstore不要超过一定的安全设置。
在这种情况下,写操作就要被阻塞一直到memstore恢复到一个“可管理”的大小, 这个大小就是默认值是堆大小 * 0.4 * 0.95,也就是当regionserver级别
的flush操作发送后,会阻塞客户端写,一直阻塞到整个regionserver级别的memstore的大小为 堆大小 * 0.4 *0.95为止 -->
<property>
<name>hbase.regionserver.global.memstore.size.lower.limit</name>
<value></value>
<description>Maximum size of all memstores in a region server before
flushes are forced.
Defaults to 95% of hbase.regionserver.global.memstore.size (0.95).
A 100% value for this value causes the minimum possible flushing to
occur when updates are
blocked due to memstore limiting.
The default value in this configuration has been intentionally left
emtpy in order to
honor the old hbase.regionserver.global.memstore.lowerLimit property if
present.
</description>
</property>
第三种触发条件:(RegionServer级别Flush)
- 定期 hbase.regionserver.optionalcacheflushinterval(默认3600000即一个小时)进行 MemStore 的刷写,确保 MemStore 不会长时间没有持久化。为避免所有的 MemStore 在同一时间进行 flush 而导致问题,定期的 flush 操作会有一定时间的随机延时。
第四种触发条件:(Region级别Flush)
- 当一个 Region 的更新次数达到 hbase.regionserver.flush.per.changes(默认30000000即3千万)时,也会触发 MemStore 的刷写。
第五种触发条件 - 当一个 RegionServer 的 HLog 即WAL文件数量达到上限(旧版本可通过参数 hbase.regionserver.maxlogs,新版不再对外开放 ,默认32)时,也会触发 MemStore 的刷写,HBase 会找到最旧的 HLog 文件对应的 Region 进行刷写 。
#region的memstore的触发
#判断如果某个region中的某个memstore达到这个阈值,那么触发flush,flush这个region的所有memstore
hbase.hregion.memstore.flush.size=128M
#region的触发级别:如果没有memstore达到128,但是所有memstore的大小加在一起大于等于128*4
#触发整个region的flush
hbase.hregion.memstore.block.multiplier=4
#regionserver的触发级别:所有region所占用的memstore达到阈值,就会触发整个regionserver中memstore的溢写
#从memstore占用最多的Regin开始flush
hbase.regionserver.global.memstore.size=0.4 --RegionServer中Memstore的总大小
#低于水位后停止
hbase.regionserver.global.memstore.size.upper.limit=0.99
hbase.regionserver.global.memstore.size.lower.limit = 0.4*0.95 =0.38
自动触发机制:HBase 2.0之后
#设置了一个flush的最小阈值
#memstore的判断发生了改变:max("hbase.hregion.memstore.flush.size / column_family_number",hbase.hregion.percolumnfamilyflush.size.lower.bound.min)
#如果memstore高于上面这个结果,就会被flush,如果低于这个值,就不flush,如果整个region所有的memstore都低于,全部flush
#水位线 = max(128 / 列族个数,16),列族一般给3个 ~ 42M
#如果memstore的空间大于42,就flush,如果小于就不flush;如果都小于,全部flush
举例:3个列族,3个memstore, 90/30/30 90会被Flush
举例:3个列族,3个memstore, 30/30/30 全部flush
hbase.hregion.percolumnfamilyflush.size.lower.bound.min=16M
# 2.x中多了一种机制:In-Memory-compact,如果开启了【不为none】,会在内存中对需要flush的数据进行合并
#合并后再进行flush,将多个小文件在内存中合并后再flush
hbase.hregion.compacting.memstore.type=none|basic|eager|adaptive
关于相关参数的说明和调整建议:
-
hbase.hregion.memstore.flush.size
默认值 128M,单个 MemStore 大小超过该阈值就会触发 Flush。如果当前集群 Flush 比较频繁,并且内存资源比较充裕,建议适当调整为 256M。调大的副作用可能是造成宕机时需要分裂的 HLog 数量变多,从而延长故障恢复时间。 -
hbase.hregion.memstore.block.multiplier
默认值 4,Region 中所有 MemStore 超过单个 MemStore 大小的倍数达到该参数值时,就会阻塞写请求并强制 Flush。一般不建议调整,但对于写入过快且内存充裕的场景,为避免写阻塞,可以适当调整到5~8。 -
hbase.regionserver.global.memstore.size
默认值 0.4,RegionServer 中所有 MemStore 大小总和最多占 RegionServer 堆内存的 40%。这是写缓存的总比例,可以根据实际场景适当调整,且要与 HBase 读缓存参数 hfile.block.cache.size(默认也是0.4)配合调整。旧版本参数名称为 hbase.regionserver.global.memstore.upperLimit。 -
hbase.regionserver.global.memstore.size.lower.limit
默认值 0.95,表示 RegionServer 中所有 MemStore 大小的低水位是 hbase.regionserver.global.memstore.size 的 95%,超过该比例就会强制 Flush。一般不建议调整。旧版本参数名称为 hbase.regionserver.global.memstore.lowerLimit。 -
hbase.regionserver.optionalcacheflushinterval
默认值 3600000(即 1 小时),HBase 定期 Flush 所有 MemStore 的时间间隔。一般建议调大,比如 10 小时,因为很多场景下 1 小时 Flush 一次会产生很多小文件,一方面导致 Flush 比较频繁,另一方面导致小文件很多,影响随机读性能,因此建议设置较大值。 -
此外还有一点值得说一下
官方建议使用一个列族,因为一个列族就对应磁盘中的一个文件,如果使用多个列族,数据不均匀的情况下,在全局Flush时会产生较多的小文件。
如: 列族 CF1 CF2 CF3
100M 1K 5K
全局Flush时,对于CF2和CF3会生成2个小文件。但是也可以使用多个列族,尽量保证数据均匀就好。
三、hbase 读数据流程
细节
- 1、Client先访问zookeeper,获取hbase:meta表位于哪个Region Server。
- 2、访问对应的Region Server,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问。
- 3、与目标Region Server进行通讯;
- 4、分别在Block Cache(读缓存),MemStore和Store File(HFile)中查询目标数据,并将查到的所有数据进行合并。此处所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete)。
- 5、将从文件中查询到的数据块(Block,HFile数据存储单元,默认大小为64KB)缓存到Block Cache。
- 6、将合并后的最终结果返回给客户端。
Block Cache
HBase 在实现中提供了两种缓存结构 MemStore(写缓存) 和 BlockCache(读缓存)。写缓存前面说过不再重复。
- 1、HBase 会将一次文件查找的 Block块 缓存到 Cache中,以便后续同一请求或者邻近数据查找请求,可以直接从内存中获取,避免昂贵的IO操作。
- 2、BlockCache是Region Server级别的,
- 3、一个Region Server只有一个Block Cache,在 Region Server 启动的时候完成 Block Cache 的初始化工作。
- 4、HBase对Block Cache的管理分为如下三种。
- LRUBlockCache 是最初的实现方案,也是默认的实现方案,将所有数据都放入JVM Heap中,交给JVM进行管理。
- SlabCache 实现的是堆外内存存储,不再由JVM管理数据内存。一般跟第一个组合使用,单它没有改善 GC 弊端,引入了堆外内存利用率低。
- BucketCache 缓存淘汰不再由 JVM 管理 降低了Full GC 发生的频率。
重点
读数据时不要理解为先从 MemStore 中读取,读不到再读 BlockCache 中,还读不到再从HFile中读取,然后将数据写入到 BlockCache 中。因为如果人为设置导致磁盘数据new,内存数据old。你读取的时候会出错的!
结论
HBase 把磁盘跟内存数据一起读,然后把磁盘数据放到 BlockCache中,BlockCache 是磁盘数据的缓存。HBase 是个读比写慢的工具。
四、StoreFile合并(Compaction)
-
由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的 HFile 中,因此查询时需要遍历所有的 HFile。
-
为了减少 HFile 的个数,以及清理掉过期和删除的数据,会进行 StoreFile Compaction。Compaction 分为两种,分别是 Minor Compaction 和 Major Compaction。
# 2.0版本之前,只有StoreFile文件的合并
磁盘中合并:minor compaction、major compaction
# 2.0版本开始,内存中的数据也可以先合并后Flush
内存中合并:In-memory compaction
磁盘中合并:minor compaction、major compaction
Minor Compaction :轻量级
- Minor Compaction 是指选取一些小的、相邻的 HFile 将他们合并成一个更大的 HFile。默认情况下,Minor Compaction 会删除所合并 HFile 中的 TTL 过期数据,但是不会删除手动删除(也就是 Delete 标记作用的数据)不会被删除。
- 属性: hbase.hstore.compaction.min=3
minor compact文件选择标准由以下几个参数共同决定
<!--待合并文件数据必须大于等于下面这个值-->
<property>
<name>hbase.hstore.compaction.min</name>
<value>3</value>
</property>
<!--待合并文件数据必须小于等于下面这个值-->
<property>
<name>hbase.hstore.compaction.max</name>
<value>10</value>
</property>
<!--默认值为128m,
表示文件大小小于该值的store file 一定会加入到minor compaction的store file中
-->
<property>
<name>hbase.hstore.compaction.min.size</name>
<value>134217728</value>
</property>
<!--默认值为LONG.MAX_VALUE,
表示文件大小大于该值的store file 一定会被minor compaction排除-->
<property>
<name>hbase.hstore.compaction.max.size</name>
<value>9223372036854775807</value>
</property>
Major Compaction :重量级合并
- Major Compaction 是指将一个 Store 中所有的 HFile 合并成一个 HFile,这个过程会清理三类没有意义的数据:被删除的数据(打了 Delete 标记的数据)、TTL 过期数据、版本号超过设定版本号的数据。另外,一般情况下,Major Compaction 时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此,生产环境下通常关闭自动触发 Major Compaction 功能,改为手动在业务低峰期触发。
- 参数配置: hbase.hregion.majorcompaction=7天
In-memory compaction
- 原理:将当前写入的数据划分segment【数据段】
- 当数据不断写入MemStore,划分不同的segment,最终变成storefile文件
- 如果开启内存合并,先将第一个segment放入一个队列中,与其他的segment进行合并
- 合并以后的结果再进行flush
- 内存中合并的方式:hbase.hregion.compacting.memstore.type=None|basic|eager|adaptive
- Basic compaction策略不清理多余的数据版本,无需对cell的内存进行考核
- eager compaction会过滤重复的数据,清理多余的版本,这会带来额外的开销
- adaptive compaction根据数据的重复情况来决定是否使用eager策略
禁用自动合并,使用手动处理:
Compact all regions in a table:
hbase> major_compact 't1'
hbase> major_compact 'ns1:t1'
Compact an entire region:
hbase> major_compact 'r1'
Compact a single column family within a region:
hbase> major_compact 'r1', 'c1'
Compaction 触发时机:
概括的说,HBase 会在三种情况下检查是否要触发 Compaction,分别是 MemStore Flush、后台线程周期性检查、手动触发。
- MemStore Flush:可以说 Compaction 的根源就在于Flush,MemStore 达到一定阈值或触发条件就会执行 Flush 操作,在磁盘上生成 HFile 文件,正是因为 HFile 文件越来越多才需要 Compact。HBase 每次Flush 之后,都会判断是否要进行 Compaction,一旦满足 Minor Compaction 或 Major Compaction 的条件便会触发执行。
- 后台线程周期性检查:后台线程 CompactionChecker 会定期检查是否需要执行 Compaction,检查周期为 hbase.server.thread.wakefrequency * hbase.server.compactchecker.interval.multiplier,这里主要考虑的是一段时间内没有写入仍然需要做 Compact 检查。其中参数 hbase.server.thread.wakefrequency 默认值 10000 即 10s,是 HBase 服务端线程唤醒时间间隔,用于 LogRoller、MemStoreFlusher 等的周期性检查;参数 hbase.server.compactchecker.interval.multiplier 默认值1000,是 Compaction 操作周期性检查乘数因子,10 * 1000 s 时间上约等于2hrs, 46mins, 40sec。
- 手动触发:通过 HBase Shell、Master UI 界面或 HBase API 等任一种方式执行 compact、major_compact等命令,会立即触发 Compaction。
Compaction 核心参数:
hbase.hstore.compaction.min
- 默认值 3,一个 Store 中 HFile 文件数量超过该阈值就会触发一次 Compaction(Minor Compaction),这里称该参数为 minFilesToCompact。一般不建议调小,重写场景下可以调大该参数,比如 5~10 之间,
- 注意相应调整下一个参数。老版本参数名称为 hbase.hstore.compactionthreshold。
hbase.hstore.compaction.max
- 默认值 10,一次 Minor Compaction 最多合并的 HFile 文件数量,这里称该参数为 maxFilesToCompact。这个参数也控制着一次压缩的耗时。一般不建议调整,但如果上一个参数调整了,该参数也应该相应调整,
- 一般设为 minFilesToCompact 的 2~3 倍。
hbase.regionserver.thread.compaction.throttle
- HBase RegionServer 内部设计了两个线程池 large compactions 与 small compactions,用来分离处理 Compaction 操作,该参数就是控制一个 Compaction 交由哪一个线程池处理,
- 默认值是 2 * maxFilesToCompact * hbase.hregion.memstore.flush.size(默认210128M=2560M即2.5G),建议不调整或稍微调大。
hbase.regionserver.thread.compaction.large/small
- 默认值 1,表示 large compactions 与 small compactions 线程池的大小。一般建议调整到 2~5,不建议再调太大比如10,否则可能会消费过多的服务端资源造成不良影响。
hbase.hstore.blockingStoreFiles
<!-- 每个store阻塞更新请求的阀值,表示如果当前hstore中文件数大于该值,系统将会强制执行compaction操作进行文件合并,
合并的过程会阻塞整个hstore的写入,这样有个好处是避免compaction操作赶不上Hfile文件的生成速率 -->
<property>
<name>hbase.hstore.blockingStoreFiles</name>
<value>10</value>
<description>
If more than this number of StoreFiles in any one Store
(one StoreFile is written per flush of MemStore) then updates are
blocked for this HRegion until a compaction is completed, or
until hbase.hstore.blockingWaitTime has been exceeded.
</description>
</property>
默认值 10,表示一个 Store 中 HFile 文件数量达到该值就会阻塞写入,等待 Compaction 的完成。一般建议调大点,比如设置为 100,避免出现阻塞更新的情况,阻塞日志如下:
too many store files; delaying flush up to 90000ms
生产环境建议认真根据实际业务量做好集群规模评估,如果小集群遇到了持续写入过快的场景,合理扩展集群也非常重要。
五、数据切分(Split)
默认情况下,每个 Table 起初只有一个 Region,随着数据的不断写入,Region 会自动进行拆分。刚拆分时,两个子 Region 都位于当前的 Region Server,但处于负载均衡的考虑,HMaster 有可能会将某个 Region 转移给其他的 Region Server。
Region Split 时机
- 当1个region中的某个Store下所有StoreFile的总大小超过hbase.hregion.max.filesize,该 Region 就会进行拆分(0.94 版本之前)。
- 当 1 个 region 中 的 某 个 Store 下所有 StoreFile 的 总 大 小 超 过 Min(R^2 * "hbase.hregion.memstore.flush.size",hbase.hregion.max.filesize"),该 Region 就会进行拆分,其中 R 为当前 Region Server 中属于该 Table 的个数(0.94 版本之后)。
- 2.*之后:判断region个数是否为1,如果为1,就按照256分,如果不为1,就按照10GB来分
数据切分会造成数据倾斜(region 大小分布不均),带来热点数据问题。所以建表时进行预分区来尽量避免这种问题。
关闭自动分裂,手动执行
split 'tableName'
split 'namespace:tableName'
split 'regionName' # format: 'tableName,startKey,id'
split 'tableName', 'splitKey'
split 'regionName', 'splitKey'
六、被删除数据(打了 Delete 标记的数据)的清除时机
被删除数据会在两种操作中被清除:
- Flush:内存数据刷写到磁盘(MemStore ——> StoreFile),这时候只会清除当前内存(memStore)中被 Delete 标记覆盖的数据,不会清除 Delete 标记。
- major compact:大合并会删除三类无效数据:被删除的数据(打了 Delete 标记的数据)、TTL 过期数据、版本号超过设定版本号的数据。
为什么 Flush 不清除 Delete 标记?
因为 Flush 只能清除 memStore 中的数据,还要留着 Delete 标记供 major compact 合并时去清除其他 StoreFile 中的数据。
七、Hbase优化
RowKey设计
-
唯一原则:Rowkey必须具有唯一性,不能重复,一个Rowkey唯一标识一条数据
-
业务原则:Rowkey的设计必须贴合业务的需求,一般选择最常用的查询条件作为rowkey的前缀
-
组合原则:将更多的经常作为的查询条件的列放入Rowkey中,可以满足更多的条件查询可以走索引查询
-
散列原则:为了避免出现热点问题,需要将数据的rowkey生成规则构建散列的rowkey
- 方案一:更换不是连续的字段作为前缀,例如用户id
- 方案二:反转,一般用于时间作为前缀,查询时候必须将数据反转再查询
- 方案三:加盐(Salt),本质对数据进行编码,生成数字加字母组合的结果
-
长度原则:在满足业务需求情况下,rowkey越短越好,一般建议Rowkey的长度小于100字节
- 原因:rowkey越长,比较性能越差,rowkey在底层的存储是冗余的
- 如果rowkey超过了100字节,将一个长的rowkey,编码为8位,16位,32位
内存优化
- 读多写少,降低MEMStore比例
- 读少写多,降低BlockCache比例
压缩机制
- 与hadoop支持的压缩算法相关
- create ‘t1_snappy’, {NAME=>‘info’, COMPRESSION => ‘SNAPPY’}
布隆过滤
-
ROW:行级布隆过滤
- 生成StoreFile文件时,会将这个文件中有哪些Rowkey的数据记录在文件的头部
- 当读取StoreFile文件时,会从文件头部获取这个StoreFile中的所有rowkey,自动判断是否包含需要的rowkey,如果包含就读取这个文件,如果不包含就不读这个文件
-
ROWCOL:行列级布隆过滤
- 生成StoreFile文件时,会将这个文件中有哪些Rowkey的以及对应的列族和列的信息数据记录在文件的头部
- 当读取StoreFile文件时,会从文件头部或者这个StoreFile中的所有rowkey以及列的信息,自动判断是否包含需要的rowkey以及列,如果包含就读取这个文件,如果不包含就不读这个文件
环境优化
-
系统环境
- 开启文件系统的预读缓存可以提高读取速度
- 最大限度使用物理内存
- 调整文件及进程句柄数
-
HDFS
- 保证RPC调用会有较多的线程数
- 文件块大小的调整
- 文件句柄数
- 超时时间
- 避免DN错误宕机
-
zookeeper
- 优化Zookeeper会话超时时间
-
hbase
- 设置RPC监听数量
- 优化hbase客户端缓存
- 指定scan.next扫描HBase所获取的行数
参考:
https://www.cnblogs.com/wdh01/p/16283244.html
https://blog.csdn.net/qq_33208851/article/details/105223419
https://blog.csdn.net/weixin_44133605/article/details/124635627
https://www.cnblogs.com/baran/p/15629009.html
https://www.cnblogs.com/sx66/p/13425465.html
https://blog.csdn.net/zfw_666666/article/details/126627977
https://blog.csdn.net/llAl_lAll/article/details/122260638
https://blog.csdn.net/weixin_48370579/article/details/125802173