Pinpoint系列之Hbase存储介绍

2021-03-02  本文已影响0人  我知他风雨兼程途径日暮不赏

参考自《HBASE总结与实践》
xmind转markdown存在图片丢失,源文件下载地址:github hbase xmind下载地址

系统特性

优势

劣势

体系结构

总架构图

总架构图

HBase客户端

HBase客户端(Client)提供了Shell命令行接口、原生Java API编程接口、Thrift/REST API编程接口以及MapReduce编程接口。HBase客户端支持所有常见的DML操作以及DDL操作,即数据的增删改查和表的日常维护等。其中Thrift/REST API主要用于支持非Java的上层业务需求,MapReduce接口主要用于批量数据导入以及批量数据读取。HBase客户端访问数据行之前,首先需要通过元数据表定位目标数据所在RegionServer,之后才会发送请求到该RegionServer。同时这些元数据会被缓存在客户端本地,以方便之后的请求访问。如果集群RegionServer发生宕机或者执行了负载均衡等,从而导致数据分片发生迁移,客户端需要重新请求最新的元数据并缓存在本地。

ZooKeeper

ZooKeeper(ZK)也是Apache Hadoop的一个顶级项目,基于Google的Chubby开源实现,主要用于协调管理分布式应用程序。在HBase系统中,ZooKeeper扮演着非常重要的角色。

Master

RegionServer

RegionServer主要用来响应用户的IO请求,是HBase中最核心的模块,由WAL(HLog)、BlockCache以及多个Region构成。

HDFS

HBase底层依赖HDFS组件存储实际数据,包括用户数据文件、HLog日志文件等最终都会写入HDFS落盘。HDFS是Hadoop生态圈内最成熟的组件之一,数据默认三副本存储策略可以有效保证数据的高可靠性。HBase内部封装了一个名为DFSClient的HDFS客户端组件,负责对HDFS的实际数据进行读写访问。

数据模型

table(表)

表,一个表包含多行数

row(行)

行,一行数据包含一个唯一标识rowkey、多个column以及对应的值。在HBase中,一张表中所有row都按照rowkey的字典序由小到大排序

timestamp(时间戳)

时间戳,每个cell在写入HBase的时候都会默认分配一个时间戳作为该cell的版本,当然,用户也可以在写入的时候自带时间戳。HBase支持多版本特性,即同一rowkey、column下可以有多个value存在,这些value使用timestamp作为版本号,版本越大,表示数据越新。

cell(具体value)

单元格,由五元组(row, column, timestamp,type, value)组成的结构,其中type表示Put/Delete这样的操作类型,timestamp代表这个cell的版本。这个结构在数据库中实际是以KV结构存储的,其中(row, column,timestamp, type)是K,value字段对应KV结构的V

column(列)

列,与关系型数据库中的列不同,HBase中的column由column family(列簇)以及qualifier(列名)两部分组成,两者中间使用":"相连。比如contents:html,其中contents为列簇,html为列簇下具体的一列。column family在表创建的时候需要指定,用户不能随意增减。一个column family下可以设置任意多个qualifier,因此可以理解为HBase中的列可以动态增加,理论上甚至可以扩展到上百万列

数据结构

跳跃表

image.png

跳跃表(SkipList)是一种能高效实现插入、删除、查找的内存数据结构,这些操作的期望复杂度都是O(logN)。与红黑树以及其他的二分查找树相比,跳跃表的优势在于实现简单,而且在并发场景下加锁粒度更小,从而可以实现更高的并发性。正因为这些优点,跳跃表广泛使用于KV数据库中,诸如Redis、LevelDB、HBase都把跳跃表作为一种维护有序数据集合的基础数据结构。

多路归并

image.png

先看一个简单的问题:现在有K个文件,其中第i个文件内部存储有Ni个正整数(这些整数在文件内按照从小到大的顺序存储),如何设计一个算法将K个有序文件合并成一个大的有序文件?在排序算法中,有一类排序算法叫做归并排序,里面就有大家熟知的两路归并实现。现在相当于K路归并,因此可以拓展一下,思路类似。对每个文件设计一个指针,取出K个指针中数值最小的一个,然后把最小的那个指针后移,接着继续找K个指针中数值最小的一个,继续后移指针……直到N个文件全部读完为止

LSM树

image.png

LSM树本质上和B+树一样,是一种磁盘数据的索引结构。但和B+树不同的是,LSM树的索引对写入请求更友好。因为无论是何种写入请求,LSM树都会将写入操作处理为一次顺序写,而HDFS擅长的正是顺序写(且HDFS不支持随机写),因此基于HDFS实现的HBase采用LSM树作为索引是一种很合适的选择。LSM树的索引一般由两部分组成,一部分是内存部分,一部分是磁盘部分。内存部分一般采用跳跃表来维护一个有序的KeyValue集合。磁盘部分一般由多个内部KeyValue有序的文件组成

布隆过滤器

在HBase 1.x版本中,用户可以对某些列设置不同类型的布隆过滤器,共有3种类型。
• NONE:关闭布隆过滤器功能。
• ROW:按照rowkey来计算布隆过滤器的二进制串并存储。Get查询的时候,必须带rowkey,所以用户可以在建表时默认把布隆过滤器设置为ROW类型。
• ROWCOL:按照rowkey+family+qualifier这3个字段拼出byte[]来计算布隆过滤器值并存储。如果在查询的时候,Get能指定rowkey、family、qualifier这3个字段,则肯定可以通过布隆过滤器提升性能。但是如果在查询的时候,Get中缺少rowkey、family、qualifier中任何一个字段,则无法通过布隆过滤器提升性能,因为计算布隆过滤器的Key不确定。

Compaction

Minor Compaction

是指选取部分小的、相邻的HFile,将它们合并成一个更大的HFile

