业无高卑志当坚,男儿有求安得闲?这篇文章主要讲述HBase概述与体系结构相关的知识,希望能为你提供帮助。
1. HBase概述
HBase是目前热门的一款分布式KV(keyValue,键值)数据库系统,无论是互联网行业还是其他传统IT行业都在大量使用。尤其是近几年随着国内大数据理念的普及,HBase凭借其高可靠、易扩展、高性能以及成熟的社区支持,受到越来越多企业的青睐。许多大数据系统都将HBase做为底层数据存储服务,例如KyLin、OpenTSDB等。
2. HBase数据模型
从使用角度来看,HBase包含了大量关系型数据库的基本概念——表、行、列,但在BigTable的论文中又称HBase为“sparse, distributed, persistent, multidimensional sorted map”,即HBase本质来看是一个Map。
实际上,从逻辑视图来看,HBase中的数据是以表形式进行组织的,而且和关系型数据库中的表一样,HBase中的表也由行和列构成,因此HBase非常容易理解。但从物理视图来看,HBase是一个Map,由键值(KeyValue, KV)构成,不过与普通的Map不同,HBase是一个稀疏的、分布式的、多维排序的Map。从逻辑视图到稀疏多维排序Map再到物理视图介绍HBase。
2.1 逻辑视图
在具体了解逻辑视图之前,看看HBase中的基本概念。
- table:表,一个表包含多行数据。
- row:行,一行数据包含一个唯一标识rowkey、多个column以及对应的值。在Hbase,一张表的所有row都按照rowkey的字典序由小到大排序。
- column:列,与关系型数据库中的列不同,HBase中的column由column family(列簇)以及qualifier(列名)两部分组成,两者中间使用":"相连。比如contents:html,其中contents为列簇,html为列簇下具体的一列。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字段对应KV结构的V。
文章图片
总休来看,HBase的逻辑视图是比较容易理解的,需要注意的是HBase引入了列簇的概念,列簇下的列可以动态扩展;另外,HBase使用时间戳实现了数据的多版本支持。 2.2 多维稀疏排序Map 使用关系型数据库中表的概念来描述HBase,对于HBase的入门使用大有裨益,然而,对于理解HBase的工作原理意义不大。要真正理解HBase的工作原理,需要从KV数据库这个视角重新对其审视。BigTable论文中称BigTable为"sparse, distributed, persistent, multidimensional sorted map",可见BitTable本质上是一个Map结构数据库,HBase亦然,也是由一系列KV构成的。然而HBase这个Map系统却并不简单,有很多限定词——稀疏的、分布式的、持久性的、多维的以及排序的。我们先对这个Map进行解析,这对于之后理解HBase的工作原理非常重要。 Map是由key和value组成,那组成HBase Map的key和value分别是什么?和普通Map的KV不同,HBase中的Map的key是一个复合键,由rowkey、column family、qualifier、type以及timestamp组成,value即为cell的值。举例上节逻辑视图中行“com.cnn.www”以及列"anchor:cnnsi.com"对应的数值“CNN”实际上在HBase中存储为如下结构: {"com.cnn.www", "anchor", "cnnsi.com", "put", "t9"} -> "CNN" 对HBase中数据的存储形式有了初步了解后,在此基础上再来介绍多维、稀疏、排序等关键词。
- 多维:穿上特性比较容易理解。HBase中的Map与普通Map最大的不同在于,key是一个复合数据结构,由多维元素构成,包括rowkey、column family、qualifier、type以及timestamp。
- 稀疏:稀疏性是HBase一个突出特点。从上节的逻辑表中行"com.example.www"可以看出,整整一行,仅有一列(people:author)有值,其他列都为空。在其他数据库中对于空值的处理一般都会填充null,而对于HBase,空值不需要任何填充。这个特性为什么重要?因为HBase的列在理论上是允许无限扩展的,对于成百万列的表来说,通常会存在大量的空值,如果使用填充null的策略,势必会造成大量空间的浪费。因此稀疏性是HBase的列可以无限扩展的一个重要条件。
- 排序:构成HBase的KV在同一个文件中都是有序的,但规则并不是仅仅按照rowkey排序,而是按照KV中的key进行排序——先比较rowkey,rowkey小的排在前面;如果rowkey相同,再比较column,即column family:qualifier,column小的排在前面;如果column还相同,再比较时间戳timestamp,即版本信息,timestamp大的排在前面。这样的多维元素排序规则对于提升HBase的读取性能至关重要。
- 分布式:很容易理解,构成HBase的所有Map并不集中在某台机器上,而是分布在整个集群中。
文章图片
列簇contents的所有数据存储在一起形成:
文章图片
列簇people的所有数据存储在一起形成:
文章图片
2.4 行式存储、列式存储、列簇式存储 为什么HBase要将数据按照列簇分别存储?回答问题之前先了解两个非常常见的概念:行式存储、列式存储,这是数据存储领域比较常见的两种数据存储方式。 行式存储:行式存储系统会将一行数据存储在一起,一行数据与完之后再接着写下一行,最典型的如mysql这类关系弄数据库,如下图所示
文章图片
行式存储在获取一行数据时是很高效的,但如果某个查询只需要读取表中指定列对应的数据,那么行式存储会先取出一行行数据,再在每一行中截取待查找目标列。这种处理方式在查找过程中引入了大量无用列信息,从而导致大量内存占用。因此这类系统仅适用于处理OLTP类型的负载,对于OLAT这类分析型负载并不擅长。 列式存储:列式存储理论上会将一列数据存储在一起,不同列的数据分别集中存储,最典型的如Kudu、Parquet on HDFS等系统(文件格式),如下图:
文章图片
列式存储对于只查找某些列数据的请求非常高效,只需要连续读出所有待查目标列,然后遍历处理即可;但是反过来,列式存储对于获取一行的请求就不那么高效了,需要多次IO读多个列数据,最终合并到一行数据。另外,因为同一列的数据通常都具有相同的数据类型,因此列式存储具有天然的高压缩特性。 列簇式存储:从概念上来说,列簇式存储介于行式存储和列式存储之间,可以通过不同的设计思路在行式存储和列式存储两者之间相互切换。比如,一张表只设置一个列簇,这个列簇包含所有用户的列。HBase的一个列簇的数据是存储在一起的,因此这种设计模式就等同于行式存储,再比如,一张表设置大量列簇,每个列簇下仅有一列,很显然这种设计模式就等同于列式存储。上面两例当然是两种极端的情况。在当前体系中不建议设置太多列簇,但这种架构为HBase将来演变成HTAP(Hybird Transactional and Analytical processing)系统提供了最核心的基础。 3 HBase体系结构 HBase体系结构借鉴了BigTable论文,是典型的Master-Slave模型。系统中有一个管理集群的Master节点以及大量实际服务用户读写的RegionServer节点。除此之外,HBase中所有数据最终都存储在HDFS系统中,这与BigTable实际数据存储在GFS中相对应;系统中还有一个ZooKeeper节点,协助Master对集群进行管理。HBase体系结构如下图:
文章图片
3.1 HBase客户端 HBase客户端(Client)提供了Shell命令行接口、原生java API编程接口、Thrift/REST API编程接口以及MapReduce编程接口。HBase客户端支持所有常见的DML操作以及DDL操作,即数据的增删改查和表的日常维护等。其中Thirft/REST API主要用于支持非Java的上层业务需求,MapReduce接口主要用于批量数据导入以及批量数据读取。 HBase客户端访问数据之前,首先需要通过无数据表定位目标数据所在RegionServer,之后才会发送请求到该RegionServer。同时这些元数据会被缓存在客户端本地,以方便之后的请求访问。如果集群RegionServer发生宕机或者执行了负载均衡,从而导致数据分片发生迁移,客户端需要重新请求最新的无数据并缓存在本地。 3.2 ZooKeeper ZooKeeper(ZK)也是Apache Hadoop的一个顶级项目,基于Google的Chubby开源实现,主要用于协调管理分布式应用程序。在HBase系统中,ZooKeeper扮演着非常重要的角色。
- 实现Master高可用:通常情况下系统中只有一个Master工作,一旦Active Master由于异常宕机,ZooKeeper会检测到该宕机事件,并通过一定机制选举出新的Master,保证系统正常运转。
- 管理系统核心元数据:比如,管理当前系统中正常工作的RegionServer集合,保存系统无数据表hbase:meta所在的RegionServer地址等。
- 参与RegionServer宕机恢复:ZooKeeper通过心跳可以感知到RegionServer是否宕机,并在宕机后通知Master进行宕机处理。
- 实现分布式表锁:HBase中对一张表进行各种管理操作(比如alter操作)需要先加表锁,防止其他用户对同一张表进行管理操作,造成表状态不一致。和其他RDBMS表不同,HBase中的表通常是分布式存储,ZooKeeper可以通过特定机制实现分布式表锁。
- 处理用户的各种管理请求,包括建表、修改表、权限操作、切分表、合并数据分片及Compaction等。
- 管理集群中所有RegionServer,包括RegionServer中Region的负载均衡、RegionServer的宕机恢复以及Region的迁移等。
- 清理过期日志以及文件,Master会每隔一段时间检查HDFS中HLog是否过期,HFile是否已经被删除,并在过期之后将其删除。
- WAL(HLog):HLog在HBase中有两个核心作用——其一,用于实现数据的高可靠性,HBase数据随机写入时,并非直接写入HFile数据文件,而是先写入缓存,再异步刷新落盘。为了防止缓存数据丢失,数据写入缓存之前需要首先顺序写入HLog,这样即使缓存数据丢失,仍然可以通过HLog日志恢复;其二,用于实现HBase集群间主从复制,通过回放集群推送过来的HLog日志实现主从复制。
- BlockCache:HBase系统中的读缓存。客户端从磁盘读取数据之后通常会将数据缓存到系统内存中,后续访问同一行数据可以直接从内存中获取而不需要访问磁盘。
- Region:数据表的一个分片,当数据表大小超过一定阈值就会“水平切分”,分裂为两个Region。Region是集群负载均衡的基本单位。通常一张表的Region会分布在整个集群的多台RegionServer上,一个RegionServer上会管理多个Region,当然,这些Region一般来自不同的数据表。
- 容量巨大:HBase的单表可以支持千亿行、百万列的数据规模,数据容量可以达到TB甚至PB级别。传统的关系型数据库,如Oracle和MySQL等,如果单表记录条数超过亿行,读写性能都会急剧下降,在HBase中并不会出现这样的问题。
- 良好的可扩展性:HBase集群可以非常方便地实现集群容量扩展,主要包括数据存储节点扩展以及读写服务节点扩展。HBase底层数据存储依赖于HDFS系统,HDFS可以通过简单地增加DataNode实现扩展,HBase读写服务节点也一样,也可以通过简单的增加RegionServer节点实现计算层的扩展。
- 稀疏性:HBase支持大量稀疏存储,即允许大量列值为空,并不占用任何存储空间。这与传统数据库不同,传统数据库对于空值的处理要占用一定的存储空间,这会造成一定程序的存储空间浪费。因此可以使用HBase存储多至上百万列的数据,即使表中存在大量的空值,也不需要任何额外空间。
- 高性能:HBase目前主要擅长于OLTP场景,数据写操作性能强劲,对于随机单点读以及小范围的扫描读,其性能也能够得到保证。对于大范围的扫描读可以使用MapReduce提供的API,以便实现更高效的并行扫描。
- 多版本:HBase支持多版本特性,即一个KV可以同时保留多个版本,用户可以根据需要选择最新版本或者某个历史版本。
- 支持过期:HBase支持TTL过期特性,用户只需要设置过期时间,超过TTL的数据就会被自动清理,不需要用户写程序手动删除。
- Hadoop原生支持:HBase是Hadoop生态中的核心成员之一,很多生态组件都可以与其直接对接。HBase数据存储依赖于HDFS,这样的架构可以带来很多好处,比如用户可以直接绕过HBase系统操作HDFS文件,高效地完成数据扫描或者数据导入工作;再比如可以利用HDFS提供的多级存储特性(Archival Storage Feature),根据业务的重要程序将HBase进行分级存储,重要的业务放到SSD,不重要的业务放到HDD。或者用户可以设置归档时间,进而将最近的数据放在SSD,将归档数据文件放在HDD。另外,HBase对MapReduce的支持也已经有了很多安全,后续还会针对Spark做更多的工作。
- HBase本身不支持很复杂的聚合运算(如Join、GroupBy等)。如果业务中需要使用聚合运算,可以在HBase之上架设Phoenix组件或者Spark组件,前者主要应用于小规模聚合的OLTP场景,后者应用于大规模聚合的OLAP场景。
- HBase本身并没有实现二级索引功能,所以不支持二级索引查找。好在针对HBase实现的第三方二级索引方案非常丰富,比如目前比较普遍的使用Phoenix提供的二级索引功能。
- HBase原生不支持全局跨行事务,只支持单行事务模型。同样,可以使用Phoenix提供的全局事务模型组件来弥补HBase的这个缺陷。
推荐阅读
- 简单了解一下K8S,并搭建自己的集群
- Zookeeper原理解析&使用场景详解
- 同步MySQL数据到ES神器mysqlmom介绍
- 万字长文解密数据异构最佳实践(含完整代码实现)!!
- 深入了解Zookeeper核心原理
- Angular 服务器端渲染的学习笔记
- MySQLmom程序全量同步MySQL表数据到ES
- 使用Centos系统忘记密码怎么办
- 大白话聊聊微服务——人人都能看懂的演进过程