HBase 的表设计

1 ColumnFamily 设计

追求的原则是:在合理的范围内能尽量少的减少列簇就尽量减少列簇。

最优设计是:将所有相关性很强的 Key-Value 都放在同一个列簇下,这样既能做到查询效率最高,也能保持尽可能少的访问不同的磁盘文件。

以用户信息为例,可以将必须的基本信息存放在一个列簇,而一些附加的额外信息可以放在另一个列簇。

 

2 RowKey 设计

HBase 中,表会被划分为 1...n 个 Region,被托管在 RegionServer 中。Region 两个重要的属性:StartKey 与 EndKey 表示这个 Region 维护的 RowKey 范围,当我们要读/写数据时,如果 RowKey 落在某个 Start-end Key 范围内,那么就会定位到目标 Region 并且读/写到相关的数据。

那怎么快速精准的定位到想要操作的数据,就在于 RowKey 的设计。

 

3. RowKey 设计三原则

3.1 RowKey 长度原则

RowKey 是一个二进制码流,RowKey 的长度被很多开发者建议说设计在 10-100 个字节,建议是越短越好,不要超过 16 个字节。原因如下:

  1. 数据的持久化文件 HFile 中是按照 KeyValue 存储的,如果 RowKey 过长,比如 100 个字节,如果有 1000 万行数据,光 RowKey 就要占用 100 * 1000 万 = 10 亿字节,将近 1G 数据,这会极大的影响 HFile 的存储效率。
  2. MemStore 将缓存部分数据到内存当中,如果 RowKey 字段过长,内存的有效利用率就会降低,系统将无法缓存更多的数据,从而降低数据检索效率。因此 RowKey 的字节长度越短越好。
  3. 目前操作系统都是 64 位系统,内存 8 字节对齐。控制在 16 个字节,是 8 字节的整数倍,利用操作系统的最佳特性。

 

3.2 RowKey 散列原则

如果 RowKey 是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将 RowKey 的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个 RegionServer 实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,将产生所有新数据都在一个 RegionServer 上堆积的热点现象,这样在做数据检索的时候负载会集中到个别的 RegionServer,降低查询效率。

 

3.3 RowKey 唯一原则

必须在设计上保证其具有唯一性。RowKey 是按照字典顺序进行排序存储的,因此,设计 RowKey 的时候,要充分利用这个排序特点,将经常读取的数据存储到一个 Region 中,将最近可能会被访问的数据放到一起。

 

数据热点:

HBase 中的行是按照 RowKey 的字典顺序进行排序的,这种设计优化了 scan 操作,可以将相关的行以及会被一起读取的行存储在临近的位置,便于 scan 操作。然而,糟糕的 RowKey 设计是热点的源头。大量访问会使热点 Region 所在的单个节点超出自身承受能力,引起性能下降甚至 Region 不可用,由于主机无法提供其它 Region 的请求,这也会影响同一个 RegionServer 上的其它的 Region 的访问。设计良好的数据访问模式以使集群被充分和均衡的利用。为了避免写热点,设计 RowKey 使得不同行在同一个 Region,但是在更多数据情况下,数据应该被写入集群的多个 Region,而不是一个 Region。

 

防止数据热点的有效措施:

1. 加盐

这里所说的加盐不是密码学中的加盐,而是在 RowKey 的前面都加随机数,就是给 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 - 结束时间]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值