1 HBase存储结构
HMaster
1. 监控 RegionServer
2. 处理 RegionServer 故障转移
3. 处理元数据的变更
4. 处理 region 的分配或移除
5. 在空闲时间进行数据的负载均衡
6. 通过 Zookeeper 发布自己的位置给客户端
RegionServer
1. 负责存储 HBase 的实际数据
2. 处理分配给它的 Region
3. 刷新缓存到 HDFS
4. 维护 HLog
5. 执行压缩
6. 负责处理 Region 分片
Write-Ahead logs(HLog)
HBase 的修改记录, 当对 HBase 读写数据的时候, 数据不是直接写进磁盘, 它会在内存中保留一段时间(时间以及数据量阈值可以设定) 。 但把数据保存在内存中可能有更高的概率引起数据丢失, 为了解决这个问题, 数据会先写在一个叫做 Write-Ahead logfile 的文件中, 然后再写入内存中。 所以在系统出现故障的时候, 数据可以通过这个日志文件重建。
HFile
这是在磁盘上保存原始数据的实际的物理文件, 是实际的存储文件。
Store File
HFile 存储在 Store 中, 一个 Store 对应 HBase 表中的一个列族。
MemStore
顾名思义, 就是内存存储, 位于内存中, 用来保存当前的数据操作, 所以当数据保存在 WAL 中之后, RegsionServer 会在内存中存储键值对。
Region
Hbase 表的分片, HBase 表会根据 RowKey 值被切分成不同的 region 存储在RegionServer 中, 在一个 RegionServer 中可以有多个不同的 region。
2 Hbase写数据过程
Client写入
-> 存入MemStore, 一直到MemStore满
-> Flush成一个StoreFile,直至增长到一定阈值
-> 触发Compact合并操作
-> 多个StoreFile合并成一个StoreFile, 同时进行版本合并和数据删除
-> 当 StoreFiles Compact 后, 逐步形成越来越大的 StoreFile
-> 单个 StoreFile 大小超过一定阈值后(默认 10G),触发 Split 操作, 把当前 Region Split 成 2 个 Region, Region 会下线, 新 Split出的 2 个孩子 Region 会被 HMaster 分配到相应的 HRegionServer 上, 使得原先1 个 Region 的压力得以分流到 2 个 Region 上。
由此过程可知, HBase 只是增加数据, 没有更新和删除操作, 用户的更新和删除都是逻辑层面的, 在物理层面, 更新只是追加操作, 删除只是标记操作。
用户写操作只需要进入到内存即可立即返回, 从而保证 I/O 高性能。
3 RowKey设计原则
长度原则: 100 字节以内, 8 的倍数最好, 可能的情况下越短越好。 因为 HFile是按照 keyvalue 存储的, 过长的 rowkey 会影响存储效率; 其次, 过长的 rowkey在 memstore 中较大, 影响缓冲效果, 降低检索效率。 最后, 操作系统大多为 64位, 8 的倍数, 充分利用操作系统的最佳性能。
散列原则: 高位散列, 低位时间字段。 避免热点问题。
唯一原则: 分利用这个排序的特点, 将经常读取的数据存储到一块, 将最近可能会被访问 的数据放到一块。
4 RowKey如何设计
电信案例:查询某个人(手机号)某年某月某日的通话详情
- 预分区
(1) 评估未来半年到一年的数据增长,不让其自动分区(10G)
(2) 确定分区键
00| 01| 02| …
000| 001| …
- 设计RowKey
(1) 确定分区号 (散列性)
手机号%分区数 不够散列
(手机号+年月日)%分区数 按照月份、年进行查询 不方便
(手机号+年月)%分区数
(2) 拼接字段 (唯一性、长度)
XX_手机号_时间戳
XX_手机号_年月日 时分秒
XX_时间戳_手机号
XX_年月日 时分秒_手机号
(3) 校验
手机号:13412341234 通话时间:2021-09-07
XX_手机号_年月日 时分秒
startRow:05_13412341234_2021-09-07
stopRow :05_13412341234_2021-09-08
05_13412341234_2021-09-07
XX_年月日 时分秒_手机号
startRow:05_2021-09-07 00:00:00_13412341234
stopRow :05_2021-09-08 00:00:00_13412341234
手机号:13412341234 通话时间:2021-09 2021-11
XX_手机号_年月日 时分秒
startRow:05_13412341234_2021-09
stopRow :05_13412341234_2021-09
05_13412341234_2021-10
startRow:03_13412341234_2021-10
stopRow :03_13412341234_2021-11
startRow:04_13412341234_2021-11
stopRow :04_13412341234_2021-12
5 热点现象( 数据倾斜) 怎么产生的, 以及解决方法有哪些
5.1热点现象
某个小的时段内, 对 HBase 的读写请求集中到极少数的 Region 上, 导致这些region 所在的 RegionServer 处理请求量骤增, 负载量明显偏大, 而其他的RgionServer 明显空闲。
5.2 热点现象出现的原因
HBase 中的行是按照 rowkey 的字典顺序排序的, 这种设计优化了 scan 操作, 可以将相关的行以及会被一起读取的行存取在临近位置, 便于 scan。 然而糟糕的rowkey 设计是热点的源头。
热点发生在大量的 client 直接访问集群的一个或极少数个节点( 访问可能是读,写或者其他操作) 。 大量访问会使热点 region 所在的单个机器超出自身承受能力, 引起性能下降甚至 region 不可用, 这也会影响同一个 RegionServer 上的其他 region, 由于主机无法服务其他 region 的请求。
5.3 热点现象解决办法
为了避免写热点, 设计 rowkey 使得不同行在同一个 region, 但是在更多数据情况下, 数据应该被写入集群的多个 region, 而不是一个。 常见的方法有以下这些:
1. 加盐: 在 rowkey 的前面增加随机数, 使得它和之前的 rowkey 的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的 region 的数量一致。 加盐之后的 rowkey 就会根据随机生成的前缀分散到各个 region 上,以避免热点。
2. 哈希: 哈希可以使负载分散到整个集群, 但是读却是可以预测的。 使用确定的哈希可以让客户端重构完整的 rowkey, 可以使用 get 操作准确获取某一个行数据
3. 反转: 第三种防止热点的方法时反转固定长度或者数字格式的 rowkey。这样可以使得 rowkey 中经常改变的部分(最没有意义的部分) 放在前面。这样可以有效的随机 rowkey, 但是牺牲了 rowkey 的有序性。 反转 rowkey的例子以手机号为 rowkey, 可以将手机号反转后的字符串作为 rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题
4. 时间戳反转: 一个常见的数据处理问题是快速获取数据的最近版本, 使用反转的时间戳作为 rowkey 一部分对这个问题十分有用, 可以用Long.Max_Value - timestamp 追加到 key 的末尾, 例如[key][reverse_timestamp],[key]的最新值可以通过 scan [key]获得[key]的第一条记录, 因为 HBase 中 rowkey 是有序的, 第一条记录是最后录入的数据。
比如需要保存一个用户的操作记录, 按照操作时间倒序排序, 在设计 rowkey 的时候, 可以这样设计[userId 反转] [Long.Max_Value- timestamp], 在查询用户的所有操作记录数据的时候, 直接指定反转后的 userId,startRow 是[userId 反转][000000000000],stopRow 是[userId 反转][Long.Max_Value -timestamp]
如果需要查询某段时间的操作记录, startRow 是[user 反转][Long.Max_Value - 起始时间], stopRow 是[userId 反转][Long.Max_Value - 结束时间]
5. HBase 建表预分区: 创建 HBase 表时, 就预先根据可能的 RowKey 划分出多个 region 而不是默认的一个, 从而可以将后续的读写操作负载均衡到不同的 region 上, 避免热点现象。
6 HBase 的列簇设计
原则: 在合理范围内能尽量少的减少列簇就尽量减少列簇, 因为列簇是共享region 的, 每个列簇数据相差太大导致查询效率低下。
最优: 将所有相关性很强的 key-value 都放在同一个列簇下, 这样既能做到查询效率最高, 也能保持尽可能少的访问不同的磁盘文件。 以用户信息为例, 可以将必须的基本信息存放在一个列族, 而一些附加的额外信息可以放在另一列族。
7 HBase 中 compact 用途是什么, 什么时候触发, 分为哪两种, 有什么区别
在 hbase 中每当有 memstore 数据 flush 到磁盘之后, 就形成一个 storefile,当 storeFile 的数量达到一定程度后, 就需要将 storefile 文件来进行compaction 操作。
Compact 的作用:
- 合并文件
- 清除过期, 多余版本的数据
- 提高读写数据的效率
- HBase 中实现了两种 compaction 的方式: minor and major. 这两种 compaction 方式的 区别是:
Minor 操作只用来做部分文件的合并操作以及包括 minVersion=0 并且设置 ttl 的过 期版本清理, 不做任何删除数据、 多版本数据的清理工作。
Major 操作是对 Region 下的 HStore 下的所有 StoreFile 执行合并操作, 最终的结果 是整理合并出一个文件。