【IT168 专稿】Apache HBase将自身描述为“Hadoop数据库”,其实这样的表达多少有点混乱,因为人们通常将Hadoop视为一套高人气MapReduce处理框架。不过Hadoop事实上只是一个总称,其下涵盖了整个技术生态系统;HBase利用其中一部分构建起一套分布式面向列的数据库方案,其设计思路与谷歌Bigtable如同一辙。HBase并没有直接使用Hadoop的MapReduce能力,而是通过自身与Hadoop相集成的方式成为MapReduce作业的源头或者目标。
HBase的特点在于高度可扩展性、出色的可靠性以及我们能够在面向列数据库中所能获取到的最为卓越的灵活性。虽然表与列族必须提前加以定义,但大家仍然可以在数据库运行过程中添加新的列。HBase还提供强大的行级一致性、内置版本控制以及用于提供触发机制与存储流程的“协进程”。
作为一套设计目的面向大量数据集查询的数据库方案,HBase在读取性能方面作出了深度优化。从写入角度出发,HBase则以保持一致性作为首要诉求。相比之下,与Cassandra追求的“最终一致性”不同,HBase并不提供多种多样的一致性级别设置(这些设置是为了在单一或者一定数量的节点接受写入操作之后、将内容变更同步到集群整体当中)。因此,HBase对于写入一致性的高度坚持必然会对其运行速度造成负面影响。
HDFS——即Hadoop分布式文件系统——是Hadoop生态系统当中的基石,自然也成为HBase数据库的运作根基。作为一套专门面向商用硬件及成员节点故障容错环境所设计的文件系统,HDFS最擅长应对那些倾向于对大型数据集进行不间断访问的批处理系统。从表面上看,这种特性与大家在HBase数据库系统中所预期的随机存取操作似乎并不匹配。不过HBase采取了一系列措施来弥补由HDFS自身特性带来的不协调状况。
作为Hadoop堆栈中的另一项技术(不过最新版本的Hadoop MapReduce引擎已经不再使用),Zookeeper是一项分布式通信与协作服务。Zookeeper负责维护一套同步化的内在内数据库结构,可以同时接受多个客户端进行访问。这种数据结构的组织方式与文件系统非常相似,只不过该结构当中的组件(即znode)可以作为数据容器以及层级树当中的元素。大家可以将它想象成一套文件系统,其中的文件本身也可以作为目录存在。
测试中心记分卡 | ||||||
易用性 | 管理性 | 说明文档 | 安装及设置 | 性价比 | 总体评分 | |
30% | 30% | 15% | 15% | 10% | ||
Apache HBase 0.94.12 | 7 | 7 | 7 | 7 | 9 | 7.2 GOOD |
HBase利用Zookeeper协调集群活动并监视各成员节点的运行状况。换句话来说,大家在运行一套HBase集群的同时也必须同时运行Zookeeper。HBase会在默认情况下运行并管理Zookeeper,不过大家也可以通过配置来单独管理Zookeeper设置。大家甚至可以将Zookeeper服务器进程与其它HBase进程一道运行在同一套硬件之上,不过这种作法并不推荐、特别是对于高容量HBase集群而言更是如此。
HBase如何运作
初一上手,HBase的数据模型给人似曾相识之感。这是一套由行构成的表,每一行——从本质上讲只是一堆字节——由惟一的行键加以标记。在创建表的时候,选择合适的行键非常重要,这是因为HBase需要利用行键来引导数据的划分——也就是说,行键决定了数据将以怎样的方式分布到整个集群当中。行键还决定着表内各行的排列顺序。
更准确地说,行相当于一系列键/值对的集合体,其中键作为列的标识符、而值作为单位内容则存在于特定行与列的交叉位置。不过由于HBase是一款面向列的数据库,因此同一套表中的两个行并不需要拥有同样的列。而让问题更趋于复杂的是,HBase当中还提供数据版本控制功能。某个值(也就是基本单元)的实际位置由元组决定,其中包含{行键,列键,时间戳}。除此之外,多个列也可以汇集起来形成列族,这一概念能够帮助数据库设计人员进一步控制访问特性——因为同一列族中的全部列都将被保存在彼此相邻的位置。
HBase当中的写入操作首先将数据记录在提交日志当中(也就是‘预写日志’),而后再将内容写入至名为MemStore的内部存储结构当中。在MemStore填写完毕后,它会以所谓HFile的实体形式被刷新至磁盘上。HFile以数据库序列的形式进行存储,文件末端还会添加一套相应的索引。该索引同时也会被保留在内在当中,从而加快面向HFile内数据的搜索速度。
HFile在写入完成后无法进行内容变更。如果某个键被删除,HBase会记录一条特殊的“墓碑”标记来指明删除操作。在HFile经过定期更新后,墓碑记录也会随之被移除(被删除的数据也将一同消失)。
HBase希望通过MemStore机制尽量满足用户对于读取操作的性能需求。如果无法借此实现,HBase就会检查另一套内存内结构,也就是BlockStore。BlockStore是一种读取缓存机制,其设计目的在于利用内存向使用者将会访问频率较高的读取内容,这就避免了磁盘读取所带来的响应延迟。
HBase按区域对行进行划分,而区域的定义则由一系列行键来实现。HBase集群当中的每个区域都由对应的RegionServer进程来管理。通常情况下,每个HBase节点上都存在一个RegionServer进程。随着数据规模的不断增长,HBase会进一步划分区域并将相关数据迁移到集群中的其它节点上、借此达到负载平衡的目标。
HBase的集群架构并非完全对称。举例来说,每个集群都必须拥有一个单一的活动主节点。主节点可以(也应该)由多个节点构成,但在集群启动时、其它节点只作为后备主节点充当替补,因此实质上的活动主节点仍然只有一个。主节点的责任在于监控区域服务器、处理区域服务器故障转移工作以及协调区域划分。
如果主节点发生崩溃,整套集群仍然能够以稳定状态模式运作——就是说能够继续管理读取与写入请求,但无法执行任何需要主节点介入的协调工作(例如负载平衡调整)。有鉴于此,大家最好指定多个主节点;这样在区域主节点发生故障时,替补主节点就能快速跟上、让集群始终保持良好的运作状态。
大家可以在本机文件系统上运行HBase来进行开发工作,不过对于HBase集群来说、运行在HDFS上似乎并不是个好选择——理由我们在前文中已经提到。尽管底层文件系统主要面向流程操作,HBase仍然能够带来出色的快速随机I/O表现。它通过将批量内存内写入与日志结构化合并树支持下的持久性磁盘数据写入相结合的方式实现了这一奇迹般的效果。也就是说,所有随机写入操作都将在内存当中进行;而在向磁盘进行写入时,相关数据会首先经过归类、而后配合排序索引以连续形式进行写入。随机读取操作同样首先指向内存,这一点我们之前也有提到。如果无法在内存中找到请求指向的数据,后续磁盘搜索流程同样能够快速完成——这要归功于数据库本身对于数据进行的排序与索引。
HBase的实际运用
HDFS的设计原则在于简化将计算资源(例如在MapReduce操作当中)向待处理数据的移动过程,而非将数据转移至计算资源处。有鉴于此,HDFS本身并不能保证相关数据片段(例如数据库中的行)实现协同定位。这意味着由特定RegionServer负责管理的数据块并没有被保存在RegionServer所处的同一台物理主机中。不过HDFS提供了多种机制来通告数据块位置,更重要的是能够根据需求对数据块位置进行重新调整。HBase利用这些机制进行数据块迁移,这样它们就能够始终与自身RegionServer进行协同定位。
虽然HBase并不支持事务型操作,也没有采取最终一致性保障,但它仍然具备很强的一致性控制能力——至少从单独的行来看是如此。HBase当中没有数据类型的概念;所有内容都被保存在一系列字节。不过HBase明确定义了一种特殊的数据类型,也就是“计数器”,它能够提供一种原子性递增操作——适用于那些需要统计访问次数的页面。大家可以通过单一调用在同一行中增加计数器的数值,同时又无需对该行加以锁定。请注意,计数器会与写入操作进行同步(多次写入将始终执行一致的增量方式)但并一定需要与读取操作保持一致。
HBase shell其实是一套运行在JRuby当中、经过修改的交互式Ruby shell,即相当于在Java虚拟机内运行Ruby。大家可以在交互式Ruby shell中实现的一切操作都可以在HBase shell上重现,这就意味着HBase shell完全可以充当一套非常强大的脚本编写环境。
最新版本的HBase shell提供一系列面向对象的接口,旨在对HBase表加以操作。举例来说,大家可以将一个表分配到JRuby情境下,然后利用利用标准点符号在表对象中建立方法。假设大家已经定义好一个表并将其分配给了myTable变量,则可以通过以下格式将数据写入到该表当中:
myTable.put '<row>', '<col>', '<v>'
其中v代表值,row与col则分别代表行和列。其表意是将某值写入到某列中的某行内。
HBase还拥有一系列第三方管理GUI可供选择,其中最典型的例子就是hbase-explorer。HBase自身包含多款内置Web监控工具。HBase主节点会利用端口60010支持Web界面。对其进行浏览,大家会找到与主节点本身相关的多种信息,其中包括开始时间、当前Zookeeper端口、区域服务器列表以及各区域服务器的平均区域数量等等。其中还会提供一份表,点击该表即可查看多种信息,例如该表组件由哪些区域服务器负责托管等。该页面还能够控制表压缩或者表区拆分的初始化进程。
除此之外,每个区域服务器节点会在端口60030上运行一套监控Web界面。在这里,大家可以查看多项指标,包括读取与写入延迟等,不同项目的统计结果都被转化为百分比表示方式。再有,我们也可以查看当前区域服务器管理下的各个区域的统计信息,并对该服务器上的活动进程进行转储。
HBase参考指南当中包含入门指引与常见问题解答。这是一份在线文档,因此大家可以通过链接在每项条目下找到对应的用户社区评论。HBase网站也提供指向HBase Java API的链接,同时提供视频及HBase离线信息资源。要获得大家信息,大家不妨查找维基中的HBase词条。虽然也还算不错,但HBase的说明文档仍然无法与我所见过的其它数据库产品网站相比肩,例如Canssandra以及MongoDB。不过互联网上相关信息非常丰富,HBase社区在规模与活跃程度上也相当突出,任何关于HBase的问题都能很快在这里得到解答。
HBase近来最有趣的一项更新就是添加了对“协进程”的支持能力——用户代码将被作为HBase RegionServer以及Master进程中的一部分加以执行。协进程大体上讲分为两种:观察者与终端。所谓观察者是一种由用户编写的Java类,旨在定义特定HBase事件发行时随之触发的方法。大家可以将观察者想象成HBase上的RDBMS触发器。举例来说,作为观察者之一的RegionObserver可以对数据进行流程化控制,包括执行get、put以及delete等操作。
HBase终端协进程的作用更像是存储流程。举例来说,它在载入后可以通过观察者实现调用,从而以动态方式为HBase添加更多新功能。我们可以通过多种方式在HBase集群中载入协进程,其中包括借助HBase shell。
配置一套大型HBase集群往往非常困难。一套HBase集群当中包含主节点、RigionServer进程、HDFS进程以及同时运行的一整套Zookeeper集群。很明显,由于体系当中囊括了无数时刻运作的部件,要对其进行故障排查自然也是一项难以完成的任务。
HBase是一套以开发者为核心的数据库。它的在线说明指南大部分指向HBase的Java API文档。如果大家希望了解特定HBase条目所扮演的角色——例如Filter——请准备好阅读Java API文档中关于Filter类的大量详细解释。
由于访问指向行、而行又由行键负责索引,因此只有认真设计行键结构才能获得理想的性能表现。颇为讽刺的是,熟悉ISAM(即索引循序存取法)的旧派程序员对此非常了解:数据库访问的核心在于复合键索引体系下的组件与组件顺序。
HBase当中采用了众多来自Hadoop领域、经过无数实战考验的技术成果。对于需要建立一套规模庞大、可扩展、高度可用的分布式数据库,特别是对一致性拥有高度依赖性的应用程序而言,HBase绝对值得一试。
Apache HBase 0.94整体情况概述
优势 |
|
不足 |
|
平台 | 要求Java SE版本6;可以通过Cygwin运行在Windows环境下 |
使用成本 | 基于Apache License version 2.0的免费开源项目 |
原文链接:Review: HBase is massively scalable -- and hugely complex