Flink系列暂时停更一段时间,关于并行度机制 ,TaskManager的数据交换机制,以及flink standalone以及yarn的远程启动流程之后有时间会开篇章讲解。
对于Hbase而言,因为目前这个存储组件并没有涉及到可以二开的地方,所以Hbase系列会围绕官方文档,以及基本架构和常见问题的原理进行讲解
参考文章:developer.ibm.com/zh/technolo…
Hbase基本结构
个人架构图: www.processon.com/view/link/6…
1. 每个RegionServer拥有一个或多个HLog。(默认一个,1.1版本可开启MultiWAL功能,允许多个HLog)
2. 每个HLog多个Region共享。
3. 日志单元WALEntry表示一次行级更新的最小追加单元,由HLogKey和WALEdit两部分组成。
4. WALEdit表示一个事务中的更新集合。
0.94之前版本中,如果一个事务对一行rowR三列c1,c2,c3分别做了修改,那么HLog会有3个对应的日志片段,无法保证行级事务的原子性,假如RegionServer更新c2列之后发生宕机,那么一行记录中只有部分数据写入成功:
<logseq1-for-edit1>:<keyvalue-for-edit-c1>
<logseq2-fot-edit2>:<keyvalue-for-edit-c2>
<logseq3-for-edit3>:<keyvalue-fot-edit-c3>
0.94之后版本,将一个行级事务的写入操作表示为一条记录,其中WALEdit会被序列化为格式<-1, # of edits,,,>:
<logseq#-for-entire-txn>:<WALEdit-for-entire-txn>
<-1, 3, , , >, -1为标识符,表示新的日志结构
HLog生命周期
个人结构图 www.processon.com/view/link/6…
MemStore
MemStore Flush产生内存条带
- 不同Region的数据在JVM Heap中是混合存储的。
- Region1执行flush后,该内存被释放,变成Free Space,继续为写入MemStore的数据分配空间,进而分割成更小的条带。
- 随着MemStore中数据的不断写入并flush,整个JVM将会产生大量越来越小的内存条带,即内存碎片。
- 随着内存碎片越来越小,最后甚至分配不出来足够大的内存给写入对象,此时会触发JVM执行Full GC合并这些内存碎片。
个人结构图: www.processon.com/view/link/6…
MSLAB(MemStore本地分配缓存)
- 在RegionServer JVM启动参数中加上-xx:PrintFLASStatistics=1,打印每次GC前后内存碎片的统计信息,统计维度:
- Free Space – 老年代当前空闲的总内存容量
- Max Chunk Size(重点) - 老年代中最大的内存碎片所占的内存容量大小
- Num Chunks - 老年代中总的内存碎片数
个人结构图:www.processon.com/view/link/6…
HFile
HFile 逻辑结构图:www.processon.com/view/link/6…
HFile V2物理结构图
HFile Block
Trailer Block
Data Block
Bloom Index Block
| 一次GET请求,根据布隆过滤器进行过滤查找,步骤: 1)根据待查Key在Bloom Index Block所有的索引项中根据BlockKey进行二分查找,定位对应的Bloom Index Entry; 2)根据Bloom Index Entry中BlockOffset及BlockOndiskSize加载对应的位数组; 3)对Key进行Hash映射,查看位数组相应位置是否为1,不是则表示不存在该Key,否则只是有可能存在该Key。 |
一次GET请求,根据布隆过滤器进行过滤查找,步骤:
- 根据待查Key在Bloom Index Block所有的索引项中根据BlockKey进行二分查找,定位对应的Bloom Index Entry;
- 根据Bloom Index Entry中BlockOffset及BlockOndiskSize加载对应的位数组;
- 对Key进行Hash映射,查看位数组相应位置是否为1,不是则表示不存在该Key,否则只是有可能存在该Key。
HFile文件索引
Block & NoneRoot Index Block
查看HFile元数据
# 查看HFile元数据
# hbase hfile -m -f /hbase/data/default/mytable/c606b6c02a3f6b51192988432afe38bc/colfam1/e40c31de97ff47aeb27d84a4ca59f7c8
2020-05-20 14:20:59,865 INFO [main] hfile.CacheConfig: Created cacheConfig:
CacheConfig:disabled
Block index size as per heapsize: 392
reader=/hbase/data/default/mytable/c606b6c02a3f6b51192988432afe38bc/colfam1/e40c31de97ff47aeb27d84a4ca59f7c8,
compression=none,
cacheConf=CacheConfig:disabled,
firstKey=r/colfam1:q/1565781611071/Put, # 在scan时可通过startkey和stopkey优化性能
lastKey=r2/colfam1:q2/1565781667630/Put,
avgKeyLen=22, # 文件中所有KeyValue的平均Key长度;如果相对较小,可将Block适当调小(如32KB),避免Block内有太多KeyValue数,导致顺序扫描定位KeyValue时会增大块内延迟时间。
avgValueLen=1,
entries=3,
length=4975
Trailer:
fileinfoOffset=289,
loadOnOpenDataOffset=181,
dataIndexCount=1,
metaIndexCount=0,
totalUncomressedBytes=4884,
entryCount=3,
compressionCodec=NONE,
uncompressedDataIndexSize=34,
numDataIndexLevels=1,
firstDataBlockOffset=0,
lastDataBlockOffset=0,
comparatorClassName=org.apache.hadoop.hbase.KeyValue$KeyComparator,
encryptionKey=NONE,
majorVersion=3,
minorVersion=0
Fileinfo:
BLOOM_FILTER_TYPE = ROW
DELETE_FAMILY_COUNT = 0
EARLIEST_PUT_TS = 1565781611071
KEY_VALUE_VERSION = 1
LAST_BLOOM_KEY = r2
MAJOR_COMPACTION_KEY = false
MAX_MEMSTORE_TS_KEY = 8
MAX_SEQ_ID_KEY = 10
TIMERANGE = 1565781603186....1565781667630
hfile.AVG_KEY_LEN = 22
hfile.AVG_VALUE_LEN = 1
hfile.CREATE_TIME_TS = 1565785277850
hfile.LASTKEY = r2/colfam1:q2/1565781667630/Put/vlen=0/mvcc=0
# Hfile V3存储cell标签数据
MAX_TAGS_LEN = 22 # 单个cell中存储标签的最大字节数
TAGS_COMPRESSED = true # 是否针对标签进行压缩处理
Mid-key: \x00\x01r\x07colfam1q\x00\x00\x01l\x8F\xDBR?\x04
Bloom filter:
BloomSize: 8
No of Keys in bloom: 3
Max Keys for bloom: 6
Percentage filled: 50%
Number of chunks: 1
Comparator: RawBytesComparator
Delete Family Bloom filter:
Not present
BucketCache
BucketCache内存结构
BucketCache标签
BucketSize大小总比Block本身大1KB,是因为Block不是固定大小,总会比64K更大一些;
默认标签:(4+1)K, (8+1)K, (16+1)K, (48+1)K,
(56+1)K, (64+1)K, (96+1)K,…(512+1)K;
启动HBase时,系统先从小到大遍历一次所有size标签,
为每类标签分配一个Bucket,最后所有剩余的Bucket都分配最大的size标签,默认分配(512+1)K。
Bucket的size标签可以动态调整:64KB的Block比较多,
65K的Bucket用完后,其它size标签的完全空闲的Bucket可以转换成65K的Bucket,
但是会至少保留一个该size的Bucket。
BucketCache中Block缓存写入及读取流程
HDFS文件检索Block
HDFS Block为128M:
HDFS主要存储大文件,当数据量大到一定程度,如果Block太小会导致Block元数据(Block所在DN位置、文件与Block之间对应关系等)非常庞大。
HDFS元数据都存储在NN上,大量元数据容易让NN成为整个集群的瓶颈。
因此,HDFS Block从最初的64M增加到128M。
HBase Block为64K:
HBase的缓存策略是缓存整个Block,如果Block设置太大会导致缓存很容易被耗尽,尤其对于很多随机读业务,设置Block太大会让缓存效率低下。