专栏首页数据社面试,HBase如何设计rowkey

面试,HBase如何设计rowkey

HBase中的rowkey是按字典顺序排序的,通过rowkey查询可以对千万级的数据实现毫秒级响应。然而,如果rowkey设计不合理的话经常会出现一个很普遍的问题----热点。当大量client的请求(读或者写)只指向集群的一个节点,或者很少量的几个节点时,也就代表产生了热点问题。

避免产生热点的方式也就是尽可能的将rowkey均匀分散到所有的region上,下面介绍了几种rowkey设计常用的方式:

第一:加盐(salting)

加盐是指在rowkey的前缀添加随机数据,使rowkey尽可能的分布到其他regionserver上

假设遇到下面的rowkey,表的预分区设置为每个字母对应一个region。前缀“a”是一个region,前缀“b”是另一个region等等。那么在这个表中,所有以“f”开头的rowkey都将位于同一个region。比如:

foo0001

foo0002

foo0003

foo0004

那么,如果你想把它们分散到四个不同的region,那么就可以使用四种不同的前缀: a、b、c和d来做加盐。在加盐之后,rowkey也就变成了下面这样。

a-foo0003

b-foo0001

c-foo0004

d-foo0002

(ps:由于现在可以向四个region写数据,理论上,性能比之前向同一个region写吞吐量提升四倍)

并且,如果后续有新的数据写入,rowkey也就会随机的添加前缀,写到不同的region中

缺点:加盐虽然可以很大程度的避免热点问题,提升写入效率,但是由于rowkey被随机的添加了salt值,在读取时候要付出额外的开销。具体怎么读取加盐后的数据,后面再做介绍

第二:哈希(hashing)

哈希的算法有多种,在rowkey设计中用的比较多的大概就是MD5了吧,但是需要注意的是MD5散列还是有碰撞的可能性的,概率很小,但是不是零。

所以一般使用MD5做rowkey散列时候,都会附加一个唯一字段,比如账号字段account,对account做MD5,截取6位左右的md5返回值然后再拼接account字段,也就是:

substr(md5(account))+account

此外,通过md5散列之后的rowkey,在创建表预分区时候,可以使用hbase自带的HexStringSplit方法

第三:反转(Reversing)

如果定义的rowkey字段,前部分数据变化幅度很小,变化很慢,尾部数据变化频率较高,便可以考虑反转字段,尤其对类似时间戳的数据

不管以哪种方式设计rowkey,在查询时候也要做对应的数据处理,比如做hash的,查询时候也需要先把数据hash之后,然后查询rowkey;通过反转方式设计的rowkey同理。

第四:最小化rowkey和列簇长度

rowkey可以是任意的字符串,最大长度64KB,但是建议在设计rowkey时候,尽可能的短,原因:

1.hbase数据存储是以key-value的形式存储的,如果rowkey比较长,比如100字节,那么1000w行数据,光rowkey存储就需要100*1000w=10亿个字节,将近1G的数据。

2.memstore的会缓存数据到内存,如果rowkey比较长,同样会占用更多的空间

3.建议rowkey设计在8字节的整数倍,控制在16个字节,因为目前的操作系统大多都是64位的,整数倍更好了利用了操作系统的特性。

列簇(ColumnFamily)同理,尽可能的短,最好是一个字符,比如 f 或者 d

第五:Byte Patterns

我们知道,long类型是8个字节,并且你可以通过long类型存储一个最大为18,446,744,073,709,551,615的无符号数字,仅仅用8个字节,但是如果以string类型的形式存储这样的数字,那么几乎需要3倍空间的大小(假定每个字符占一个字节)

举个例子验证一下:

// long
//
long l = 1234567890L;
byte[] lb = Bytes.toBytes(l);
System.out.println("long bytes length: " + lb.length);   // returns 8

String s = String.valueOf(l);
byte[] sb = Bytes.toBytes(s);
System.out.println("long as string length: " + sb.length);    // returns 10

// hash
//
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(Bytes.toBytes(s));
System.out.println("md5 digest bytes length: " + digest.length);    // returns 16

String sDigest = new String(digest);
byte[] sbDigest = Bytes.toBytes(sDigest);
System.out.println("md5 digest as string length: " + sbDigest.length);    // returns 26

但是,也有一个缺点,就是如果使用这种二进制表示的类型时候,在hbase shell界面查数据的时候,可读性比较差,比如:

hbase(main):002:0> get 'table1', 'rowkey1'
COLUMN                                        CELL
 f:q                                          timestamp=1369163040570, value=\x00\x00\x00\x00\x00\x00\x00\x01
1 row(s) in 0.0310 seconds

本文分享自微信公众号 - 数据社(DataClub),作者:HBase

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-11-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 从0到1搭建大数据平台之计算存储系统

    前面已经给大家讲了《从0到1搭建大数据平台之数据采集系统》、《从0到1搭建大数据平台之调度系统》,今天给大家讲一下大数据平台计算存储系统。大数据计算平台目前主要...

    数据社
  • 关于机器学习,你需要了解的规范化方法

    那么如何用相同的标准来比较 A 与 B 的成绩呢?Z-Score 就是用来可以解决这一问题的。

    数据社
  • 数据和业务的关系是什么?

    数据和业务的关系,没有固定形态,就如兵无常势、水无常形。这和公司大boss的风格、业务boss的风格、数据boss的风格、公司组织架构紧密相关。

    数据社
  • hbase的rowkey设计原则和实现方式

    hbase的内部使用KeyValue的形式存在,其key是有rowkey:family:column:logTime,value是其存储的内容。

    凹谷
  • 【SLAM】开源 | 基于混合地图的视觉惯性定位算法,平均定位误差为1.7cm,并且召回率达到100%

    论文地址: http://arxiv.org/pdf/2011.04173v1.pdf

    CNNer
  • 还单身?不如来看看脱单神器!

    今天小李在逛人类知识宝库时发现一个非常有意思的目,“CoupleGenerator”, 可以理解为伴侣生成器。哦也不对,单身的小伙伴不要想太多,国家不会分配,A...

    老肥码码码
  • 高性能算法的四大实战技巧 | 算法经验(12)

    性能提升的力度按上表的顺序从上到下依次递减。举个例子,新的建模方法或者更多的数据带来的效果提升往往好于调出最优的参数。但这并不是绝对的,只是大多数情况下如此。

    用户7623498
  • Computer Vision 杂志对何恺明 Rethinking ImageNet Pre-training 的最新评论

    「Rethinking ImageNet Pre-training」这篇惊艳的论文向我们展示了:使用从随机初始化的状态开始训练的标准模型在 COCO 数据集上也...

    AI科技评论
  • Mysql(9)——排序的方法order by与limit的用法

    其中,order by即按照升序或者降序的方式排列,如果后面跟的是desc则是降序排列,如果后面跟的是asc,则是升序排列。

    gzq大数据
  • Python基础之模块_包

    Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。

    海仔

扫码关注云+社区

领取腾讯云代金券