《HBbase原理与实践》读书笔记

第五章 RegionServer的核心模板

RegionServer 是HBase 的最核心组件,主要负责 用户数据的读写等IO操作。

一个RS由默认由一个HLog、一个BlockCache 以及多个Region组成。 

一个Region由一个 多个store 组成 (有多少column 就有多少 store)

一个store 由 一个MemStore 和 多个Hfile 组成, Hfile存放在HDFS上面

5.1 RegionServer的内部结构

    内部结构图如下:

hbase基本操作实验报告_大数据

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。
    
    逻辑结构图:

hbase基本操作实验报告_hbase基本操作实验报告_02

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 物理结构

hbase基本操作实验报告_hbase_03

HFile文件由各种不同类型的Block(数据块)构成,虽然这些Block的类型不同,但却拥有相同的数据结构。
    
    HBase中定义了8种BlockType,每种BlockType对应的Block都存储不同的内容。
    
    核心BlockType如下表

hbase基本操作实验报告_数据库_04

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对业务请求的实际影响,

            但其也存在一些问题。比如,使用堆外内存会存在拷贝内存的问题,在一定程度上会影响读写性能。