《HBase原理与实战》-HBase概述
一、HBase逻辑视图
视图术语 | 解释 |
---|---|
table | 表,一个表包含多行数据。 |
row | 行,一行数据包含:一个唯一标识rowkey、多个column及对应的value。 (一张表中所有row都按roweky的字典顺序由小到大排序) |
column | 列,hbase中的列由列族(column family,cf)和列名(qualifier)组成, 格式:cf:qualifier。 (cf下可以设置任意多个qualifier,理论上可以扩展到上百万列) |
timestamp | 时间戳,每个cell在写入时hbase都会默认分配一个时间戳作为该cell的版本,用户也可在写入时自带时间戳。 (同一rowkey、column下可以有多个value存在,这些value使用时间戳作为版本号,版本越大,数据越新) |
cell | 单元格,由五元组(row, column, timestamp, type, value)组成的结构, 其中,type表示Put/Pelete这样的操作类型。该结构在数据库中以KV结构存储, 其中(row, column, timestamp,type)是K, value是字段对应的KV结构的V。 |

上图逻辑视图表示:
- 表中存储2行数据,两个rowkey分别是com.cnn.www和com.example.ww,按字典序由小到大排列;
- 每行有3个列族,分别是anchior,coments,people,其中anchior列族下有2列,分别是cnnsi.com和my.lock.ca;
- 根据行com.cnn.www和列cnnsi.com可以定位到数据CNN,对应的时间戳信息是t9;同row下的conent:html列下,却有3个版本的数据,版本号分别是t5, t6, t7;
(1)HBase引用了列族的概念,列族下的列可以动态扩展;
(2)HBase使用时间戳实现数据的多版本支持;
二、多维稀疏排序Map
BigTable本质上是一个Map结构数据库(Map由key和value组成),HBase也是由一系列KV构成。且HBase的Map结构有很多限定词:稀疏的、分布式的、持久性的、多纬的、排序的。
HBase中Map的key是一个复合键,由(row, column, timestamp,type),value是cell(单元格)的值。
举例说明:上述HBase逻辑视图对应的Map存储结构如下:
{"com.cnn.www","anchor","cnnsi.com","put","t9"} --> "CNN"
HBase Map存储结构的特性如下:
(1)多维:HBase Map的key是一个复合数据结构,由多维元素构成,包括:row, column, timestamp,type),其中,column由column family:qualifier构成。
(2)稀疏:HBase中空值不需要填充null;稀疏性是HBase的列可以无限扩充的一个重要条件。
(3)排序:构成HBase的KV在同一个文件中都是有序的,排序规则不仅仅按照rowkey排序,而是按KV中的key进行排序——先比较rowkey,rowkey小的排在前面;若rowkey相同,再比较column,以此类推。这样的多维元素排序规则,对于提升HBase的读取性能至关重要。
(4)分布式:构成HBase的所有Map并不是集中在某台机器上,而是分布在整个集群中。
三、HBase物理视图
HBase中的数据是按列族存储的,即:将数据按列族分布存储在不同的目录中。
举例说明:上述HBase逻辑视图中列族anchor的所有数据存储在一起形成:

四、列族式存储的优势
HBase是列族式存储的,为什么HBase要将数据按列族式分布存储?回答这个问题之前,需要先了解行式存储和列式存储:
(1)行式存储
将一行数据存储在一起。行式存储在获取一行数据时很高效,但是如果只需要读取表中某列数据,行式存储会先取出一行行数据,再对每行数据中截取目标列,这种处理方式在查找过程中引入了大量无用列信息,从而导致大量内存占用。行式存储的系统适合处理OLTP类型的负载,不适合PLAP这类分析型负载。
(2)列式存储
将一列数据存储在一起。列式存储对于只查找某列数据的请求高效,只需要连续读出所有待查目标列,然后遍历处理即可;对于获取某行的请求就不够高效了。另外,同一列的数据通常具有相同的数据类型,因此列式存储具有天然的高压缩特性。
列族式存储介于行式存储和列式存储,可以通过不同的设计思路在行式存储和列式存储之间相互切换。比如:设计一个列族里有多个列,这种设计模式就等同于行式存储;设计多个列族,每个列族下仅一个列,这种设计模式就等同于列式存储。
在当前体系下不建议设置太多列族,但是这种架构为HBase将来演变为HTAP系统(Hybrid Transactional and Analytical Processing)提供列最核心的基础。
四、HBase体系结构

