目录
(一)概述
长期以来,传统的关系型数据库(Mysql)等因为其易懂的关系模型、高效的查询引擎和易用的查询语言而被广泛应用,但在一些互联网应用场景中,数据量的膨胀非常快,基于关系型数据库的方案很难满足系统扩展的需求。同时,引入了分布式文件系统HDFS之后,除了直接以文件形式保存的数据以外,还有大量的结构化和半结构化数据,这类数据通常需要支持更新操作,例如随机插入和删除,例如在Facebook上,用户的评论内容是随机的,但是评论的ID、评论人和评论对象是有序的,而且这种有序的数据是需要随机插入和删除操作的,这使得HDFS难以适应OLAP的场景。
为了解决以上问题,HBase应运而生,作为Google BigTable的开源实现,非常适合存储海量的结构化或者半结构化数据。HBase具备以下优点:
1.极好的扩展性:随着数据量的增加,架构支持水平扩展以满足存储需求;
2.弱化ACID需求:关系型数据库的一个优点是支持ACID,但在HBase场景下,对事务的要求较低,可以选择性的降低一些性能,强化查询等性能;
3.良好的容错性:HBase倾向于用较低的成本实现横向扩展方案。
(二)HBase数据模型
与数据库的Database和Table的概念类似,HBase将这两项称之为namespace和table,一个namespace能够包含多个table,HBase内置了两个默认的namespace:
1.hbase:系统内建表,包括了namespace和meta表;
2.default:用户建表时未指定namespace的表都创建在这里。
HBase表有一系列行构成,每行数据都有一个rowkey,以及若干个column family构成,每个column family可以包含无限多的列。因此,可以将HBase看成一个有序多维映射表,也可以看作是一个key/value存储系统,rowkey作为key,其他部分是value。相关概念解释如下:
1.rowkey:HBase表中的数据都是以rowkey作为标识的,rowkey类似于关系型数据库中的“主键”,每行数据都有一个rowkey,唯一标识该行,是定位数据的索引。同一张表内,rowkey是全局有序的。rowkey没有数据类型,以字节数组(byte[])的形式保存。
2.column family:HBase表中的数据是按照column family组织的,每行数据拥有相同的column family,column family属于schema的一部分,定义表结构时就需要指定好。column family是访问控制的基本单元,同一个column family的数据再物理上会存储在同一个文件内。
3.column qualifier:column family内部列标识,HBase每列数据可以通过family:qualifier来做唯一标识。Qualifier不属于schema的一部分,可以动态制定,且每行数据可以有不同的schema。跟rowkey一样,column qualifier也是没有数据类型的,以字节数组(byte[])的形式保存。
4.cell:通过rowkey,column family + column qualifier可以唯一定位一个cell,内部保存了多个版本的数值,默认情况下,每个数值的版本号是写入时间戳。C
5.timestamp:cell内部数据是多版本的,默认将写入时间戳作为版本号,用户可以根据自己的业务需求设置版本号,timestamp的数据类型为long类型。每个column family保留最大版本数可以单独配置,默认是3,如果读取数据时未指定版本号,HBase只会返回最新版本的数值。如果一个cell内部数据超过最大版本数,旧的版本数据会被自动删除。
HBase的数据模型如下所示:
HBase是列簇式存储引擎,数据在存储介质中按照下图所示形式保存:
HBase同一表中的数据是按照rowkey升序排列的,同一行中的不同列是按照column qualifier升序排列的,同一cell中的数值是按照版本号降序排列的,下图是HBase表从逻辑视图到物理视图的映射关系:
HBase是列式存储引擎吗?
(三)HBase基本架构
为了将数据表分布到集群中以提供并行读写服务,HBase按照rowkey将数据划分成为多个固定大小的有序分区,每个分区被称为一个“region”,这些region会被均衡地存在在不同的节点上。如果HBase是构建在HDFS之上的,那么所有的region均会以文件的形式保存到HDFS上,以保证这些数据的高可靠存储。
HBase采用了经典的master/slave架构,与HDFS不同的是,它的master与slave不直接互连,而是通过引入Zookeeper来让两类服务解耦,这使得Master变得完全无状态,避免了master宕机导致的整个集群不可用。HBase各个服务的功能如下:
HMaster:HMaster可以存在多个,主HMaster由Zookeeper动态选举产生,当主HMaster出现故障后,系统可由Zookeeper动态选举出新的HMaster来接管。HMaster主要负责协调RegionServer的均衡性和元信息的管理,为用户提供增删改查的操作。
RegionServer:RegionServer负责单个Region的存储和管理,例如文件的切分等,并与Client进行交互,处理读写请求。
Zookeeper:Zookeeper内部存储着有关HBase的重要元信息和状态信息,担任着Master与RegionServer之间的服务协调角色,具体包括:集群中只有一个Master、存储Region的寻址入口、实时监控RegionServer的上线和下线信息、存储HBase的schema和table元数据等功能。
Client;提供HBase的访问接口,并与RegionServer交互读写数据,维护cache以加快对HBase的访问。
(四)HBase内部原理
HBase是构建在HDFS之上的,利用HDFS的高可靠性存储数据文件,以实现对Region定位、读写流程和文件管理等功能的实现。相关原理如下
1.Region定位
HBase支持put、get、delete和scan等基础操作,所有操作的基础是region定位:给定一个rowkey或者是rowkey区间,其基本步骤为:客户端与Zookeeper交互,查找hbase:meta系统表所在的RegionServer,随后客户端与RegionServer进行交互,获取rowkey所在的RegionServer信息,执行该rowkey的相关操作。图示流程如下:
2.RegionServer内部关键组件
RegionServer内部关键组件如下图所示:
BlockCache:读缓存,负责缓存频繁读取的数据,采用了LRU置换策略。
MemStore:写缓存,负责暂时缓存未写入磁盘的数据,并在写入磁盘前对数据进行排序,每个region内的每个column family拥有一个MemStore。
HFile:一种支持多级索引的数据存储格式,用户保存HBase表中的实际数据,所有HFile均保存在HDFS中。
WAL:即Write Ahead Log,保存在HDFS上的日志,用于保存那些未持久化到HDFS中的HBase数据,以便RegionServer宕机后恢复这些数据。
3.RegionServer读写操作
RegionServer读写流程如下图所示:
(1)写流程
为了提高HBase的写效率,RegionServer将所有收到的写请求暂时写入内存,之后再顺序刷新到磁盘上,进行将随机写转化为顺序写以提升性能。具体流程为:RegionServer收到写请求后,将数据写入内存数据结构MemStore中,并通知客户端数据写入成功。当MemStore所占内存达到一定阀值之后,RegionServer会将数据刷新到HDFS中,保存成HFile格式的文件。
(2)读流程
由于写流程可能使得数据位于内存或者磁盘上,因此读取数据时,需要从多个数据存放位置中寻找数据,包括BlockCache、MemStore及HFile,并将读到的数据合并在一起返回给用户。查找的顺序为:BlockCache、MemStore、HFile。
4.MemStore与HFile组织结构
MemStore负责将最近写入的数据缓存到内存中,它是一个有序的key/value内存存储格式,每个column family拥有一个MemStore,格式如下图所示:
HFile是Google SSTable的开源实现,作为有序的key/value磁盘存储格式,带有多级索引,以方便定位数据,HFile中的多级索引类似于B+树。HFile格式如下图所示:
HFile具有以下特点:
(1)数据按照key以升序排列;
(2)文件由若干64KB的block构成,每个block包含一系列key/value;
(3)每个block拥有自己的索引,称之为“leaf index”,按照key构建;
(4)每个block的最后一个key被放倒“intermediate index”中;
(5)每个HFile文件包含一个“root index”,指向“intermediate index”;
(6)每个文件末尾包含一个tralier域,记录了block meta,bloom filter等信息。
(五)HBase访问方式
常用的HBase Shell命令如下:
常用的HBase Java API命令如下: