HBase的原理及运行机制

Posted YaoYong_BigData

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HBase的原理及运行机制相关的知识,希望对你有一定的参考价值。

一、Hbase体系结构

                                                         图1 Hbase体系结构

                                                         图2 HBase 逻辑表结构

                                                         图3 HBase 物理存储结构

1.HBase客户端

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

2.ZooKeeper

         ZooKeeper(ZK)也是Apache Hadoop的一个顶级项目,基于Google的Chubby开源实现,主要用于协调管理分布式应用程序。在HBase系统中,ZooKeeper扮演着非常重要的角色。
        1)实现Master高可用:通常情况下系统中只有一个Master工作,一旦Active Master由于异常宕机,ZooKeeper会检测到该宕机事件,并通过一定机制选举出新的Master,保证系统正常运转。
        2)管理系统核心元数据:比如,管理当前系统中正常工作的RegionServer集合,保存系统元数据表hbase:meta所在的RegionServer地址等。
        3)参与RegionServer宕机恢复:ZooKeeper通过心跳可以感知到RegionServer是否宕机,并在宕机后通知Master进行宕机处理。
        4)实现分布式表锁:HBase中对一张表进行各种管理操作(比如alter操作)需要先加表锁,防止其他用户对同一张表进行管理操作,造成表状态不一致。和其他RDBMS表不同,HBase中的表通常都是分布式存储,ZooKeeper可以通过特定机制实现分布式表锁。

3.Master

Master主要负责HBase系统的各种管理工作:
        1)处理用户的各种管理请求,包括建表、修改表、权限操作、切分表、合并数据分片以及Compaction等。
        2)管理集群中所有RegionServer,包括RegionServer中Region的负载均衡、RegionServer的宕机恢复以及Region的迁移等。
        3)清理过期日志以及文件,Master会每隔一段时间检查HDFS中HLog是否过期、HFile是否已经被删除,并在过期之后将其删除。

4.RegionServer

    - RegionServer 维护 Master 分配给它的 Region,处理对这些 Region 的 IO 请求(即对表中数据的增、删、改);
    - 负责和底层的文件系统hdfs交互,存储数据到hdfs;
    - 负责 Store 中的 HFile 的合并工作;
    - RegionServer 负责 Split 在运行过程中变得过大的 Region,负责 Compact (切分)操作。

        负责管理一个或多个Region,是存放Region的容器,一般来说一个服务器只有一个RegionServer,但是也允许启动多个。客户端从Zookeeper获取数据的地址后,会直接从RegionServer读取数据,不经过Master,数据的插入删除也是直接在RegionServer上进行的。      

        RegionServer主要用来响应用户的IO请求,是HBase中最核心的模块,由WAL(HLog)、BlockCache以及多个Region构成。
        1)WAL(HLog):HLog在HBase中有两个核心作用——其一,用于实现数据的高可靠性,HBase数据随机写入时,并非直接写入HFile数据文件,而是先写入缓存,再异步刷新落盘。为了防止缓存数据丢失,数据写入缓存之前需要首先顺序写入HLog,这样,即使缓存数据丢失,仍然可以通过HLog日志恢复;其二,用于实现HBase集群间主从复制,通过回放主集群推送过来的HLog日志实现主从复制。
        2)BlockCache:HBase系统中的读缓存。客户端从磁盘读取数据之后通常会将数据缓存到系统内存中,后续访问同一行数据可以直接从内存中获取而不需要访问磁盘。对于带有大量热点读的业务请求来说,缓存机制会带来极大的性能提升。
        BlockCache缓存对象是一系列Block块,一个Block默认为64K,由物理上相邻的多个KV数据组成。BlockCache同时利用了空间局部性和时间局部性原理,前者表示最近将读取的KV数据很可能与当前读取到的KV数据在地址上是邻近的,缓存单位是Block(块)而不是单个KV就可以实现空间局部性;后者表示一个KV数据正在被访问,那么近期它还可能再次被访问。当前BlockCache主要有两种实现——LRUBlockCache和BucketCache,前者实现相对简单,而后者在GC优化方面有明显的提升。
        3)Region:数据表的一个分片,当数据表大小超过一定阈值就会“水平切分”,分裂为两个Region。Region是集群负载均衡的基本单位。通常一张表的Region会分布在整个集群的多台RegionServer上,一个RegionServer上会管理多个Region,当然,这些Region一般来自不同的数据表。
        一个Region由一个或者多个Store构成,Store的个数取决于表中列簇(column family)的个数,多少个列簇就有多少个Store。HBase中,每个列簇的数据都集中存放在一起形成一个存储单元Store,因此建议将具有相同IO特性的数据设置在同一个列簇中。
        每个Store由一个MemStore和一个或多个HFile组成。MemStore称为写缓存,用户写入数据时首先会写到MemStore,当MemStore写满之后(缓存数据超过阈值,默认128M)系统会异步地将数据flush成一个HFile文件。显然,随着数据不断写入,HFile文件会越来越多,当HFile文件数超过一定阈值之后系统将会执行Compact操作,将这些小文件通过一定策略合并成一个或多个大件。

