大家好,我是易安!
Google发表了三篇论文,即GFS、MapReduce和BigTable,被誉为“三驾马车”,开启了大数据时代。今天我们来聊一下BigTable对应的NoSQL系统HBase,看看它是如何处理海量数据的。
在计算机数据存储领域,关系数据库(RDBMS)一直占据主导地位,以至于在传统企业应用领域,许多应用系统设计都是以数据库为中心,即“先设计数据库,再设计程序”。这导致了关系模型限制了对象模型的发展,并引发了业务对象贫血模型与充血模型之争。
为了解决关系数据库的不足,业界提出了许多方案,其中最著名的是对象数据库。然而,这些数据库的出现似乎只是进一步证明了关系数据库的优越性。直到人们遇到了关系数据库难以克服的缺陷——糟糕的海量数据处理能力及僵硬的设计约束,局面才有所改变。从Google的BigTable开始,一系列可用于处理海量数据存储与访问的数据库被设计出来,这也引发了NoSQL的概念。
NoSQL主要指非关系型、分布式、支持海量数据存储的数据库设计模式。许多专家将NoSQL解读为“Not Only SQL”,表示NoSQL只是关系数据库的补充,而不是替代方案。其中,HBase是这类NoSQL系统的杰出代表。
什么是HBase
HBase是一种分布式的、基于列的NoSQL数据库,具有高可扩展性和高可靠性。它采用了类似BigTable的数据模型,将数据以表格的形式存储在分布式文件系统Hadoop的HDFS上。HBase使用了一种称为HBase Region的机制,将表格水平划分为多个区域,每个区域可以由不同的服务器进行维护。这种机制允许HBase水平扩展,使其可以轻松地处理海量数据。
与传统关系型数据库相比,HBase具有很多优点。首先,它具有非常高的可扩展性,能够处理海量的数据。其次,HBase支持灵活的数据模型,可以存储不同结构的数据。此外,它还具有良好的容错性,即使出现故障,也可以快速地进行数据恢复。
HBase具有处理海量数据的能力,其根本在于与传统关系型数据库设计的不同思路。传统关系型数据库对存储在其中的数据有许多约束。学习关系数据库也需要学习数据库设计范式,这实际上是在数据存储中包含了一部分业务逻辑。相比之下,NoSQL数据库则简单粗暴地认为数据库只是用来存储数据的,业务逻辑应该由应用程序去处理。有时候,简单粗暴也是一种美。
可伸缩架构
我们先来看看HBase的架构设计。HBase为可伸缩海量数据储存而设计,实现面向在线业务的实时数据访问延迟。HBase的伸缩性主要依赖其可分裂的HRegion及可伸缩的分布式文件系统HDFS实现。
HRegion是HBase架构中主要的数据存储进程,应用程序需要通过与HRegion通信来进行数据读写操作。在HBase中,数据被分成多个HRegion进行管理,因此,如果应用程序需要访问某个数据,必须先找到相应的HRegion,然后将读写操作提交给该HRegion来完成数据存储操作。
HRegionServer是HBase架构中的物理服务器,每个HRegionServer可以启动多个HRegion实例。当一个HRegion中写入的数据达到配置的阈值时,该HRegion会分裂成两个HRegion,然后将新的HRegion在整个集群中进行迁移,以实现HRegionServer的负载均衡。
每个HRegion存储一段Key值区间[key1, key2)的数据。所有HRegion的信息,包括存储的Key值区间、所在HRegionServer地址、访问端口号等,都记录在HMaster服务器上。为了保证HMaster的高可用性,HBase会启动多个HMaster,并通过ZooKeeper选举出一个主服务器。
HBase架构中的HRegion、HRegionServer和HMaster等组件,是为了实现海量数据的存储和快速查询而设计的。HRegion作为数据存储的基本单元,通过HRegionServer进行管理,而HMaster则负责管理HRegion的元数据和整个集群的状态,从而保证HBase集群的高可用性和性能。
下面是一张调用时序图,应用程序通过ZooKeeper获得主HMaster的地址,输入Key值获得这个Key所在的HRegionServer地址,然后请求HRegionServer上的HRegion,获得所需要的数据。
数据写入过程也是一样,需要先得到HRegion才能继续操作。HRegion会把数据存储在若干个HFile格式的文件中,这些文件使用HDFS分布式文件系统存储,在整个集群内分布并高可用。当一个HRegion中数据量太多时,这个HRegion连同HFile会分裂成两个HRegion,并根据集群中服务器负载进行迁移。如果集群中有新加入的服务器,也就是说有了新的HRegionServer,由于其负载较低,也会把HRegion迁移过去并记录到HMaster,从而实现HBase的线性伸缩。
HBase的核心设计目标是解决海量数据的分布式存储,和Memcached这类分布式缓存的路由算法不同,HBase的做法是按Key的区域进行分片,这个分片也就是HRegion。应用程序通过HMaster查找分片,得到HRegion所在的服务器HRegionServer,然后和该服务器通信,就得到了需要访问的数据。
可扩展数据模型
传统的关系数据库为了保证关系运算(通过SQL语句)的正确性,在设计数据库表结构的时候,需要指定表的schema也就是字段名称、数据类型等,并要遵循特定的设计范式。这些规范带来了一个问题,就是僵硬的数据结构难以面对需求变更带来的挑战,有些应用系统设计者通过预先设计一些冗余字段来应对,但显然这种设计也很糟糕。
那有没有办法能够做到可扩展的数据结构设计呢?不用修改表结构就可以新增字段呢?当然有的,许多NoSQL数据库使用的列族(ColumnFamily)设计就是其中一个解决方案。列族最早在Google的BigTable中使用,这是一种面向列族的稀疏矩阵存储格式,如下图所示。
这是一个学生的基本信息表,表中不同学生的联系方式各不相同,选修的课程也不同,而且将来还会有更多联系方式和课程加入到这张表里,如果按照传统的关系数据库设计,无论提前预设多少冗余字段都会捉襟见肘、疲于应付。
而使用支持列族结构的NoSQL数据库,在创建表的时候,只需要指定列族的名字,无需指定字段(Column)。那什么时候指定字段呢?可以在数据写入时再指定。通过这种方式,数据表可以包含数百万的字段,这样就可以随意扩展应用程序的数据结构了。并且这种数据库在查询时也很方便,可以通过指定任意字段名称和值进行查询。
HBase这种列族的数据结构设计,实际上是把字段的名称和字段的值,以Key-Value的方式一起存储在HBase中。实际写入的时候,可以随意指定字段名称,即使有几百万个字段也能轻松应对。
高性能存储
传统的机械式磁盘的访问特性是 连续读写很快,随机读写很慢。这是因为机械磁盘靠电机驱动访问磁盘上的数据,电机要将磁头落到数据所在的磁道上,这个过程需要较长的寻址时间。如果数据不连续存储,磁头就要不停地移动,浪费了大量的时间。
为了提高数据写入速度,HBase使用了一种叫作 LSM树 的数据结构进行数据存储。LSM树的全名是Log Structed Merge Tree,翻译过来就是Log结构合并树。数据写入的时候以Log方式连续写入,然后异步对磁盘上的多个LSM树进行合并。
LSM树可以看作是一个N阶合并树。数据写操作(包括插入、修改、删除)都在内存中进行,并且都会创建一个新记录(修改会记录新的数据值,而删除会记录一个删除标志)。这些数据在内存中仍然还是一棵排序树,当数据量超过设定的内存阈值后,会将这棵排序树和磁盘上最新的排序树合并。当这棵排序树的数据量也超过设定阈值后,会和磁盘上下一级的排序树合并。合并过程中,会用最新更新的数据覆盖旧的数据(或者记录为不同版本)。
在需要进行读操作时,总是从内存中的排序树开始搜索,如果没有找到,就从磁盘 上的排序树顺序查找。
在LSM树上进行一次数据更新不需要磁盘访问,在内存即可完成。当数据访问以写操作为主,而读操作则集中在最近写入的数据上时,使用LSM树可以极大程度地减少磁盘的访问次数,加快访问速度。
总结
HBase作为Google BigTable的开源实现,完整地继承了BigTable的优良设计。架构上通过数据分片的设计配合HDFS,实现了数据的分布式海量存储;数据结构上通过列族的设计,实现了数据表结构可以在运行期自定义;存储上通过LSM树的方式,使数据可以通过连续写磁盘的方式保存数据,极大地提高了数据写入性能。这些优良的设计结合Apache开源社区的高质量开发,使得HBase在NoSQL众多竞争产品中保持领先优势,逐步成为NoSQL领域最具影响力的产品。
如果本文对你有帮助的话,欢迎点赞分享,这对我继续分享&创作优质文章非常重要。感谢 !
本文由mdnice多平台发布