1 RowKey设计
重要:一条数据的唯一标识就是 rowkey,那么这条数据存储于哪个分区,取决于 rowkey 处于 哪个一个预分区的区间内,设计 rowkey的主要目的 ,就是让数据均匀的分布于所有的 region 中,在一定程度上防止数据倾斜。
设计方案如下:
- 生成随机数、hash、散列值
- 时间戳反转
- 字符串拼接
1.1 RowKey定长
- 避免扫描数据混乱,解决字段长度不一致的问题,可以使用相同阿斯卡码值的符 号进行填充,框架底层填充使用的是阿斯卡码值为 1 的^A。
- 最后的日期结尾处需要使用阿斯卡码略大于'-'的值,比如 .
powershell
rowKey 设计格式 => ^A^Auser
1.2 可枚举的部分放在前面
hbase 设计 rowKey 使用的特点为: 适用性强 泛用性差 能够完美实现一个需求 但是不能同时完美实现多个需要。
如果想要同时完成两个需求,需要对 rowKey 出现字段的顺序进行调整。
调整的原则为:可枚举的放在前面。其中时间是可以枚举的,用户名称无法枚举,所以 必须把时间放在前面。
powershell
rowKey 设计格式 => date(yyyy-MM)^A^Auserdate(-dd hh:mm:ss ms)
1.3 添加预分区优化
每一个 region 维护着 startRow 与 endRowKey,如果加入的数据符合某个 region 维护的 rowKey 范围,则该数据交给这个 region 维护。
预分区的分区号同样需要遵守 rowKey 的 scan 原则。所有必须添加在 rowKey 的最前面, 前缀为最简单的数字。同时使用 hash 算法将用户名和月份拼接决定分区号。(单独使用用 户名会造成单一用户所有数据存储在一个分区)
1.3.1 预规划分区
根据12个月,规划120个分区,每个分区有startKey 和stopKey,采用startKey 作为分区号
powershell
添加预分区优化
startKey stopKey
000 001
001 002
002 003
...
119 120
1.3.2 提前将分区号和月份进行对应。
每一个月份对应10个分区
powershell
000 到 009 分区 存储的都是 1 月份数据
010 到 019 分区 存储的都是 2 月份数据
...
110 到 119 分区 存储的都是 12 月份数据
1.3.3 设计rowKey
powershell
rowKey 设计格式 => 分区号date(yyyy-MM)^A^Auserdate(-dd hh:mm:ss ms)
1.3.4 根据 用户名和事件获取rowKey值
powershell
分区号=> hash(user+date(MM)) % 10 + 对应月份初始分区号
分区号填充 如果得到 85 => 085
例:zhagnsan 2022-02-14 12:34:45
powershell
分区号=hash(zhagnsan+date(02)) % 10 + 20 = 25
分区号补0 :025
用户名补^A :^A^Azhagnsan
rowKey => 0252022-02^A^Azhagnsan-14 12:34:45
1.4 案例
powershell
可以穷举的写在前面即可 rowKey 设计格式 => 分区号date(yyyy-MM)^A^Auserdate(-dd
hh:mm:ss ms)
(1)统计张三在 2021 年 12 月份消费的总金额
分区号=> hash(user+date(MM)) % 10 + 110
scan: startRow => 分区号2021-12^A^Azhangsan stopRow => 2021-12^A^Azhangsan.
(2)统计所有人在 2021 年 12 月份消费的总金额
分区号=> hash(user+date(MM)) % 10 + 110
scan: startRow => 分区号2021-12 stopRow => 分区号2021-12.
2 参数调优
2.1 Zookeeper 会话超时时间
属性:zookeeper.session.timeout
解释:默认值为 90000 毫秒(90s)。当某个 RegionServer 挂掉,90s 之后 Master 才 能察觉到。可适当减小此值,尽可能快地检测 regionserver 故障,可调整至 20-30s。
看你能有都能忍耐超时,同时可以调整重试时间和重试次数
hbase.client.pause(默认值 100ms)
hbase.client.retries.number(默认 15 次)
2.2 设置 RPC 监听数量
属性:hbase.regionserver.handler.count
解释:默认值为 30,用于指定 RPC 监听的数量,可以根据客户端的请求数进行调整,读写 请求较多时,增加此值。
2.3 手动控制 Major Compaction
属性:hbase.hregion.majorcompaction 解释:默认值:604800000 秒(7 天), Major Compaction 的周期,若关闭自动 Major Compaction,可将其设为 0。如果关闭一定记得自己手动合并,因为大合并非常有意义
2.4 优化 HStore 文件大小
属性:hbase.hregion.max.filesize
解释:默认值 10737418240(10GB),如果需要运行 HBase 的 MR 任务,可以减小此值, 因为一个 region 对应一个 map 任务,如果单个 region 过大,会导致 map 任务执行时间过长。该值的意思就是,如果 HFile 的大小达到这个数值,则这个 region 会被切分为两 个 Hfile。
2.5 优化 HBase 客户端缓存
属性:hbase.client.write.buffer
解释:默认值 2097152bytes(2M)用于指定 HBase 客户端缓存,增大该值可以减少 RPC 调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到 减少 RPC 次数的目的。
2.6 指定 scan.next 扫描 HBase 所获取的行数
属性:hbase.client.scanner.caching 解释:用于指定 scan.next 方法获取的默认行数,值越大,消耗内存越大。
2.7 BlockCache 占用 RegionServer 堆内存的比例
属性:hfile.block.cache.size
解释:默认 0.4,读请求比较多的情况下,可适当调大
2.8 MemStore 占用 RegionServer 堆内存的比例
属性:hbase.regionserver.global.memstore.size
解释:默认 0.4,写请求较多的情况下,可适当调大
Lars Hofhansl(拉斯·霍夫汉斯)大神推荐 Region HStore 文件设置 20G,刷写大小设置 128M,其 它默认。
3 JVM 调优
JVM 调优的思路有两部分:一是内存设置,二是垃圾回收器设置。
垃圾回收的修改是使用并发垃圾回收,默认 PO+PS 是并行垃圾回收,会有大量的暂停。 理由是 HBsae 大量使用内存用于存储数据,容易遭遇数据洪峰造成 OOM,同时写缓存的数 据是不能垃圾回收的,主要回收的就是读缓存,而读缓存垃圾回收不影响性能,所以最终设 置的效果可以总结为:防患于未然,早洗早轻松。
- 设置使用 CMS 收集器:
powershell
-XX:+UseConcMarkSweepGC
- 保持新生代尽量小,同时尽早开启 GC,例如:
powershell
//在内存占用到 70%的时候开启 GC
-XX:CMSInitiatingOccupancyFraction=70
//指定使用 70%,不让 JVM 动态调整
-XX:+UseCMSInitiatingOccupancyOnly
//新生代内存设置为 512m
-Xmn512m
//并行执行新生代垃圾回收
-XX:+UseParNewGC
// 设 置 scanner 扫 描 结 果 占 用 内 存 大 小 , 在 hbase-site.xml 中,设置
hbase.client.scanner.max.result.size(默认值为 2M)为 eden 空间的 1/8(大概在 64M)
// 设置多个与 max.result.size * handler.count 相乘的结果小于 Survivor Space(新生代经过垃圾回收之后存活的对象)
4 HBase 使用经验法则
官方给出了权威的使用法则:
- Region 大小控制 10-50G
- cell 大小不超过 10M(性能对应小于 100K 的值有优化),如果使用 mob(Mediumsized Objects 一种特殊用法)则不超过 50M。
- 1 张表有 1 到 3 个列族,不要设计太多。最好就 1 个,如果使用多个尽量保证不同时读取多个列族。
- 1 到 2 个列族的表格,设计 50-100 个 Region。
- 列族名称要尽量短,不要去模仿 RDBMS(关系型数据库)具有准确的名称和描述。
- 如果 RowKey 设计时间在最前面,会导致有大量的旧数据存储在不活跃的 Region中,使用的时候,仅仅会操作少数的活动 Region,此时建议增加更多的 Region 个数。
- 如果只有一个列族用于写入数据,分配内存资源的时候可以做出调整,即写缓存不会占用太多的内存。