hbase中是以表结构在行的方向上划分的一个数据单元,一个region存储的是一个表中一定行键范围的数据,一个表在行的方向上进行划分会分成多个region。
region是hbase进行分布式存储的最小单位;
region是hbase各个节点进行均衡的最小单位;
但是region不是物理存储的最小单位。       

        补充说明:

        关于MemStore,很容易让人混淆。数据在被刷到HFile之前,已经被存储到了HDFS的WAL上了,那么为什么还要在放入MemStore呢?其实很简单,我们都知道HDFS是不能修改的,而HBase的数据又是按照Row Key进行排序的,其实这个排序的过程就是在MemStore中进行的。值得注意的是:MemStore的作用不是为了加快写速度,而是为了对Row Key进行排序。

5.HDFS

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

6.总结

        我们知道HBase依赖HDFS也依赖Zookeeper,那么首先出来的应该是HDFS,这是他底层的存储地,随便画几个DataNode无所谓,然后HBase还依赖Zookeeper,因此我们在启动HBase之前需要先启动它们。那接下轮到HBase启动了,HBase需要启动两大进程HMaster和HRegionServer,这个Master工作太累了,它需要把某些工作交给Zookeeper,后面在说具体都交给些什么任务。Master主要管理DDL相关的操作,操作表,操作命名空间,HRegionServer则是管理DML数据层面的操作,涉及数据的增删改查,同时Master也会管理HRegionServer,因为我的Region到底是给哪个HRegionServer维护由Master说的算,万一某个HRegionServer挂掉了,也需要Master重新分配给其它人来维护。
   在谈HRegionServer之前还有一个HLog,这个又叫预写入日志Write-Ahead logfile在/HBase/wal文件夹中,相当于HDFS的edits文件,由于数据一开始并没有落盘存在内存中,若内存崩掉数据就会丢失,HLog会实时记录操作。接下来就是一堆HRegion,一个表对应一个或者多个HRegion,HRegion里面就是列族,也就是Store,它们的存储是隔离的,就像上面看的info1,info2,对于HBase来说它的列就是数据,在插入数据之前是没有列这个概念的,随着插入数据而存在。
   下面来看看MemStore,主要是做刷写操作(flush),上面我们做个一个操作证明HBase是按照Row Key的字典序排列的,因此数据首先存到MemStore中进行排序,等待刷写时机将其写入磁盘中这就是HFile,因此将来会有很多个文件,当触发全局刷写条件(即HRegionServer的刷写条件)时可能有的MemStore只有几k,就会产生很多小文件,这时候HBase就会做合并(compact)操作,当合并的文件过大又会做拆分(split)操作。
   关于Store File和HFile的关系:HFile和.txt,.csv等同等级,是一种存储格式,Store File只是我们对刷写下来的文件的一种命名,这个文件以HFile格式存储,虽然Store File是HBase的一个组件,但它真正活跃在DataNode上,作用在磁盘上,然后就是一系列的HDFS读写操作。
   那么Zookeeper到底为HMaster做了什么?如果是DDL那没话说客户端需要请求HMaster,若进行DML操作,客户端会请求Zookeeper然后直接到HRegionServer不经过HMaster,即使HMaster挂了,也可以进行读写操作,因此Zookeeper作为HBase接待客户端的第一管家,分担HBase的DML操作。     

二、hbase的寻址机制

        既然读写都在 RegionServer 上发生,我们前面有讲到,每个 RegionSever 为一定数量的 Region 服务,那么 Client 要对某一行数据做读写的时候如何能知道具体要去访问哪个 RegionServer 呢?那就是接下来我们要讨论的问题。

