可能是最易懂的Hbase架构原理解析

作者:微信小助手

发布时间:2019-04-27T09:34:49

小史是一个非科班的程序员,虽然学的是电子专业,但是通过自己的努力成功通过了面试,现在要开始迎接新生活了。


今天,小史的姐姐和吕老师一起过来看小史,一进屋,就有一股难闻的气味。

可不,小史姐姐走进卫生间,发现地下一个盆子里全是没洗的袜子。

小史:当然不是,盆里的袜子满了,就先放到这个桶里,然后再继续装,等到桶里的袜子满了,然后才放到洗衣机里一次洗完,这样不仅效率高,而且节省水电费。

小史洋洋得意地介绍起自己洗袜子的流程。

小史一听就有点不高兴,全世界都黑程序员,没想到自己还没变成程序员就被自家姐姐黑了。

说完就进自己房间,把姐姐和吕老师晾在外面。小史姐姐也意识到不该拿程序员开玩笑,但现在也不知道该怎么办,就看着吕老师。

吕老师走进小史的房间。

HBase是啥


小史:别吹了,构建在 HDFS 上除了能存储海量数据之外,缺点一大堆,上次你给我介绍的 HDFS 缺点我可没忘啊,不支持小文件,不支持并发写,不支持文件随机修改,查询效率也低。


小史仔细回忆起 HDFS 来:

吕老师:HDFS 确实有很多缺点,但是 HBase 却是一个支持百万级别高并发写入,支持实时查询,适合存储稀疏数据的分布式数据库系统。

吕老师:HBase 主要用于大数据领域,在这方面,确实比 MySQL 要厉害得多啊,它和 MySQL 的存储方式就完全不一样。MySQL 是行式存储,HBase 是列式存储。

列式存储


吕老师:没错,这就是行式存储系统存储稀疏数据的问题,我们再来看看列式存储如何解决这个问题,它的存储结构是这样的:

小史:这个我看懂了,相当于把每一行的每一列拆开,然后通过 Rowkey 关联起来,Rowkey 相同的这些数据其实就是原来的一行。

吕老师:你这里只说到了一个好处,由于把一行数据变成了这样的 key-value 的形式。


所以 HBase 可以存储上百万列,又由于 HBase 基于 HDFS 来存储,所以 HBase 可以存储上亿行,是一个真正的海量数据库。

吕老师:这就是 HBase 的威力呀,还不只如此,其实很多时候,我们做 Select 查询的时候,只关注某几列,比如我现在只关心大家的工资,传统的按行存储,要选出所有人的工资是怎么办的呢?


小史:哦,我大概明白了,原来是这样,所以 HBase 的查询效率也很高,但是我有个问题啊,如果我就要查我的所有信息,这是一行数据,HBase 查询起来是不是反而更慢了呢?

列簇


吕老师:列簇,顾名思义,就是把一些列放在一起咯,在 HBase 中,会把列簇中的列存储在一起,比如我们把和工作相关的 Salary 和 Job 都放在 Work 这个列簇下。


那么大概是这样的:

小史:哦,我明白了,这样的话,一个列簇中的列会被一次就拿出来,如果我要查所有列的信息的话,把所有信息都放在一个列簇就好了。

注意:HBase 中,其实所有列都是在列簇中,定义表的时候就需要指定列簇。生产环境由于性能考虑和数据均衡考虑,一般只会用一个列簇,最多两个列簇。


Rowkey 设计


注:当然,有些中间件把 SQL 翻译成 HBase 的查询规则,从而支持了 SQL 查 HBase,不在本文讨论范围内。

小史:啊?这和我想象的不一样啊,如果我想查询工资比 20w 多的记录,在 MySQL 中,只要用一条很简单的 SQL 就行啊,这在 HBase 中怎么查呢?

吕老师:在 HBase 中,你需要把要查询的字段巧妙地设置在 Rowkey 中,一个 Rowkey 你可以理解为一个字符串,而 HBase 就是根据 Rowkey 来建立索引的。

不熟悉 B+ 树的同学可以看这篇文章HBase 的 HFile 底层也是一样的原理。

吕老师:假设员工工资 9999w 封顶,查询的时候可能根据员工工资查询,也可能根据名字查询一个特定的员工,那么 Rowkey 就可以这样设计:

注意:以上 Rowkey 是简化版设计,只是为了讲清楚范围查询。实际使用中由于 Rowkey 需要考虑散列性,所以可能不会这么用。后文会具体探讨散列性。

吕老师:HBase 提供了三种查询方式:

  • 全表扫描,Scan。

  • 根据一个 Rowkey 进行查询。

  • 根据 Rowkey 过滤的范围查询。


比如你要查工资不少于 20w 的记录,就可以用范围查询,查出从 startRow=0020 到 stopRow=9999 的所有记录,这是 HBase 直接支持的一种查询方式哦。

吕老师:这里要注意几点,首先,Rowkey 是按照字符串字典序来组织成 B+ 树的,所以数字的话需要补齐,不然的话会出现 123w 小于 20w 的情况,但是补齐的话,你就会发现 020w 小于 123w。

小史:哦,明白了,这都很好理解,因为 Rowkey 是字符串形式,所以肯定是按照字符串顺序排序咯。


而且 Rowkey 有点类似于 MySQL 中的主键吧,所以保证其唯一性也是可以理解的。


还有就是因为每个 key-value 都包含 Rowkey,所以 Rowkey 越短,越能节省存储空间。