Hbase的Rowkey设计原则

一、 Hbase介绍

HBase -> Hadoop Database,HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式,主要用来存储非结构化和半结构化的松散数据(列存NoSQL数据库)

二、 设计原则

2.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字节的整数倍利用操作系统的最佳特性。

2.2 Rowkey散列原则

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

2.3 Rowkey唯一原则

必须在设计Rowkey上保证其唯一性。

2.4 访问hbase table中的行,只有三种方式:
    1 通过单个row key访问
    2 通过row key的range
    3 全表扫描

Hbase API文档:http://hbase.apache.org/apidocs/index.html?overview-summary.html

HBase的查询实现只提供两种方式:

    1、按指定RowKey获取唯一一条记录,get方法(org.apache.hadoop.hbase.client.Get)
    2、按指定的条件获取一批记录,scan方法(org.apache.hadoop.hbase.client.Scan)

实现条件查询功能使用的就是scan方式,scan在使用时有以下几点值得注意:

1、 scan可以通过setCaching与setBatch方法提高速度(以空间换时间);
2、 scan可以通过setStartRow与setEndRow来限定范围。范围越小,性能越高。
    通过巧妙的RowKey设计使我们批量获取记录集合中的元素挨在一起(应该在同一个    Region下),可以在遍历结果时获得很好的性能。
3、 scan可以通过setFilter方法添加过滤器,这也是分页、多条件查询的基础。

三、 应用场景

   3.1  针对事务数据Rowkey设计

事务数据是带时间属性的,建议将时间信息存入到Rowkey中,这有助于提示查询检索速度。对于事务数据建议缺省就按天为数据建表,这样设计的好处是多方面的。按天分表后,时间信息就可以去掉日期部分只保留小时分钟毫秒,这样4个字节即可搞定。加上散列字段2个字节一共6个字节即可组成唯一 Rowkey。如下图所示:

事务数据Rowkey设计

第0字节

第1字节

第2字节

第3字节

第4字节

第5字节

散列字段

时间字段(毫秒)

扩展字段

0~65535(0x0000~0xFFFF)

0~86399999(0x00000000~0x05265BFF)

这样的设计从操作系统内存管理层面无法节省开销,因为64位操作系统是必须8字节对齐。但是对于持久化存储中Rowkey部分可以节省25%的开销。也许有人要问为什么不将时间字段以主机字节序保存,这样它也可以作为散列字段了。这是因为时间范围内的数据还是尽量保证连续,相同时间范围内的数据查找的概率很大,对查询检索有好的效果,因此使用独立的散列字段效果更好,对于某些应用,我们可以考虑利用散列字段全部或者部分来存储某些数据的字段信息,只要保证相同散列值在同一时间(毫秒)唯一。

针对统计数据的Rowkey设计

统计数据也是带时间属性的,统计数据最小单位只会到分钟(到秒预统计就没意义了)。同时对于统计数据我们也缺省采用按天数据分表,这样设计的好处无需多说。按天分表后,时间信息只需要保留小时分钟,那么0~1400只需占用两个字节即可保存时间信息。由于统计数据某些维度数量非常庞大,因此需要4个字节作为序列字段,因此将散列字段同时作为序列字段使用也是6个字节组成唯一Rowkey。如下图所示:

统计数据Rowkey设计

第0字节

第1字节

第2字节

第3字节

第4字节

第5字节

散列字段(序列字段)

时间字段(分钟)

扩展字段

0x00000000~0xFFFFFFFF)

0~1439(0x0000~0x059F)

同样这样的设计从操作系统内存管理层面无法节省开销,因为64位操作系统是必须8字节对齐。但是对于持久化存储中Rowkey部分可以节省25%的开销。预统计数据可能涉及到多次反复的重计算要求,需确保作废的数据能有效删除,同时不能影响散列的均衡效果,因此要特殊处理。

针对通用数据的Rowkey设计

通用数据采用自增序列作为唯一主键,用户可以选择按天建分表也可以选择单表模式。这种模式需要确保同时多个入库加载模块运行时散列字段(序列字段)的唯一性。可以考虑给不同的加载模块赋予唯一因子区别。设计结构如下图所示。

通用数据Rowkey设计

第0字节

第1字节

第2字节

第3字节

散列字段(序列字段)

扩展字段(控制在12字节内)

0x00000000~0xFFFFFFFF)

可由多个用户字段组成

支持多条件查询的RowKey设计

 

下面举个形象的例子:

 

