一、架构
Hbase的是主从架构,通过zookeeper来保证高可用
Hbase的存储机构是LSM
数据—①—>内存—②—>小文件—③—>大文件
①:Hbase采用了WAL预写日志,保证写内存的数据不丢失,载体是Hlog
之后就把写的数据写到内存里
②:当内存的数据量达到一定的程度后,会将数据写到磁盘中,载体是HFile,并且采用B+树的存储结构
③:在小文件达到一定的数量后,会触发compact,此时会合并小文件成大文件
(生产环境下大合并会尽量避开使用高峰)
二、操作流程
读数据流程
Client—①—>Zookeeper—②—>HRegionServer1 —③—>HRegionServer2
—④—>MemStore—⑤—>BlockCache—⑥—>StoreFile—⑦—>key-value
①:从Zookeeper读取meta表位于哪台HRegionServer上
②:去①获取的HRegionServer中查询meta表
(根据命名空间、表名以及rowkey定位数据所存储的Region以及Region所处的服务器)
③:根据②获取的信息访问目标HRegionServer
④:在目标HRegionServer的目标Region里的MemStore查询
⑤:若④没找到,则在BlockCache中查询
⑥:所⑤没找到,则在目标Region里的StoreFile中查找
⑦:若是⑥找到了,则将数据存储在BlockCache中并根据版本组织key-val返回
写数据流程
Client—①—>Zookeeper—②—>HRegionServer1—③—>HRegionServer2
—④—>HLog—⑤—>MemStore—⑥—>StoreFile
①:从Zookeeper读取meta表位于哪台HRegionServer上
②:去①获取的HRegionServer中查询meta表
(根据命名空间、表名以及rowkey进行Hash,确定数据应该存储的Region,并且返回该Region的服务器信息)
③:去②返回的服务器进行数据写入
④:将写入操作先记录在磁盘HLog中(WAL 存储在HDFS)
⑤:再将实际的数据写到目标Region的目标Store里的MemStore中
⑥:当MemStore满足条件后刷写磁盘StoreFile(存储在HDFS)并删除HLog
⑦:StoreFile在满足一定条件下进行compact
三、机制
1. Flush
原因:
存储在MemStore中的数据变多后,不仅持有太多的内存资源,而且对数据恢复也不好,因此会将MemStore中的数据刷写到磁盘文件StoreFile中
flush流程
- prepare阶段:遍历当前Region的所有MemStore,将每一个MemStore中的数据集CellSkipListSet做一个快照;再新建一个CellSkipList给后期数据的写入
这个阶段会加updateLock对写请求阻塞,该阶段比较快 - flush阶段:遍历所有MemStore,将prepare生成的快照转为临时文件,该阶段涉及到写磁盘,比较耗时
- commit阶段:遍历所有MemSore,将flush阶段生成的临时文件转到指定的ColumnFamily目录下,然后将其添加到HSore的storefile列表中,最后清空prepare产生的快照
刷写的条件分为⑥种,满足任意一种都会触发
① MemStore级别
Region中任意MemStore大小达到上限 hbase.hregion.memstore.flush.size,默认128MB
触发:是单个MemStore刷写还是该Region中所有的MemStore刷写
② Region级别
当Region中所有的MemStore占有资源达到上限
hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size,默认 2* 128M = 256M
③ Server级别
当Region Server上所有Region资源超过低水位阈值
低水位阈值:低水位百分比 * RegionServer分配的MemStore资源
低水位百分比:hbase.regionserver.global.memstore.size.lower.limit
(默认95%)
RegionServer的MemStore资源:hbase.regionserver.global.memstore.size
(默认jvm40%)
按照占用资源数量从大到小依次flush Region
如果写入速度大于flush速度,导致占用的资源到达RegionServer分配的MemStore资源,会阻塞Region Server的写入直到资源占用小于低水位阈值
④ HLog数量过多
当HLog的数量达到hbase.regionserver.maxlogs
设置的值后,会将最早的HLog对应的Region进行flush,之后删除该HLog
⑤ 定期Flush
默认周期为1小时,确保Memstore不会长时间没有持久化
为避免所有MemStore同时flush导致的问题,定期的flush操作有20000左右的随机延时
⑥ 主动触发
通过命令flush tablename
或者flush regionname
分别对一个表或者一个Region进行flush
问题:
每一次刷写文件都是新的一个StoreFile吗
2. Compact
原因:
由于每次MemStore满足条件都会刷写磁盘文件Store,并且由于Region不同或Region内部的Store不同,会刷写不同的StoreFile,因此会产生大量的小文件。
影响查询效率以及系统性能
① minor compaction
- 将部分较小/相邻的HFile合并成更大的HFile
- 标记超过TTL、更新、删除的数据
② major compaction
- 合并一个Store中的所有HFile为一个HFile
- 清理超过TTL、更新/删除、以及无效版本号的数据
3. 预分表
表创建的时候,只会默认给它生成一个Region,因此数据可能会全部写到该Region所处的那个Region Server上,导致负载不均衡
分区的好处
- 增加数据读写效率
- 负载均衡
- 方便集群容灾调度Region
- 优化Map数量
分区的原理:每个Region都有一个startRowKey和endRowKey,若读写数据rowKey落在该范围,则读写该Region
4. Region合并
原因:
当删除大量的数据之后,可能会导致很多小的Region,此时最好进行合并
合并Region并不能带来的性能的提升,只是方便管理
四、小结
- 相同列簇的列会存储在同一个文件里面(加速按行读取操作),在Region的一个StoreFile里
- rowkey不建议太长,Hbase的存储是细化到了 rowkey—>每个单元格。rowkey太大影响性能
- HBase按照rowkey进行查找,要查找的字段尽量放到rowkey里。rowkey可能会导致数据热点,rowkey根据字典序排序
- HBase适合OLAP应用
- 遗留问题:分布式组件都是怎么解决哈希映射的问题呢?