Hbase系列(一)---- Hbase究竟是一个怎样的数据库(基础原理)
提到hbase,我们第一反应是这是一个海量数据场景下使用的数据库。但是Hbase究竟是怎么样存数据的?他为什么会比其他传统关系型数据库在海量数据的场景下,更具有优势?在一两年前笔者刚接触hbase的时候,也是一头雾水,现在闲余时间,对这方面的认识做一些总结。
一.Hbase的储存模式
在谈到Hbase的特点时,相信大家一定听说过,Hbase是一个列式数据库。Hbase包含了大量关系型数据库的概念(表、行、列),从视图的角度来说,Hbase中的数据是以表的形式进行组织的,这和关系型数据库是一样的,但是从物理的角度上来看,这样理解Hbase是不正确的。在bigTable的论文中,称Hbase从本质上来说就是一个“Map”,没错,他就是一个“Map”,或者读在这里,你会大致感觉得到Hbase跟传统关系型数据库的区别。
Hbase是一个“Map”,由(Key Value)构成,但与普通的Map不同,Hbase是一个稀疏的,分布式的,多维排序的Map。我们先了解一下Hbase的基本概念:
table:表,一张表包含多行数据
row:行,一行数据包含一个唯一标识rowkey、多个column以及对应的值。在Hbase中,一张表中所有的row都按照rowkey的字典顺序有小到大排序。
column:列,与关系型数据库中的列不同,Hbase中的cloumn由column family(列簇)以及qualifier(列名)两部分组成,两者中间使用“:”相连。
column family在表创建的时候要指定,用户不能随意增减,一个column family下可以设置任意多个qualifier,因此可以理解为Hbase中的列可以动态增加。
timestamp:时间戳,每个cell在写入Hbase的时候都会默认分配一个时间戳作为cell的版本(这个时间戳也可以是用户自定义),Hbase支持多版本特性,即统一rowkey、column下可以拥有多个value的存在。这些value用timestamp作为版本号,版本越大表示数据越新。
cell:单元格,这个是重点,每个单元格由五个元素组成(row、column、timestamp、type、value),其中type表示Put/Delete这样的操作类型,timestamp代表这个cell的版本。这个结构在数据库中实际是以KV结构存储的,其中(row、column、timestamp、type)是K,value是V。
对于这样的一组数据,在Hbase中,如果获得你想要的那个准确的值?
(rowkey1, eduInfo, university, put, timestamp2) -> d
这样一看,是不是有点理解为什么Hbase其实就是一个Map(K -> V)。
二.Hbase的储存特点
上面我们提到过,base是一个稀疏的,分布式的,多维排序的Map,现在我们弄清楚他为什么是一个Map了,接下来我们就要弄清楚什么是稀疏的,分布式的,多维排序。
稀疏:上面的图中我们可以看到,在一行数据里面,部分column对应的value是空的,也就是说他是没有值的,在关系型数据库中,这种情况一般会填充一个null值上去。但是我们回顾一下Hbase列的特性,理论上列是可以无限扩充的,假如我们给每个空的列都赋予一个null值,会造成很大的空间浪费,因此,Hbase中空值不需要任何填充,这也为Hbase列可以无限拓展的一个重要条件。
分布:这个非常容易理解,Hbase的数据不是集中在一台机器上面的,而是分布在多个regionServer上面的,至于regionServer是什么,在后面的章节会讨论到。
多维:这个其实就是指,Hbase跟普通的map不一样的地方在于,Hbase里面的Key并不是一个单一的值,它是由(rowkey,column,timestamp,type)组成的,他是一个复合数据结构。
排序:Hbase里面的数据是有序的,一般我们会说他是根据rowkey进行排序的,但是实际上,他是针对Key进行排序的,在Key里面,会先根据rowkey进行排序,对于rowkey相同的,会根据column family:qualifier进行排序,如果还是相同,则会根据timestamp进行排序。
三.行式储存和列式储存
行式储存(mysql,oracle)会将一行数据存储在一起,一行数据写完之后再接着写下一行,这种储存模式,在我们获取一行数据的时候是很高效的,但是如果某个查询只需要读取表中指定的列的数据,那行式储存的模型下,就要先获取一整行数据,然后在一行数据里面截取需要的列,这无疑是很浪费的。因此,这类系统适合OLTP类型的处理,对OLAP类的并不擅长。
列式储存对只查找某列数据的请求非常高效,只需要连续读出所有待查目标列,然后遍历处理即可。但是同样的,列式储存对于获取一整行数据的效率就不怎么高了。另外,因为相同列的数据一般拥有相同的类型,因此列式储存具有天然高压缩的特性。
列簇式储存其实是一种介乎于行式储存和列式储存之间的储存模式,假如一张表只设置一个列簇,这种设计模式就等同于行式储存。而一张表里面有大量列簇,每个列簇里面只有一个列,这就等同于列式储存。