1.老的 Region 寻址方式

        在 HBase-0.96 版本以前,HBase 有两个特殊的表,分别是 -ROOT- 表和 .META. 表,其中 -ROOT- 的位置存储在 ZooKeeper 中,-ROOT- 本身存储了 .META. Table 的 RegionInfo 信息,并且 -ROOT- 不会分裂,只有一个 Region。而 .META. 表可以被切分成多个Region。

 1)表原始数据直接存储在每一个region中;
一个表中的数据量很大的时候有可能一个表被切分多个region,有可能存在多个regionserver上;
hbase中是按照rowkey字典顺序排序,每一个region对应一定的rowkey范围,这就必然需要记录每一个region的存储位置。
2).meta表
元数据表是用来存储原始数据的,.meta表记录的region和regionserver的对应关系。
3)-root-表
这个表是终极索引表,不会再进行region分裂,不管多大都只会有一个;
一个region只会存储在一个regionserver上;
这个表的存储位置就存储在zookeeper中。

(1)读取的流程如下图所示:

(2)详细步骤:
第 1 步:Client 请求 ZooKeeper 获得 -ROOT- 所在的 RegionServer 地址。
第 2 步:Client 请求 -ROOT- 所在的 RS 地址,获取 .META. 表的地址,Client 会将 -ROOT- 的相关信息 cache 下来,以便下一次快速访问。
第 3 步:Client 请求 .META. 表的 RegionServer 地址,获取访问数据所在 RegionServer 的地址,Client 会将 .META. 的相关信息 cache 下来,以便下一次快速访问。
第 4 步:Client 请求访问数据所在 RegionServer 的地址,获取对应的数据。

(3)总结:
        从上面的路径我们可以看出,用户需要 3 次请求才能直到用户 Table 真正的位置,这在一定程序带来了性能的下降。在 0.96 版本之前使用 3 层设计的主要原因是考虑到元数据可能需要很大。但是真正集群运行,元数据的大小其实很容易计算出来。在 BigTable 的论文中,每行METADATA 数据存储大小为 1KB 左右,如果按照一个 Region 为 128M 的计算,3 层设计可以支持的 Region 个数为 2^34个,采用 2 层设计可以支持 2^17(131072)。那么 2 层设计的情况下一个集群可以存储 4P 的数据。这仅仅是一个 Region 只有 128M 的情况下。如果是 10G 呢? 因此,通过计算,其实 2 层设计就可以满足集群的需求。因此在 0.96 版本以后就去掉了 -ROOT- 表了。

2.新的 Region 寻址方式

如上面的计算,2 层结构其实完全能满足业务的需求,因此 0.96 版本以后将 -ROOT- 表去掉了。

1)表原始数据直接存储在每一个region中;
一个表中数据量很大有可能一个表被切分多个region;
有可能存在多个regionserver上 hbase中按照rowkey字典顺序排序;
每一个region对应一定的rowkey范围;
需要记录每一个region的存储位置。
2).meta表
元数据表是存储原始数据的,记录region和 regionserver的对应关系;
这个.meta 只有一个不会再进行分裂。
3).meta表的存储regionserver的位置以及编号存在zookeeper中;
zk中存储的是.meta表的存储路径。

(1)读取的流程如下图所示:

(2)访问路径变成了 3 步:
第 1 步:Client 请求 ZooKeeper 获取 .META. 所在的 RegionServer 的地址。
第 2 步:Client 请求 .META. 所在的 RegionServer 获取访问数据所在的 RegionServer 地址,Client 会将 .META. 的相关信息 cache 下来,以便下一次快速访问。
第 3 步:Client 请求数据所在的 RegionServer,获取所需要的数据。

(3)总结去掉 -ROOT- 的原因有如下 2 点:
其一:提高性能;
其二:2 层结构已经足以满足集群的需求。

(4)问题说明:
        这里还有一个问题需要说明,那就是 Client 会缓存 .META. 的数据,用来加快访问,既然有缓存,那它什么时候更新?如果 .META. 更新了,比如 Region1 不在 RerverServer2 上了,被转移到了 RerverServer3 上。Client 的缓存没有更新会有什么情况?
        其实,Client 的元数据缓存不更新,当 .META. 的数据发生更新。如上面的例子,由于 Region1 的位置发生了变化,Client 再次根据缓存去访问的时候,会出现错误,当出现异常达到重试次数后就会去 .META. 所在的 RegionServer 获取最新的数据,如果 .META. 所在的RegionServer 也变了,Client 就会去 ZooKeeper 上获取 .META. 所在的 RegionServer 的最新地址。

