irpas技术客

HBase的regionServer_ligen1112_hbase region server

irpas 2784

RegionServer核心模块

RegionServer后面简称rs,是比较核心的模块,数据写入读取的基础组件。rs包含HLog,MemStore,HFile和BlockCache。

1. RS内部结构

HLog用来保证数据写入的可靠性,BlockCache读缓存,一个strore是一个列族,memstore是写缓存,数据达到阈值直接落盘HFile, HFile按照rowkey排序,文件之间异步会进行多路归并(LSM结构)。

1.1 HLog

所有写操作先追加写入HLog再写入memstore。rs挂了,memstore是内存里面的concurrentSkipMap,数据直接就没了,HLog是落在HDFS的,可以用来数据恢复。

Hlog是多个region共享的,日志每个单元是行级更新单元,HLogKey+WALEdit。HLogKey由表名,region,sequenceId,时间等信息组成 HLog生命周期:构建 -> 滚动新建->(mem flush后)失效移到oldWAL-> oldWAL下面文件过了TTL删除。

sequenceID干啥用的?

每个region的操作都顺序自增sequenceID,存在了HLogKey里面,sequenceID操作flush到hfile后会有标记,还没flush的操作序号最小的变成oldestUnflushedSequenceId,当一个Hlog里面所有的region,sequceID都小于相应的oldestUnflushedSequenceId,说明这个HLog可以删掉了。同理rs挂了,每个region从相应的oldestUnflushedSequenceId开始恢复

1.2 Memstore

rs里面每个列族一个memstore,memstore刷写的这种lsm结构有如下优点

随机io写入变成顺序io写入(写HLog) + 内存写入,写入性能好HFile排序在memstore完成,直接刷写memstore缓存最新写入数据,直接内存读取的概率更大memstore刷写前可以灵活处理KV,比如只保留一版数据,memstore里的老版本直接干掉

memstore高效读写,用concurrentSkipMap,在O(logN)时间复杂度完成增删查。底层采用CAS原子操作,提升性能。

memstore的GC问题,多个region的memtore共用rs的内存,比如下图region 1落盘以后产生的白色部分会继续写入,长时间后,条带越来越窄,甚至无法分配足够内存出来给大的对象,触发Full GC 这里memstore使用了顺序化内存分配,内存数据分块等使得碎片更加粗粒度。 每个memstore申请一个2M的chunk数组同时维护偏移量,kv来了就放进去同时偏移量移动kv.length,不够用了就申请下一个chunk,每个2MB都是由一个memstore里面的对象填充,这个据官方实验降低了full GC的频率。 chunk循环利用也可以避免jvm回收chunk(kafka生产者的内存池也是这个思路),因此

创建chunkpool管理未使用的chunk,防止回收chunk没有使用就进入poolchunkpool有一定大小限制,如果还有余力就会分配新增的chunk需求

chunk大小默认是2MB,开启的。chunkpool需要自己开启。

1.3 HFile

scanned block : 顺序扫描的地方,存储数据的地方,leaf index block是索引书叶子节点,bloomblock是布隆过滤器non-scanned block : 顺序扫描不会扫到的地方load on open : 打开hfile时候加载到内存,各种元数据trailer : 记录了偏移值

每种block都有blockheader和blockdata

block有8种

1.3.1 trailer block

这个部分似曾相识,orc结构也是这样。这种块大小是固定的。加载后解析出hfile的压缩算法,kv数量等信息,load-on-open部分的偏移量并根据偏移量加载。

1.3.2 Data Block

rowkey结构前面说过了,hbase排序的依据。从这可以看出,rowkey,列族,列等在每条数据都占用了位置,因此越短越好。

1.3.3 bloomblock

lsm特性,hbase写性能好,读差点,因此每个hfile都整一个布隆过滤器,加载到内存,滤过一些无结果rowkey查询。新版本hbase把布隆过滤器页拆分了,多个bloom block 按照 bloom index block进行拆分

bloom index block结构,先根据rowkey二分查找定位相应bloom block,再根据offset和szie搞到bloom block。 bloom index block的元信息包括hash函数的信息。

1.3.4 HFile的多级索引

随着数据量增多,hfile的索引会由一层变为二层三层。