Major Compaction

是指将一个Store中所有的HFile合并成一个HFile,这个过程还会完全清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。

RegionServer核心模块

HLog

HBase中系统故障恢复以及主从复制都基于HLog实现。默认情况下,所有写入操作(写入、更新以及删除)的数据都先以追加形式写入HLog,再写入MemStore。大多数情况下,HLog并不会被读取,但如果RegionServer在某些异常情况下发生宕机,此时已经写入MemStore中但尚未f lush到磁盘的数据就会丢失,需要回放HLog补救丢失的数据。此外,HBase主从复制需要主集群将HLog日志发送给从集群,从集群在本地执行回放操作,完成集群之间的数据复制。

MemStore

HFile

BlockCache

BlockCache是RegionServer级别的,一个RegionServer只有一个BlockCache,在RegionServer启动时完成BlockCache的初始化工作。到目前为止,HBase先后实现了3种BlockCache方案,LRUBlockCache是最早的实现方案,也是默认的实现方案;HBase 0.92版本实现了第二种方案SlabCache,参见HBASE-4027;HBase 0.96之后官方提供了另一种可选方案BucketCache,参见HBASE-7404。

读写流程

写入流程

读取流程

和写流程相比,HBase读数据的流程更加复杂。主要基于两个方面的原因:一是因为HBase一次范围查询可能会涉及多个Region、多块缓存甚至多个数据存储文件;二是因为HBase中更新操作以及删除操作的实现都很简单,更新操作并没有更新原有数据,而是使用时间戳属性实现了多版本;删除操作也并没有真正删除原有数据,只是插入了一条标记为"deleted"标签的数据,而真正的数据删除发生在系统异步执行Major Compact的时候。很显然,这种实现思路大大简化了数据更新、删除流程,但是对于数据读取来说却意味着套上了层层枷锁:读取过程需要根据版本进行过滤,对已经标记删除的数据也要进行过滤。

Meta表

HBase一张表的数据是由多个Region构成,而这些Region是分布在整个集群的RegionServer上的。那么客户端在做任何数据操作时,都要先确定数据在哪个Region上,然后再根据Region的RegionServer信息,去对应的RegionServer上读取数据。因此,HBase系统内部设计了一张特殊的表——hbase:meta表,专门用来存放整个集群所有的Region信息。hbase:meta中的hbase指的是namespace,HBase容许针对不同的业务设计不同的namespace,系统表采用统一的namespace,即hbase;meta指的是hbase这个namespace下的表名。

数据结构

该列对应的Value主要存储4个信息,即EncodedName、RegionName、Region的StartRow、Region的StopRow。

该列对应的Value主要存储Region落在哪个RegionServer上。

客户端定位Region方式

HBase客户端有一个叫做MetaCache的缓存,在调用HBaseAPI时,客户端会先去MetaCache中找到业务rowkey所在的Region,这个Region可能有以下三种情况:
•Region信息为空,说明MetaCache中没有这个rowkey所在Region的任何Cache。此时直接用上述查询语句去hbase:meta表中Reversed Scan即可,注意首次查找时,需要先读取ZooKeeper的/hbase/meta-region-server这个ZNode,以便确定hbase:meta表所在的RegionServer。在hbase:meta表中找到业务rowkey所在的Region之后,将(regionStartRow, region)这样的二元组信息存放在一个MetaCache中。这种情况极少出现,一般发生在HBase客户端到服务端连接第一次建立后的少数几个请求内,所以并不会对HBase服务端造成巨大压力。
•Region信息不为空,但是调用RPC请求对应RegionServer后发现Region并不在这个RegionServer上。这说明MetaCache信息过期了,同样直接ReversedScan hbase:meta表,找到正确的Region并缓存。通常,某些Region在两个RegionServer之间移动后会发生这种情况。但事实上,无论是RegionServer宕机导致Region移动,还是由于Balance导致Region移动,发生的几率都极小。而且,也只会对Region移动后的极少数请求产生影响,这些请求只需要通过HBase客户端自动重试locatemeta即可成功。
•Region信息不为空,且调用RPC请求到对应RegionSsrver后,发现是正确的RegionServer。绝大部分的请求都属于这种情况,也是代价极小的方案。

负载均衡

Region迁移

作为一个分布式系统,分片迁移是最基础的核心功能。集群负载均衡、故障恢复等功能都是建立在分片迁移的基础之上的。比如集群负载均衡,可以简单理解为集群中所有节点上的分片数目保持相同。实际执行分片迁移时可以分为两个步骤:第一步,根据负载均衡策略制定分片迁移计划;第二步,根据迁移计划执行分片的实际迁移。HBase系统中,分片迁移就是Region迁移。和其他很多分布式系统不同,HBase中Region迁移是一个非常轻量级的操作。所谓轻量级,是因为HBase的数据实际存储在HDFS上,不需要独立进行管理,因而Region在迁移的过程中不需要迁移实际数据,只要将读写服务迁移即可。

Region合并

在线合并Region是HBase非常重要的功能之一。相比Region分裂,在线合并Region的使用场景比较有限,最典型的一个应用场景是,在某些业务中本来接收写入的Region在之后的很长时间都不再接收任何写入,而且Region上的数据因为TTL过期被删除。这种场景下的Region实际上没有任何存在的意义,称为空闲Region。一旦集群中空闲Region很多,就会导致集群管理运维成本增加。此时,可以使用在线合并功能将这些Region与相邻的Region合并,减少集群中空闲Region的个数。

Region分裂

Region分裂是HBase最核心的功能之一,是实现分布式可扩展性的基础。HBase中,Region分裂有多种触发策略可以配置,一旦触发,HBase会寻找分裂点,然后执行真正的分裂操作。

上一篇 下一篇

猜你喜欢

热点阅读