1、HBase客户端
client提供shell命令行接口、原生java api编程接口、thrift/REST api编程接口以及MapReduce编程接口。客户端支持数据的增删改查和表的日常维护等,其中thrift/REST api主要用于非java的上层业务需求,MapReduce接口主要用于批量导入数据以及批量数据读取。
HBase客户端访问数据行之前,先需要通过元数据表定位目标数据所在RS,之后才会发送请求到该RS。同时这些元数据会被缓存在客户端本地,以方便之后的请求访问。如果集群RS发生宕机或执行了负载均衡等,从而导致数据分片发生迁移,客户端需要重新请求最新的元数据并缓存在本地。
2、Zookeeper
ZK主要用于协调管理分布式应用程序,在HBase系统中,ZK的作用如下:
- 实现Master高可用:通常情况下系统只有一个active Master,一旦由于异常宕机,ZK会检测到该宕机事件,并通过一定机制选举出新的active Master,保证Hbase正常运行。
- 管理系统核心元数据:比如,管理正常工作的RS集合、保存元数据表hbase:meta所在的RS地址等。
- 参与RS宕机恢复:ZK通过心跳感知到RS是否宕机,并在宕机后通知Master进行宕机处理;
- 实现分布式表锁:HBase中对一个表进行各种管理操作(比如alter操作)需要先加表锁,防止其他用户对同一个表进行管理操作,造成表状态不一致。因为HBase是分布式存储,ZK可以通过特定机制实现分布式表锁。
3、Master
Master主要负责HBase的各种管理工作:
- 处理用户的各种管理请求,包括:建表、修改表、权限操作、切分表、合并数据分片、compaction等。
- 管理集群中所有RS,包括:RS中Region的负载均衡、RS的宕机恢复、Region的迁移等。
- 清理过期日志以及文件,Master会每隔一段是检查HDFS中HLog是否过期、HFile是否已经被删除,并在过期后将其删除。
4、RegionServer
RS主要用来响应用户的IO请求,是HBase中最核心的模块,由WAL(HLog)、BlockCache以及多个Region构成。
- WAL(HLog):WAL在HBase中有两个核心作用:(1)实现数据的高可用性;(2)实现HBase集群之间主从复制;
(1)实现数据的高可用性
HBase数据随机写入时,并非直接写入HFile数据文件,而是先写入缓存,再异步刷新落盘,为了防止缓存数据丢失,数据写入缓存之前需要先顺序写入HLog,这样即使缓存数据丢失仍然可以通过HLog日志恢复。
(2)实现HBase集群之间主从复制
通过回放主集群推送过来的HLog日志实现主从复制。
- BlockCache:HBase的读缓存,客户端从磁盘读取数据之后通常会将数据缓存到系统内存中,后续访问同一行数据可以直接从内存中获取而不需要访问磁盘。对于带有大量热点读的业务请求来说,缓存机制会带来极大的性能提升。
当前BlockCache主要有两种实现:LRUBlockCache和BucketCache。
BlockCache缓存对象是一系列Block块,一个Block默认是64K,由物理上相邻的多个KV数据组成。
BlockCache同时利用了空间局部性和时间局部性原理:
(1)空间局部性:最近将读取的KV数据很可能与当前读取到的KV数据在地址上是邻近的。缓存单位是Block而不是单个KV就可以实现空间局部性。
(2)时间局部性:一个KV数据正在被访问,那么近期它还可能再次被访问。
- Region:数据表的一个分片,当数据表超过一定阀值就会“水平切分”,分裂为两个Region。Region是集群负载均衡的基本单位,通常一个表的Region会分布在整个集群的多台RS上,一个RS上会管理多个Region(当然,这些Region一般来自不同的数据表)。
(1)一个Region由一个或多个Store构成,Store的个数取决于表中列族的个数:多少个列族就有多少个Store。
(2)一个Store由一个MemStore(写缓存)和一个或多个HFile组成。用户写入数据时首先写到MemStore,当MemStore写满之后(缓存数据超过阀值,默认128MB),系统会异步将数据flush成一个HFile文件,随着数据不断写入,HFile文件越来越多,当HFile文件数量超过一定阀值后系统将执行Compact操作,将这些小文件通过一定策略合并成一个或多个大文件。
(3)每个列族的数据都集中存储在一起形成一个存储单元Store,因此建议将具有相同IO特性的数据设置在一个列族里。
5、HDFS
HBase底层依赖HDFS组建存储实际数据,包括用户数据文件、HLog日志文件等最终都会写入HDFS落盘。
HDFS数据默认三副本存储策略,可以有效保证数据的高可用性。HBase内部封装了一个名为DFSClient的HDFS客户端组件,负责对HDFS的实际数据进行读写访问。
五、HBase系统特性
1、优点
容量巨大、可扩展、稀疏性、高性能、多版本、支持过期、Hadoop原生支持
- 容量巨大:单表可支持千亿行、百万列的数据规模;数据容量可以达到TB甚至PB级别;
- 良好的可扩展性:集群容量扩展方便,包括:数据存储节点扩展(增加DataNode节点)、读写服务节点扩展(增加RegionServer节点)。
- 稀疏性:支持大量稀疏存储,即允许大量列值为空,并不占用任何存储空间。
- 高性能:主要擅长OLTP场景,数据写操作性能强。对于随机单点读以及小范围扫描读,性能也能得到保证;对于大范围扫描读,可以使用MapReduce提供的API,以便实现更高效的并行扫描。
- 多版本:一个kv可以同时保留多个版本,用户可以根据需要选择最新版本或某个历史版本。
- 支持过期:支持TTL过期特性,用户只需设置过期时间,超过TTL的数据会被自动清理,不需要用户手动删除。
- Hadoop原生支持:HBase是HAdoop生态中的核心成员之一,很多生态组件可以与其直接对接。
2、缺点
不支持复杂聚合运算、不支持二级索引查找、不支持全局跨行事务
- 不支持复杂聚合运算。例如:join、groupby等。复杂聚合运算需要借助Phoenix组件(适合小规模聚合的OLTP场景)或Spark组件(适合大规模的OLAP场景)。
- 不支持二级索引查找。HBase本身没有实现二级索引功能,目前比较普遍的使用Phoenix提供的二级索引功能。
- 原生不支持全局跨行事务,只支持单行事务模型。可以使用Phoenix提供的全局事务模型组件。