Hbase¶
HBase是什么¶
Hbase是一个建立在Hadoop上的分布式列式存储数据库,它用于存储非结构化和半结构化的大规模数据,并提供了实时的数据访问能力
HBase的底层架构¶
为什么项目中要用HBase¶
实时数仓中为什么维度表数据要用Hbase存储
- 事实表需要通过主键获取一行维表信息,要求维表永久存储和主键查询
- 有读写缓存
- 主键对应Hbase的Rowkey,Hbase会对RowKey加索引且排序,查询效率较高
- 加索引且排序在哪进行
- 都是自动进行
- 排序在数据写入memstore进行
- 加索引在刷写进HFile时, 写入到HFile的数据块索引部分
- 为什么不用redis:用户表数量大,Redis用内存存储,数据量这么大成本很高
HBase如何保证数据一致性¶
- Hbase通过WAL来保证数据的一致性和可靠性
- hbase在写操作时会先写入wal日志,这样在写操作出现了故障,也可以通过wal来恢复数据
- Hbase还支持数据复制(副本)和自动故障转移(通过zk感知后告知hmaster)
hbase的文件存储格式¶
StoreFile是HBase存储数据的文件格式。
StoreFile是以Hfile的形式存储在HDFS上的。
Hbase的架构¶
HBase主要包括region server和master,其外还有zookeeper和hdfs
- region server主要用于region的管理
- master主要用于管理region server
- zookeeper主要是用来保证master的高可用
- hdfs提供存储服务
简述Hbase的读写流程¶
-
写流程:
put 'student', '1001', 'info:sex', 'male' -
客户端先访问zookeeper,获取元数据表
hbase:meta在哪个region server中 - 然后客户端访问对应的region server,获取到元数据表,根据写的请求,确定数据应该写到哪个region server的哪个region中
- 然后将region信息和元数据表的信息缓存在客户端的
meta cache中,以便下次访问 - 与对应的region server进行通讯
- 将数据先写入到WAL文件中,然后再写入memstore中,数据会在memstore中进行排序
- WAL文件也就是预写日志
- HBase之读写流程中WAL机制_>hbase.wal.rolling.interval-CSDN博客
- 写入完成后,region server会向客户端发送ack
-
等到达memstore的刷写时机后(达到一个默认值大小或者达到刷写的时间),再将数据刷写到HFile中
-
读流程:
get 'student', '1001' -
客户端先访问zookeeper,获取元数据表
hbase:meta在哪个region server中 - 然后客户端访问对应的region server,获取到元数据表,根据读的请求,确定数据位于哪个region server的哪个region中
- 然后将region信息和元数据表的信息缓存在客户端的meta cache中,以便下次访问
- 与对应的region server进行通讯
- 先在block cache(读缓存)中读,如果没有,然后去memstore和hfile中读取
- 再将读到的HFile数据返回给客户端并且写入block cache中,方便下一次读取
Hbase有哪几种写入方式,应用场景¶
- 单条put:线上业务
- 批量put:数据量较大
- 使用Mapreduce:数据量非常大
- bluckload:速度快
HBase 在写过程中的region的split时机¶
每一个region 由一个或多个 store 组成,且至少有一个 store。一个store 由一个memstore + 0或多个 StoreFile 组成。默认情况下,每个 table 只有一个 region,随着不断写入数据,region 会自动进行拆分
- region 切分时机
- hbase0.94版本之前:当一个region 中的某个 store 下的所有 storefile 总大小超过 10G的时候,就会自动拆分,这个10G是默认值,也可以改配置参数
- hbase0.94 版本之后:当一个region 中的某个 store 下的所有 storefile 总大小超过
min(表的个数的平方*128M,10G)的时候
Hbase的blockcache的底层实现?你提到了LRU那除了LRU还有什么方案?¶
- LRUBlockCache (LRU最近最少使用) 太多对象会造成jvmGC
- SlabCache 也是用LRU淘汰, 但是是用堆外内存管理, 不用jvm管理, 淘汰时标记为空闲,后续cache直接覆盖
- BucketCache
block cache底层实现 ◼ https://blog.csdn.net/weixin_40954192/article/details/106963979
在 HBase 中,BlockCache 是用于缓存频繁访问数据块(如 HFile 数据块)的核心组件,其三种实现方案(LRUBlockCache、SlabCache、BucketCache)针对不同场景优化,设计理念和实现方式各有差异。
| 实现方案 | 核心目标 | 适用场景 |
|---|---|---|
| LRUBlockCache | 通用缓存,淘汰冷数据 | 中小规模数据、简单访问模式 |
| SlabCache | 优化小对象内存分配与访问 | 索引块(如 Bloom Filter)、键值对 |
| BucketCache | 高吞吐大块数据缓存,避免 GC 影响 | 大规模扫描、高并发数据块访问 |
| 特性 | LRUBlockCache | SlabCache | BucketCache |
|---|---|---|---|
| 内存类型 | 堆内内存(JVM Heap) | 堆内内存,固定大小内存池 | 堆外内存(Direct Memory,默认) |
| 数据结构 | 分片哈希表 + 双向链表(近似LRU) | 分片哈希表 + 内存池(Slab) | 分片哈希表 + 链表(LRU-K/2Q) |
| 键(Key) | 文件路径 + 块偏移量 | 小对象唯一标识(如索引键) | 文件路径 + 块偏移量 |
| 值(Value) | 数据块内容 + 元数据 | 小对象内容 + 元数据 | 数据块内容 + 元数据 |
| 淘汰算法 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| LRUBlockCache | 近似 LRU(如 Clock 算法) | 实现简单,通用性强 | 锁竞争可能较高,内存碎片 |
| SlabCache | FIFO 或简单 LRU | 低延迟,内存分配高效 | 内存利用率低,不适合大块数据 |
| BucketCache | LRU-K、2Q 或手动淘汰 | 高吞吐,避免 GC 停顿 | 配置复杂,冷启动性能差 |
| 方案 | 优点 | 缺点 |
|---|---|---|
| LRUBlockCache | 通用性高,实现简单 | 内存碎片,锁竞争,GC 影响 |
| SlabCache | 低延迟,内存分配高效 | 内存利用率低,仅适合小对象 |
| BucketCache | 高吞吐,避免 GC,适合大块数据 | 配置复杂,冷启动性能差 |
LRUBlockCache
- 分片哈希表:将缓存项分散到多个哈希表分片,减少锁竞争。
- 近似 LRU:通过双向链表或时钟算法(Clock)维护访问顺序,平衡性能与实现复杂度。
- 元数据跟踪:记录访问时间戳,支持基于时间的淘汰(如 TTL)。
SlabCache
- 内存池(Slab):按对象大小(如 128B、256B)划分内存块,避免频繁分配/释放。
- 无锁分配:使用 CAS 或 Disruptor 框架管理空闲链表,提升并发性能。
- 固定大小块:适合小对象(如索引),减少内存碎片,但可能浪费空间。
BucketCache
- 堆外内存:通过
ByteBuffer或Unsafe分配,绕过 JVM GC,适合大块数据。 - 复杂淘汰策略:如 LRU-K(结合访问次数)或 2Q(分层队列),避免误淘汰热点数据。
- 预读与批量加载:优化顺序扫描场景,预加载相邻数据块到缓存。
协作与调优建议
- 组合使用:
- SlabCache 缓存索引块,BucketCache 缓存数据块,LRUBlockCache 作为补充(如元数据)。
- 参数调优:
- SlabCache:调整 Slab 大小(如
hbase.slabcache.slab.size)。 - BucketCache:设置堆外内存大小(如
hbase.bucketcache.size),选择淘汰策略(如hbase.bucketcache.combinedcache.enabled)。 - 监控指标:
- 命中率(
CacheHitRatio)、内存使用量(CacheUsed)、淘汰次数(Evictions)。
总结
- LRUBlockCache:适合通用场景,但受限于堆内内存和锁竞争。
- SlabCache:专为小对象优化,内存分配高效,适合索引和键值对。
- BucketCache:针对大块数据设计,利用堆外内存提升吞吐,适合高并发扫描。
实际部署时,需根据数据访问模式(如读写比例、查询类型)选择或组合缓存方案,并通过监控调整参数以达到最佳性能。
删除Hbase中的一个数据,它是立马就把数据删除掉了吗¶
不是,只是将删除操作记录下来,刷写的时候记录在StoreFile的元数据里,在StoreFile文件比较多进行合并时,才清理过期或者删除数据
Hbase的高可用是怎么实现的¶
- 数据复制:数据能够通过wal日志在不同的RegionServer之间进行复制
- Zookeeper:可以监控RegionServer的状态,告知HMaster
- RegionServer的自动故障修复:zk通过WAL感知Hmaster
Hbase Get和scan的区别和联系¶
- 区别:
- Get根据RowKey获取唯一值
- Scan按照指定的条件和顺序扫描表中的多行数据
- Get操作在内部对数据进行缓存,因此适用于对特定行的频繁读取,而Scan操作不会缓存数据,适用于一次性读取大量数据或按顺序遍历数据
- 为什么scan不缓存数据,因为scan读取的数据量可能会很大
- 联系
- Get和Scan都可以使用过滤器进行数据过滤,以便按照特定条件筛选所需要的数据
- 都可以选择返回的列族和列限定符,以获取特定的列数据
HBase 中的 compact 用途、触发时间和流程,有哪几种以及之间的区别¶
-
用途
-
合并HFile 文件,提高读写数据的效率
-
清除过期和删除的数据
-
触发时间
由于memstore每次刷写都会生成一个新的HFile,当HFile 的数量达到一定程度后,就需要进行 StoreFile Compaction
- 流程
- 合并:对所有的StoreFile进行归并排序,并进行合并,读取所有hfile文件写入一个hfile中,合并同时处理文件版本,时间戳等信息,合并过程会进行版本合并和数据删除(看具体的compaction)
- 清理:合并完成后,原有的StoreFile会废弃,Hbase会将其删除,并释放相应的空间(看具体的compaction)
- 更新元数据:hbase更新相应的元数据
- 分类以及区别(大合并和小合并)
- minor compaction:会将临近的若干个较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据
- major compaction:会将一个Store下的所有的HFile合并成一个大 HFile,而且会清理掉过期和删除的数据
WAL日志恢复流程¶
- WAL日志拆分
- HMaster将故障RegionServer的WAL文件按Region拆分,提取每个Region相关的日志条目,生成独立的临时文件。
- 拆分依据是WALKey中的Region信息(如
HRegionInfo)。 - 日志分配与重放
- 拆分后的WAL日志片段会分配给新接管对应Region的RegionServer(这些RegionServer可能原本并无该Region的数据)。
- 新RegionServer加载Region的HFile后,重放WAL日志中的未持久化操作(如MemStore未刷盘的Put/Delete),确保数据一致性。
- 数据本地化优化
- 新RegionServer在恢复过程中会通过Compaction将数据重新写入本地HDFS节点,逐步提升数据本地性,但初始阶段可能依赖远程读取。
热点现象怎么产生的,以及解决方法有哪些¶
- 热点现象
某时间段内,对HBase 的读写请求集中到极少数的Region上,导致这些region所在的 RegionServer 处理请求量骤增,负载量明显偏大,而其他的 RegionServer明显空闲
-
原因
-
hbase的中的数据是按照字典序排序的,大量连续的rowkey集中写在个别的 region,各个region 之间数据分布不均衡
- 创建表时没有提前预分区,创建的表默认只有一个region,大量的数据写入当前 region
-
创建表已经提前预分区,但是设计的rowkey不合理
-
解决办法
总的来说就是 预分区+rowkey 设计
预分区就是在建表的时候,就提前划分出多个region,而不是默认的一个
rowkey设计就是通过设计出合理的rowkey,让数据均匀的分布到所有的 region 中
HBase的rowkey 设计原则¶
- 长度原则
- RowKey是一个二进制码流,可以是任意字符串,最大长度 64kb
- 建议不超过16个字节, RowKey越大,当数据量越大,占用存储越大
- 过长会导致 RowKey 在 memStore 中占据的内存空间过大,而实际数据占据的空间很小,造成只写了少量数据就因为RowKey占据太多空间而flush
- 散列原则:rowkey要具有散列性,作用是将数据打散,不要让连续的数据集中在一个region里面,降低热点问题出现的可能性。
- 计算 hash 值
- 字符串反转
- 字符串拼接
- 可以利用按照字典顺序排序这一点, 将经常读取的数据存在一起
- 唯一原则: 因为RowKey中数据是以 key-value 格式存储的,所以一个rowkey只能对应一条数据
HBase表的设计¶
- 列族设计在合理范围内能尽量减少列族就尽量减少列族数据保留的版本数据保留的时间
- rowkey设计预分区,解决热点问题
- rowkey不能过长,建议16,且要唯一
HBase的优缺点¶
优点是
- 具有强一致性和持久性
- 数据写入内存后异步刷新到磁盘
- 读写速度快
- 底层采用K-V存储方式,意味着即使数据海量增长,查询性能也不会急剧下降
- 列式存储,可以动态添加列族和列
缺点是
- 由于hbase按照row key来读写,不支持大范围条件查询
- 不支持表的关联操作
- 聚合查询能力差
HBase 和 hive 的区别¶
首先,hbase是一个数据库,而hive一般用于构建数据仓库,从功能上理解就是,hbase可以看做是一个存储框架,而hive是一款分析框架。
从结构上分析,hive是逻辑表,存储和查询依赖hadoop;hbase是物理表,有独立的物理数据结构
其中,因为hbase的查询延迟比较低,所以常用于实时大数据的查询和存储,在数仓项目中也适用于实时场景的维表存储和查询(可以用Redis做外部缓存);而hive常用于构建基于hadoop的数据仓库,负责在离线状态下处理数据业务
hive和hbase的数据都可以存储在hdfs上,但是hive是基于hadoop去进行存储和查询的使用,hive sql的语句会被转换为MapReduce任务来执行,所以hadoop也是hive的局限性所在。对于hbase而言,只用到了hdfs来存储数据,hbase的数据查询只在hbase数据库内部,而不会用到mapreduce,因此hbase不支持sql,且运行依赖于zookeeper,这就是hbase的局限性。
hive因为支持sql,所以更适合了解sql的人上手,但是因为默认使用mapreduce计算引擎,所以查询时间长,优化方案可以将计算引擎更换为tez或者spark
hbase虽然默认不支持sql,但是可以通过集成phoenix来提供对sql的支持,其底层基于scan进行数据扫描和数据表的一级索引rowkey,所以即使没有sql,hbase也能提供较快的查询速度。