导图社区 Hbase基础理论及进阶优化学习笔记
系统化的梳理Hbase整个知识点,从写过程、架构、物理存储、读过程等方面进行了分析和概述,需要可收藏。
编辑于2022-01-04 14:49:52Hbas
架构
client职责
访问zk,获取root表位置并访问,获取.meta表信息并访问,访问用户表信息,client端缓存meta表信息
Zookerper职责
1. 为Hbase提供FailOver机制,选举master,避免master单点故障
2. 存储所有region的寻址入口,root表、meta表表在哪台机器上,位置信息
3. 实时监控RegionServer信息,将regionServer上下线信息实时通知master
4. 存储Hbase的schema信息,包括有哪些table,每个table上有哪些columnFamily
Master职责
1. 为regionServer分配region
2. 负责regionServer的负载均衡
3. 发现失效的regionServer并重新分配region
4. 清理HDFS上失效的hbase相关文件
5. 处理schema的更新(表的创建,删除,修改,列簇的增加)
ReginServer职责
1. 维护master分配的region,处理region的IO请求
2. 负责split过大的region,执行compact操作
物理存储
1. table中所有的行都按照rowkey的字典序排列
2. table在行的方向上分割为多个HRegion
3. HRegion按大小分割,初始默认10G,每个表只有一个(预分区除外),随着数据不断插入,HRegion不断增大,到一个阈值会split
4. HRegion是Hbase中分布式存储和负载均衡的最小单元,一个HRegion不会拆分到多个RegionServer上
5. HRegion由一个或多个store构成,每个store保存一个columnFamily,每个store由一个memStore和0至多个storeFile组成
读过程
1. client访问zk,获取root表及.meta表所在位置,访问获取数据所在regionServer
2. 请求reginServer查询数据
3. regionServer查询相关store的memStore(写缓存)和blockCache(读缓存),命中则返回
4. memStore和blockCache中找不到则扫描storeFile,扫描时通过BloomFilter判断该rowkey是否在该storeFile中,BloomFilter有一定误判率
5. 将数据缓存到blockCache,使用LRU机制按不同cache等级分不同队列,分别淘汰数据 cache大小默认是4G ,38%的Hbase Heap Size
拓展
columnFamily的block缓存等级有三种
InMemory 常驻memory
Single 被访问一次的block
Multi 被访问不止一次的block
compact
原因
storeFile是只读的,创建后不可更新(3层B+树),Hbase的更新是追加的。当一个store中的storeFile达到一定阈值的时候,会进行一次合并,将对一个rowkey的操作合并至一个storeFile,当storeFile的大小达到一定阈值后,又会对storeFile进行split,等分为两个storeFile。
分类
minor_compact
仅合并小文件 Hfile
major_compact
合并region内所有文件
过程
读取store内所有的storeFile和memStore,按照rowkey进行合并
写过程
1. 根据rowkey查找regionServer,.META.存储了每一个region的起始rowkey
2. 向regionServer提交写请求
3. regionServer找到对应目标region
4. region检查数据是否和schema一致
5. 如果客户端没有指定数据版本在,则获取当前系统是时间为数据版本
6. 将更新写入memStore
1. 数据写入WAL log(Hlog) 预写内存,每秒由logSync线程刷写磁盘,有丢失数据风险
2. 写入memStore(2层B+树)
3. memStore是排序的,写入达到一定阈值,会flush生成新的storeFile
4. 老的memStore添加到队列,由单独的线程flush生成storeFile,Hlog被移到新目录默认保存两天,然后物理删除
5. ZK中记录一个redo point用于意外情况下执行恢复
7. 判断memStore是否需要flush为一个storeFile 最大64Mb
Hbase优化
表设计
1. 预分区
2. rowkey设计,可以是任意字段串,最大64KB,一般10~100bytes
(1). 越短越好,提高效率
Hfile是按照keyValue存储,rowkey会占用较大空间
缓存结果存储在内存,rowkey过长会降低内存利用率,降低检索效率
(2). 散列原则-实现负载均衡
如果rowkey按时间戳递增,高位需要存储散列字段,如果没有散列,可使用加盐,hash,反转等方式生成
(3). 唯一原则-字典序排序存储
设计上必须保证唯一性,将经常需要读取的数据存储到一块
3. 列簇的设计
不要在一张表里定义太多的columnFamily,因为某个CF在flush时因为关联效应,临界的CF也会因为关联效应被触发flush,最终导致系统产生更多的IO
flush操作是region级别的,所以一个memstore被flush,其他memstore也会
多个CF数据量相差悬殊时,split操作会导致数据量小的CF的HFile被进一步切分成小文件
compaction也是region级别的,过多的列簇也会有更多的IO
HDFS底层对一个目录下的文件数是有限制的,列簇过多文件会翻倍
4. in memory
Hbase的LRU缓存采用分层设计
InMemory 常驻memory
Single 被访问一次的block
Multi 被访问不止一次的block
5. max version
6. Time to live
7. compaction
minor compaction
合并较少的小文件
I. hbase.hstore.compaction.min(默认值3)
至少需要3个满足条件的storeFile,minor compaction才会启动
II. hbase.hstore.compaction.max(默认值10)
一次minor compaction最多选取10个storeFile
III. hbase.hstore.compaction.min.size
storeFile size大于该值的文件一定会加入minor compaction
IV. hbase.hstore.compaction.max.size
storeFile size大于该值的文件一定不会加入minor compaction
V. hbase.hstore.compaction.ratio(默认值1.2)
storeFile按年龄排序,总是从older File开始选择,如果该文件的size小于后面 hbase.hstore.compaction.max个文件size之和乘以ratio,那么该file会加入minor compaction
major compaction
将所有storeFile合并为一个
手动触发
major compact 命令
majorCompact() API调用
regionServer自动执行
hbase.hregion.majorcompaction (默认24h)
hbase.hregion.majorcompaction.jetter (默认值0.2)防止同一时间触发,范围内浮动
写优化
1. 是否需要WAL,关闭WAL可以提升2~3X,异步WAL可以提升1~2X
2. put优化
put是否可以使用批量提交
put是否可以使用异步提交
setAutoFlush(false)
3. region是否太少
4. 写入请求是否不均衡
5. 写入keyValue数据是否太大
6. WAL放置到SSD (hdfs 2.6.0+)
7. mulitiple WALS,将regionSever级WAL设置为nameSpace级,提升0.2~0.4X
读优化
1. scan缓存设置是否合理
2. get是否可以批量操作
3. 离线批量读取请求设置禁用缓存,读请求的数据进入缓存后会挤占掉热点数据,导致其他业务需要从HDFS加载,造成读延迟
4. 读请求是否均衡
5. BlockCache设置是否合理
JVM内存配置<20G,使用默认的 LRUBlockCache,否则使用BucketCache
LRUBlockCache
hfile.block.cache.size.LRUBlockCache(默认0.4) 表示cache占用heap大小
Memstore+BlockCache的内存占比不能超过0.8 (hbase.regionserver.global.memstore.size+hfile.block.cache.size<=0.8)
LRUBlockCache 完全基于JVM heap的LRU的方案 (弊端产生原因,对象越来越,一定会产生fullGc)
三段式缓存
single-access占用25%
multi-acsess占用50%
in-memory占用25%
CombineBlockCache(LRUBlockCache+BucketCache)
LRUBloackCache缓存 Index / Bloom Block
BucketCache缓存 Data Block
BucketCache
Bucket三种工作模式 (hbase.bucketcache.ioengine)
heap
Bucket 从JVM heap中申请
offheap(默认)
从堆外内存申请
file
从类似SSD高速缓存文件系统申请
工作原理
开始启动 BucketCache 会申请许多带有固定大小标签的Bucket (大小上限为最大尺寸的Block * 4),超过最大size的Block无法缓存
通过 BucketAllocator 为 Block寻找一个 Bucket,Bucket的序号和offset与Block的物理序号和offset形成映射
相同size的Bucket由同一个BucketSizeInfo管理
Bucket的size标签可以动态调整,某个size的Bucket用完后,其他size的空闲Bucket可以生成该size的Bucket,但至少保留一个原size大小的Bucket,同时触发Block淘汰
配置项
hbase.bucketcache.ioengine
hbase.bucketcache.combinedcache.enabled(默认true)
hbase.bucketcache.size
0.0~1.0 代表堆内存百分比
>1 代表实际值 单位Mb
6. HFile是否过多
compaction策略
7. Compaction是否太频繁,消耗系统资源
hbase.hstore.compaction.min 不能太小
hbase.hstore.compaction.max 不能太大
8. 数据本地率是否太低
HRegion与DataNode的关系,本地率太低会产生大量的网络IO请求,导致读延迟,数据本地率低的原因一般是region迁移
避免无故region迁移
关闭自动balance
RS宕机后迁回飘走的region
业务低峰期执行major compaction
LSM
I. RegionScanner会根据列簇构建StoreScanner
1. 为每一个HFile构建一个StoreFileScanner,,为memStore构建MemStoreScanner
2. 过滤淘汰的StoreFileScanner,根据Time Range以及Rowkey Range对StoreFileScanner和MemStoreScanner进行过滤
3. Seek key
1| 定位block offset,在BlockCache中读取该HFile的索引树结构,根据索引树,检索对应的Rowkey所在的Block offset和BlockSize
2| load Block,根据上一步的Block offset从Block Cache中查找Data Block(64KB),如果不在缓存再在HFile中加载
3| 在Data Block中使用二分查找,找到Rowkey
4. StoreFileScanner合并构建最小堆,将所有scanner合并形成一个heap,heap是一个优先级队列,元素是scanner,排序规则按每个scanner seek到的keyValue由小到大排列
a. 由小到大 scan效率最高
b. KeyValue是一个特殊的结构,包含keyType(Put/Delete/……)
c. keyValue比大小,rowkey>columnFamliy>Qualifier>TimeStamp>KeyTpye(Delete Famliy>Delete column>Delete>Put)
II. heap堆内的各个scanner,返回对应rowkey的记录,同时指针下移(方便scanner下一个对应rowkey)
III. LSM树和B+树相比,LSM树牺牲了部分读性能,用来大幅提高写性能