我们在表中存储的是文件信息,每个文件有5个属性:文件id(long,全局唯一)、创建时间(long)、文件名(String)、分类名(String)、所有者(User)。
我们可以输入的查询条件:文件创建时间区间(比如从20120901到20120914期间创建的文件),文件名(“快乐大本营”),分类(“综艺”),所有者(“浙江卫视”)。
假设当前我们一共有如下文件:

内容列表 ID CreateTime Name Category UserID 1 2 3 4 5 6 7 8 9 10

20120902

快乐大本营第1期

综艺

1

20120904

快乐大本营第2期

综艺

1

20120906

快乐大本营番外

综艺

1

20120908

快乐大本营第3期

综艺

1

20120910

快乐大本营第4期

综艺

1

20120912

快乐大本营嘉宾采访

综艺花絮

2

20120914

快乐大本营第5期

综艺

1

20120916

快乐大本营录制花絮

综艺花絮

2

20120918

王祖蓝独家专访

花絮

3

20120920

安慕希酸奶广告

综艺广告

4

这里UserID应该对应另一张User表,暂不列出。我们只需知道UserID的含义:

1代表 浙江卫视; 2代表 大本营剧组; 3代表 XX微博; 4代表 赞助商。

调用查询接口的时候将上述5个条件同时输入find(20120901,20121001,"快乐大本营","综艺","浙江卫视")。

此时我们应该得到记录应该有第1、2、3、4、5、7条。第6条由于不属于“浙江卫视”应该不被选中。

我们在设计RowKey时可以这样做:采用UserID + CreateTime + FileID组成rowKey,这样既能满足多条件查询,又能有很快的查询速度。

需要注意以下几点:

1、每条记录的RowKey,每个字段都需要填充到相同长度。假如预期我们最多有10万量级的用户,则userID应该统一填充至6位,如000001,000002...

2、结尾添加全局唯一的FileID的用意也是使每个文件对应的记录全局唯一。避免当UserID与CreateTime相同时的两个不同文件记录相互覆盖。
按照这种RowKey存储上述文件记录,在HBase表中是下面的结构:

rowKey(userID 6 + time 8 + fileID 6)     name    category ....

00000120120902000001
00000120120904000002
00000120120906000003
00000120120908000004
00000120120910000005
00000120120914000007
00000220120912000006
00000220120916000008
00000320120918000009
00000420120920000010
.....

怎样用这张表?

在建立一个scan对象后,我们setStartRow(00000120120901),setEndRow(00000120120914)。

这样,scan时只扫描userID=1的数据,且时间范围限定在这个指定的时间段内,满足了按用户以及按时间范围对结果的筛选。并且由于记录集中存储,性能很好。

然后使用SingleColumnValueFilter(org.apache.hadoop.hbase.filter.SingleColumnValueFilter),共4个,分别约束name的上下限,与category的上下限。满足按同时按文件名以及分类名的前缀匹配。

(注意:使用SingleColumnValueFilter会影响查询性能,在真正处理海量数据时会消耗很大的资源,且需要较长的时间。)

如果需要分页还可以再加一个PageFilter限制返回记录的个数。

以上,我们完成了高性能的支持多条件查询的HBase表结构设计。

四、 什么是热点

HBase中的行是按照rowkey的字典顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey设计是热点的源头。热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他region,由于主机无法服务其他region的请求。设计良好的数据访问模式以使集群被充分,均衡的利用。

为了避免写热点,设计rowkey使得不同行在同一个region,但是在更多数据情况下,数据应该被写入集群的多个region,而不是一个。

下面是一些常见的避免热点的方法以及它们的优缺点:

1. 加盐

这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。

2. 哈希

哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据

3. 反转

第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。

3.1 反转rowkey的例子 

以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题

3.2 时间戳反转

一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为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 - 结束时间]

3.3 尽量减少行和列的大小

在HBase中,value永远和它的key一起传输的。当具体的值在系统间传输时,它的rowkey,列名,时间戳也会一起传输。如果你的rowkey和列名很大,HBase storefiles中的索引(有助于随机访问)会占据HBase分配的大量内存,因为具体的值和它的key很大。可以增加block大小使得storefiles索引再更大的时间间隔增加,或者修改表的模式以减小rowkey和列名的大小。压缩也有助于更大的索引。

转载于:https://www.cnblogs.com/zmoumou/p/10292676.html

