本节书摘来自华章出版社《HBase企业应用开发实战》一 书中的第3章,第3.2节,作者:马延辉 孟鑫 李立松 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
3.2 数据模型的重要概念
HBase是一种列式存储的分布式数据库,其核心概念是表(Table)。与传统的关系型数据库一样,表由行和列组成,但HBase同一列可以存储不同时刻的值,同时多个列可以组成一个列族(Column Family),这种组织形式是出于存取性能考虑的。理解HBase的这些概念是很重要的,因为数据模型设计的好坏将直接影响你的查询性能。本节我们将讨论最重要的概念。
3.2.1 表
在HBase中数据以表的形式存储。使用表的主要原因是把某些列组织起来一起访问,同一个表中的数据通常是相关的,通过列族进一步把一些列组织在一起进行访问。用户可以通过命令行或Java API来创建表。表名通常使用Java String类型或byte[](二进制数组)表示,表名作为HDFS存储路径的一部分来使用,因此必须要符合文件名规范,所以构成表名的字符是有限制的。可以直接查看底层存储系统,在HDFS中可以看到每个表的表名都作为独立的目录结构,在某些情况下,用户可能需要查看这部分信息。
HBase列式存储格式允许用户存储大量的信息到相同的表中,而在RDBMS模型中,大量信息则需要切分成多个表存储。通常的数据库规范规则不适用于HBase,因此HBase中表的数量相对较少。
虽然理论上HBase的表是由行和列组成的,但是从物理结构上看,表存储在不同的分区,即不同的Region。每个Region只在一个RegionServer中提供服务,而Region直接向客户端提供存储和读取服务。
与传统的关系型数据库一样,HBase提供了命令行创建表,创建表时只需要指定表名和至少一个列族。列族影响表的物理存储结构,创建表后列族还可以更改,但是比较麻烦。
这就是HBase表中的全部,和传统关系型数据库不同,HBase的表没有列定义,没有类型,这就是HBase被称为无模式数据库的原因。
如何与HBase建立连接呢?可以使用Shell,或者通过Java API,与使用JDBC或ODBC访问关系型数据库不同,访问HBase不需要用户名和密码,没有Schema;将hbase-site.xml配置文件复制一份到自己的工程中,HBase API会读取配置文件完成对HBase的连接。创建连接是一项非常消耗资源的工作,HBase为我们提供了一个连接池,可以更好地管理资源重用。
3.2.2 行键
行键,即Rowkey,是HBase中最为重要的概念之一,在本书4.3节会详细讲解关于行键的设计原则。行键是不可分割的字节数组。行键是按字典排序由低到高存储在表中的,以一个空的数组来标识表空间的起始或者结尾。图3-2展示了行键的排列规则。
这可能和你预期的顺序不太一样,在字典序中,数据按照二进制字节从左至右逐一对比形成最终的次序。例如row-1小于row-2,无论后面如何,row-1都排在row-2之前。
在HBase中行键是唯一的索引,不过在新版本的HBase中考虑了对辅助索引的支持。
为了高效检索数据,应该仔细设计Rowkey以获得最高的查询性能:首先Rowkey被冗余存储,所以长度不宜过长,过长的Rowkey将会占用大量的空间同时会降低检索效率;其次Rowkey应该尽量分布均匀,这样不会产生热点现象;最后是Rowkey唯一原则,必须在设计上保证其唯一性。
在4.3节将学习Rowkey的设计,针对不同的场景Rowkey需要有不同的设计以提高检索的效率。
3.2.3 列族
HBase中的列族是一些列的集合。一个列族中所有列成员有着相同的前缀。比如,列courses:history和courses:math都是列族courses的成员。冒号(:)是列族的分隔符,用来区分列族前缀和列名。Column前缀必须是可打印的字符,剩下的部分(称为Column Qualifier),可以由任意字节数组组成。
在物理上,一个列族的成员在文件系统上都是存储在一起的。因为存储优化都是针对列族级别的,这就意味着,一个列族的所有成员是通过相同的方式访问的。
在创建表的时候至少要指定一个列族,新的列族可以随后按需、动态地加入,但是修改列族要先停用表。应该将经常一起查询的列放在一个列族中,合理划分列族将减少查询时加载到缓存的数据,提高查询的效率,但也不要有太多的列族,因为跨列族访问是非常低效的。
3.2.4 单元格
HBase中的单元格由行键、列族、列、时间戳唯一确定。单元格的内容是不可分割的字节数组。每个单元格都保存着同一份数据的多个版本,不同时间版本的数据按照时间顺序倒序排序,最新时间的数据排在最前面,时间戳是64位的整数,可以由客户端在写入数据时赋值,也可以由RegionServer自动赋值。