上图最根上的是root index clock,Mid开头的记录MidKey用以切分HFile。index entry里面有index的第一个key

上图Nonroot index clock,entry偏移量记了,所以可以用二分法找index entry

hbase hfile -m /hbase/data/default/extra_info/1fe15081622f29d8050e9852e946d480/info/84f397d181aa45dea740f733a94c4e1c Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release 22/02/22 21:22:12 WARN impl.MetricsConfig: Cannot locate configuration: tried hadoop-metrics2-hbase.properties,hadoop-metrics2.properties 22/02/22 21:22:12 INFO impl.MetricsSystemImpl: Scheduled Metric snapshot period at 10 second(s). 22/02/22 21:22:12 INFO impl.MetricsSystemImpl: HBase metrics system started 22/02/22 21:22:12 INFO metrics.MetricRegistries: Loaded MetricRegistries class org.apache.hadoop.hbase.metrics.impl.MetricRegistriesImpl Block index size as per heapsize: 229024 reader=/hbase/data/default/extra_info/1fe15081622f29d8050e9852e946d480/info/84f397d181aa45dea740f733a94c4e1c, compression=none, cacheConf=CacheConfig:disabled, firstKey=Optional[001OI202010144774496580667441152/info:create_time/1639475327647/Put/seqid=0], lastKey=Optional[002OI202110305906839144627429376/info:user_name/1639475328280/Put/seqid=0], avgKeyLen=57, avgValueLen=10, entries=1565507, length=120660499 Trailer: fileinfoOffset=120655695, loadOnOpenDataOffset=120546138, dataIndexCount=1833, metaIndexCount=0, totalUncomressedBytes=120514235, entryCount=1565507, compressionCodec=NONE, uncompressedDataIndexSize=109459, numDataIndexLevels=1, firstDataBlockOffset=0, lastDataBlockOffset=120486953, comparatorClassName=org.apache.hadoop.hbase.CellComparatorImpl, encryptionKey=NONE, majorVersion=3, minorVersion=3 Fileinfo: BLOOM_FILTER_TYPE = ROW DELETE_FAMILY_COUNT = 0 EARLIEST_PUT_TS = 1639475327646 KEY_VALUE_VERSION = 1 LAST_BLOOM_KEY = 002OI202110305906839144627429376 MAJOR_COMPACTION_KEY = true MAX_MEMSTORE_TS_KEY = 0 MAX_SEQ_ID_KEY = 858 TIMERANGE = 1639475327646....1639475331337 hfile.AVG_KEY_LEN = 57 hfile.AVG_VALUE_LEN = 10 hfile.CREATE_TIME_TS = 1639933791744 hfile.LASTKEY = 002OI202110305906839144627429376/info:user_name/1639475328280/Put/vlen=0/mvcc=0 Mid-key: Optional[001OI202109225792116//LATEST_TIMESTAMP/Maximum/seqid=0] Bloom filter: BloomSize: 270336 No of Keys in bloom: 223644 Max Keys for bloom: 225443 Percentage filled: 99% Number of chunks: 3 Comparator: ByteArrayComparator

avgKeyLen和avgValueLen代表kv长度,由于block(64KB内部)是顺序读,因此kv长度很小block就会装很多影响性能,这种情况要把blocksize设小点。

1.4 blockcache

提升读性能一般是将热点数据缓存。hbase读缓存blockcache,每个re一个blockcache,每次读先去blockcache找,没有去hfile找,找得到数据所在的block缓存起来。有三种:默认LRUBlockCache,SlabCache,BucketCache

LRUBlockCache ConcurrentHashMap,key是BlockKey,v 是block。总量达到阈值就会淘汰是用最少的block。HBase采用多层缓存设计。建表时候可以指定列簇in_memory,但是要谨慎,如果太大了会影响元数据(hbase:meta,hbase:namespace都在内存中)。每层使用最少的block都会被淘汰。JVM自身的内存管理会产生碎片。

slabcache和BucketCache 都是自己管理block,是用新block覆盖旧的,省得JVM自己去回收。但是slabcache是固定两种大小,LRUBlockCache是十几种大小的bucket而且可以互相借用空间。

hbase现在是LRUBlockCache + BucketCache, 前者放index block和bloom block,后者放datablock


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #HBase #Region #Server #rs包含HLog #Memstore #1