三、HBase读写过程

1.hbase的读操作:

        1)首先从zk找到meta表的region位置,然后读取meta表中的数据,meta表中存储了用户表的region信息;
        2)根据要查询的namespace、表名和rowkey信息。找到写入数据对应的region信息;
        3)找到这个region对应的regionServer,然后发送请求;
        4)查找对应的region;
        5)先从memstore查找数据,如果没有,再从BlockCache上读取;

HBase上Regionserver的内存分为两个部分:
一部分作为Memstore,主要用来写;
另外一部分作为BlockCache,主要用于读数据;

        6)如果BlockCache中也没有找到,再到StoreFile上进行读取;
        从storeFile中读取到数据之后,不是直接把结果数据返回给客户端,而是把数据先写入到BlockCache中,目的是为了加快后续的查询;然后在返回结果给客户端。

2.hbase的写操作:

        (1)Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server;
        (2)访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问;
        (3)与目标 Region Server 进行通讯;
        (4)将数据顺序写入(追加)到 WAL,为了数据的持久化和恢复;
        (5)将数据写入对应的 MemStore,数据会在 MemStore 进行排序;
        (6)向客户端发送 ack;
        (7)等达到 MemStore 的刷写时机后,将数据刷写到 HFile。

四、RegionServer 工作机制

1.region 分配

        任何时刻,一个 region 只能分配给一个 region server。master 记录了当前有哪些可用的 region server。以及当前哪些 region 分配给了哪些 region server,哪些 region 还没有分配。当需要 分配的新的 region,并且有一个 region server 上有可用空间时,master 就给这个 region server 发送一个装载请求,把 region 分配给这个 region server。region server 得到请求后,就开始 对此 region 提供服务。

2.region server 上线

        master 使用 zookeeper 来跟踪 region server 状态。当某个 region server 启动时,会首先在 zookeeper 上的 server 目录下建立代表自己的 znode。由于 master 订阅了 server 目录上的变 更消息,当 server 目录下的文件出现新增或删除操作时,master 可以得到来自 zookeeper 的 实时通知。因此一旦 region server 上线,master 能马上得到消息。

3.region server 下线

        当 region server 下线时,它和 zookeeper 的会话断开,zookeeper 而自动释放代表这台 server 的文件上的独占锁。master 就可以确定:
        1、region server 和 zookeeper 之间的网络断开了。
        2、region server 挂了。
        无论哪种情况,region server 都无法继续为它的 region 提供服务了,此时 master 会删除 server 目录下代表这台 region server 的 znode 数据,并将这台 region server 的 region 分配给其它还活着的 region server。

五、Master 工作机制

1.master 上线

master 启动进行以下步骤:
        a、从 zookeeper 上获取唯一一个代表 active master 的锁,用来阻止其它 master 成为 master。
        b、扫描 zookeeper 上的 server 父节点,获得当前可用的 region server 列表。
        c、和每个 region server 通信,获得当前已分配的 region 和 region server 的对应关系。
        d、扫描.META.region 的集合,计算得到当前还未分配的 region,将他们放入待分配 region 列表。

2.master 下线

        由于 master 只维护表和 region 的元数据,而不参与表数据 IO 的过程,master 下线仅导致所有元数据的修改被冻结:

无法创建删除表;

无法修改表的schema;

无法进行region的负载均衡;

无法处理region 上下线;

无法进行region的合并;

唯一例外的是region的split可以正常进行,因为只有region server参与;

表的数据读写还可以正常进行。

因此 master 下 线短时间内对整个 hbase 集群没有影响。
        从上线过程可以看到,master 保存的信息全是可以冗余信息(都可以从系统其它地方 收集到或者计算出来),因此,一般 hbase 集群中总是有一个 master 在提供服务,还有一个以上的 master 在等 待时机抢占它的位置。

以上是关于HBase的原理及运行机制的主要内容,如果未能解决你的问题,请参考以下文章

HBase-架构原理

从原理到参数解析,HBase 刷写与合并机制介绍

你想要的 HBase 原理都在这了

jvm原理及性能调优系列(自动内存管理机制)

2021年大数据HBase(十四):HBase的原理及其相关的工作机制

2021年大数据HBase(十四):HBase的原理及其相关的工作机制