Habse中Rowkey的设计原则——通俗易懂篇相关推荐

  1. Hbase中RowKey的设计原则和热点问题

    Rowkey设计需要遵循三个原则,即长度原则.散列原则.唯一原则. 1. 长度原则 由于Rowkey是一个二进制码流,可以是任意字符串,最大长度64kb,实际应用中一般为10- 100bytes,以b ...

  2. Hbase-day05_bulkLoad实现批量导入_HBase中rowkey的设计_二级索引_Phoenix二级索引

    hbase-day05 1.bulkLoad实现批量导入 优点: 如果我们一次性入库hbase巨量数据,处理速度慢不说,还特别占用Region资源, 一个比较高效便捷的方法就是使用 "Bul ...

  3. HBase RowKey的设计原则

    1.什么是HBase 1.HBase是面向列式存储的分布式的NoSql数据库: 2.HBase底层是基于HDFS实现的,集群是通过Zookeeper管理的: 3.海量存储,快速访问. 2.什么是Row ...

  4. VI设计中交通工具的设计原则

    VI设计中交通工具的设计原则 编辑:AGO(安可)品牌顾问 VI设计中交通工具的设计原则介绍如下: 1.统一性原则 各类交通工具在进行VI设计中的视觉设计时,应力求总体风格的统一性.统一的风格涉及到基 ...

  5. 面向对象的设计原则最终篇

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 关于面向对象的设计原则我之前已经解释过四种了,分别是单一职责原则,开放关闭原则,里式替换原则, ...

  6. hbase中的row key_hbase中RowKey的设计规则

    在关心到hbase中rowkey设计的时候,说明hbase基本的知识已经了解了.就直接上干货(如果不了解的可以参考我上面一片关于hbase的自我总结的文章,我觉得总结的还是很好的).如果文章中有错误或 ...

  7. 从头捋一遍Java项目中的五大设计原则,就不信你学不会!

    点击关注公众号,实用技术文章及时了解 今天我们一起来聊聊关于设计原则相关的知识点. SOLID五大原则是什么 SRP 单一责任原则 单一责任原则,从名字上我们就能比较好的去理解它.这项原则主张一个对象 ...

  8. UI设计中的交互设计原则有哪些?

    UI设计日新月异,但在变化的背后不变的是设计师对美和易用的追求.在对用户体验的不断研究中,很多复杂的案例被凝聚成简明的设计原则供我们使用.Lawsofux的UX原则便是其中的典范,这些原则久经考验,历 ...

  9. VB中的界面设计原则和编程技巧

    Windows的通用图形界面的出现,使计算机用户不必通过专门的学习就可以得心应手地使用各种Windows的软件.不仅如此,它还是程序设计者在设计Windows程序界面时所必须遵循的标准,这在很大程度上 ...

最新文章

  1. 【Linux】Linux简单操作之管道与重定向
  2. 6月4日云栖精选夜读丨加拿大AI有多强?一年投入60亿,吸引Hinton、Bengio等大神...
  3. 一目了然“之IT运维可视化,让运维不再说难!
  4. sharepoint配置问题解决方案
  5. C语言数组查找(线性查找 折半查找)
  6. 支付宝公布“五一”出境游报告:国人太能花钱了
  7. python开发面向对象基础:封装
  8. 前景检测算法(九)--PBAS算法
  9. Atlas Resources
  10. ardruino控制继电器_用 Arduino 实现带继电器的拨动开关
  11. 茎叶图、箱图是什么,如何用SPSS实现?(图文)
  12. python爬取餐饮数据_使用 Python 分析全国所有必胜客餐厅
  13. Datawhale 计算机视觉基础-图像处理(上)-Task01 OpenCV框架与图像插值算法
  14. 美颜SDK免费版怎么样?应该如何选择美颜SDK?
  15. 【IoT】加密与安全:哈希 Hash 算法用途与原理解析
  16. Python定义常量,设置config.py文件
  17. 嵌入式混合操作系统TOS源码开源
  18. 迷你电脑将取代笨重的台式机
  19. 我的chrome浏览器每次打开,总是重置所有设置,之前下的插件全都没有了
  20. 同步磁阻电机SynRM高频注入无感 FOC 采用高频注入法实现SynRM零低速下无位置传感器起动运行

热门文章

  1. 由曦:王坚在这本书里讲了他的坚持
  2. gVim编辑器——基本设置、常用命令、代码片段
  3. 文案再这么玩 非玩死文案不可!
  4. 【信息量判别块:语义监督:GAN:IVIF】
  5. unity全栈开发是什么意思_为什么你应该尝试“全栈”
  6. 这种MOS管的拆装方法,你知道嘛
  7. 边缘检测 Hough变换 轮廓提取 种子填充 轮廓跟踪
  8. mybatis 日志 Reader entry 乱码
  9. copa-pi测试软件,COPA-DATA SCADA/HMI自动化软件中的先锋——zenOn 6.20
  10. 程序员面试一面、二面、三面区别