《HBbase原理与实践》读书笔记
第五章 RegionServer的核心模板
RegionServer 是HBase 的最核心组件,主要负责 用户数据的读写等IO操作。
一个RS由默认由一个HLog、一个BlockCache 以及多个Region组成。
一个Region由一个 多个store 组成 (有多少column 就有多少 store)
一个store 由 一个MemStore 和 多个Hfile 组成, Hfile存放在HDFS上面
5.1 RegionServer的内部结构
内部结构图如下:
5.2 HLog
5.2.1/2 HLog文件结构/存储
HLog是WAL的实现类。HBase的数据恢复和主从复制都基于HLog实现
每个RegionServer默认有一个HLog(1.1版本可以开启MultiWAL功能 允许多个HLog)
每个HLog是多个Region共享的
hbase所有数据都存储在hdfs上。Hlog相关目录: /hbase/WALs (存储当前还未过期的日志) 、/hbase/oldWALs(存储已经过期的日志)
查看 Hlog : bin/hbase hlog 根据提示指定参数查看
5.2.3 Hlog生命周期
Hlog不会永久存储在系统中,完成使命后,就会失效 最终删除。如图:
HLog构建 ---> HLog滚动 ---> HLog失效 ---> HLog删除
(1)构建:任何的写入操作都会先将记录追加写入到Hlog
(2)滚动:每隔一段时间(默认一小时)进行日志滚动,生成新的日志文件。主要方便过期的日志数据能够以文件的形式直接删除
(3)失效:数据一旦从Memstore中罗盘,对应的日志数据就会失效,然后从 WALs文件夹移动到oldsWALs文件夹 (此时Hlog并没有被删除)
(4)删除:每隔一段时间(默认一分钟)检查一次oldWALs下失效的日志文件,确认是否可以删除
删除条件:
①该HLog是否还在参与主从复制
②该HLog是否在oldWALs目录中存在10分钟
5.3 MemStore
MemStore 写缓存。
使用JDK自带的ConcurrentSkipListMap,保证数据的写入、插入、删除操作都在O(logN)的时间复杂度,且线程安全。
5.4 HFile
MemStore中的数据落盘后形成一个文件写入HDFS,这个文件称为HFile。三个版本 V1 V2 V3
MemStore中数据落盘之后会形成一个文件写入HDFS,这个文件称为HFile。
逻辑结构图:
HFile文件主要分为4个部分:Scanned block部分、Non-scanned block部分、Load-on-open部分和Trailer。
Scanned Block:这部分主要存储真实的KV数据,包括Data Block、Leaf Index Block和Bloom Block。
Non-scanned Block:这部分主要存储Meta Block,这种Block大多数情况下可以不用关心。
Load-on-open:主要存储HFile元数据信息,包括索引根节点、布隆过滤器元数据等,在RegionServer打开HFile就会加载到内存,作为查询的入口。
Trailer:存储Load-on-open和Scanned Block在HFile文件中的偏移量、文件大小(未压缩)、压缩算法、存储KV个数以及HFile版本等基本信息。Trailer部分的大小是固定的。
HFile 物理结构
HFile文件由各种不同类型的Block(数据块)构成,虽然这些Block的类型不同,但却拥有相同的数据结构。
HBase中定义了8种BlockType,每种BlockType对应的Block都存储不同的内容。
核心BlockType如下表
5.5 BlockCache
尽可能将热点数据存储到内存中,与避免昂贵的IO开销,是提升数据库读取性能的一个核心方法
Hbase也实现了读缓存——BlockCache,客户端读取某个block,首先会检查该block 是否存在于Block Cache,如果存在就直接加载,
如果不存在就去Hfile加载,加载后 放到 Block Cache
BlockCache 主要用来缓存Block,Block是HBase中最小的数据读取单元,即从HBase读取都是以Block为最小单位的
BlockCache 是RegionServer级别的,一个RegionServer只有一个BlockCache
BlockCache的初始化工作是在RegionServer启动是完成的
Hbase 实现了三种BlockCache: LRUBlockCache 、SlabCache 、 BucketCache
5.5.1 LRUBlockCache
LRUBlockCache 是Hbase默认的BlockCahce机制, 使用一个ConcurrentHashMap 管理BlockKey 到 Blcok 的映射关系
缓存Blcok 只需要将BlockKey 和 对应的Blcok 放入HashMap中,查询缓存就根据BlockKey从HashMap中获取即可。
同时 该方案采用LRU淘汰算法, 当Blcok Cache总量到达一定的阈值后就会启动淘汰机制,最近最少使用的Blcok会被置换出来。
缺点
LRUBlockCache使用JVM提供的HashMap管理缓存,随着数据从single-access区 晋升到 multi-access区 或者长期停留在single-access区
对应的内存对象会从young区晋升到old区,晋升到old区的Block淘汰后会变为内存垃圾。 所以LRUBlockCache算法会带来大量的内存碎片,最后产生
Full GC。一次 Full GC 会持续较长时间,甚至分钟级别,Full GC 会将整个进程暂停,必然会极大的影响业务的正常读写请求。
5.5.2 SlabCache
SabCache方默认情况下jvav nio DirectByteBuffer技术实现堆外内存存储,不再由JVM管理数据内存。
LRUBlockCache相同,SlabCache也使用LRU算法淘汰过期的block
LRUBlockCache不同的是,SlabCache淘汰Block时只需要将对应的bufferBytes标记为闲,后续cache 对其上的内存直接进行覆盖即可
HBase 在实际实现中将SlabCache和LRUBlockCache搭配使用,称为DoubleBlockcacne。
经过实际测试,DoubleBlockCache方案有很多弊端。比如,SlabCache中固定大小内存设置会导致实际内存使用率比较低,
而且使用LRUBlockCache缓存Block依然会因为JVW产生大量内存碎片。因此在HBase 0.98版本之后,已经不建议使用该方案。
5.5.3 BucketCache
站在SlabCache的肩膀上,社区工程师开发了另一种非常高效的缓存方案——BucketCache。
BucketCache 通过不同配置方式可以工作在三种模式下:heap, oftheap和 file。
heap:表示这些Bucket 是从 JVM Heap中申请的;
offheap:使用DirectByteBuffer技术习堆外内存存储管理;
file:使用类似ssD的在储介质来缓在Data Block。
无论工作在那种模式下,BucketCache都会申请许多带有固定大小标签的Bucket,
和SlabCache一样,一种 Bucket 存储一种指定BlockSize的Data Block,
但和SlabCache不同的是,BucketCache会在初始化的时候申请14种不同大小的Bucket,
且如果某一种Bucket空间不足,系统会从其他 Bucket空间借用内存使用,因此不会出现内存使用率低的情况。
实际实现中,HBase 将 BucketCache和LRUBlockCache搭配使用,称为CombineCache。
和 DoubleBlockCache不同,系统在LRUBlock Cache中主要存储IndexBloc和Eomick.而将 Data Block在储在BucketCache中。
因此一次随机读需要先在LRUBocCaeke中查到对应的Index Block, 然后再到BucketCache查找对应DataBlock。
修正了SlabCache的弊端,极大降低了JVM GC对业务请求的实际影响,
但其也存在一些问题。比如,使用堆外内存会存在拷贝内存的问题,在一定程度上会影响读写性能。