通过作者Amandeep khurana的一篇经典论文Introduction to hbase Schema Design中提到的一个例子,深刻理解HBase的基本概念(HBase最简洁的经验总结)和实践中的使用场景。根据论文内容,用简化的需求和技术文档的形式一步步呈现一个完整的HBase的开发。
需求描述
Twitter用户关注功能(Twitter relationships)
- 用户可以关注自己的喜欢的用户
- 用户取消关注已关注的用户
- 用户可以看见自己关注了谁
- 用户可以看见谁关注了自己
- 查询用户是否关注了另一个用户
需求分析
根据需求描述,在技术层面需要执行如下的数据库的读写操作:
- 读操作:
read-1. 查询一个用户关注了谁?
read-2. 用户A关注了用户B吗?
read-3. 谁关注了用户A? - 写操作:
write-1. 用户A关注了用户B
write-2. 用户A取消关注用户B
技术选型
HBase做为底层数据存储
技术架构设计
按照作者的思路如下:
Version1
HBase表每一个用户存储在一行,他所关注的每一位用户存储在一列中。HBase表结果如图Figure4,Figure5为数据存储的一个例子。
需求分析中read-1,通过读取行获取指定用户所关注了谁。read-2可以满足,只是当查看被关注的指定用户时,需要获取一行中所有的列数据,并且遍历数据确定是否存在指定的被关注的用户,这样的操作成本太高,尤其当数据量大的时候更是如此。read-3更是需要查询整张表来确定谁关注了指定用户。
write-1操作更加复杂,因为没有一个计数器表明下一个数字是多少,无法直接添加用户,只能遍历所有列。write-2也是如此遍历所有列找到被关注的用户,删除列。
Version2
Figure6展示了一个更好的改进方案,增加了一个计数器用于记录用户关注了多少人。Figure7展示了一个数据实例。
Figure 6的设计似乎解决了write-1操作的问题,实际上write-1操作添加关注用户时是需要过滤重复的用户,因为一个用户不可以关注另外一个用户两次。其他的操作问题没有得到解决。取消关注仍旧需要遍历所有列,找到需要删除的列,删除之后会留下一个数字不连续的缺口。在这版设计中最大的问题还在于添加关注时,依次查找counter--更新counter--HBase增加一列,这一系列操作是非原子性操作的,HBase不支持跨行的事务性操作,需要我们在客户端自己保证。
Version3
HBase的列是动态并且以byte[]进行存储,这一点与传统的关系型数据库截然不同。我们可以定义列名随意变化的HBase表,如图Figure8所示。这里counter不再被需要,而且write-1增加用户时也不需要滤重,HBase会自动锁定到对应的列中。取消关注也变得简单起来,直接删除对应列即可。
Version3的设计解决了所有写操作的问题,和write-1,write-2问题。遗留下来的是read-3的问题,谁关注了用户A?HBase索引只能通过rowkey,目前的设计要解决这个问题需要遍历整张表。那么意味着我们需要对被关注者建立一个相应的索引,不需要大规模的遍历即可查找。有两种方案可以解决:
- 创建一张Figure8的反向的HBase表,记录一个用户被哪些人关注了。
- 在Figure 8的表中通过设计rowkey保存这些信息。
Version4
Figure9是一个更好优化方案。rowkey的设计包含关注者和被关注者,列族名被简化为f。如之前所介绍,短列族名是被推荐的,更少的数据量传输,可以减少I/O的负载。首先,获取一个用户关注了谁变成了一个短的Scan,而不是之前的Get操作,性能上几乎没用影响;关注、取消关注、A是否关注了B,变成了一个简单的删除和读取操作,不再需要遍历所有列实现,尤其当一个用户关注的人特别多时,性能提升更多。
数据示例如图Figure10,这张表中因为人名长度的不一致导致rowkey长度也是不一致的。由于每次传输的数据长度不同,很难了解执行的性能问题。求哈希值是一个解决方案,为了保证rowkey长度的一致性,我们可以对用户ID进行求哈希,再把关注者和被关注者合并组成rowkey。每次查询时,计算用户ID的哈希值生成rowkey即可。
Version5
改进的HBase表如图Figure11。对于read-3的问题仍旧是性能上的瓶颈,当然这里设计还有考虑到用户的其他操作,例如修改姓名等,那么所有与其相关的行就需要相应修改。这个示例只是一个关于HBase简单使用的展示,不是一个规范化的实现。
结论
根据论文Introduction to hbase Schema Design中提到的Twitter用户关注模型,设计的一个基于HBase的实现。仍旧具有改进的空间,在我们日常工作中这样的用户关注模型的需求不在少数,凡是互动的应用都会具有关注的功能,那么这个例子在实际中是具有借鉴意义的。这个例子也是经典的一个例子,面试中也极为可能遇到。学习成熟的实践例子,也可以帮助掌握基础,拓宽视野。