深入HBase架构原理

深入学习HBase架构原理

HBase定义

HBase 是一个高可靠、高性能、面向列、可伸缩的分布式存储系统,利用Hbase技术可在廉价PC Server上搭建大规模结构化存储集群。

HBase 是Google Bigtable 的开源实现,与Google Bigtable 利用GFS作为其文件存储系统类似, HBase 利用Hadoop HDFS 作为其文件存储系统;Google 运行MapReduce 来处理Bigtable中的海量数据, HBase 同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable 利用Chubby作为协同服务, HBase 利用Zookeeper作为对应。

HBase 的特点

HBase 中的表一般有以下特点。

1) 大:一个表可以有上亿行,上百万列。

2) 面向列:面向列表(簇)的存储和权限控制,列(簇)独立检索。

3) 列式存储,其数据在表中是按照某列存储的,这样在查询只需要少数几个字段时,能大大减少读取的数据量。

4) 稀疏:对于为空(NULL)的列,并不占用存储空间,因此,表可以设计的非常稀疏。

5) 无模式:每一行都有一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中不同的行可以有截然不同的列

6) 数据多版本:Hbase每一个列的存储有多个Version。

7) 数据类型单一,Hbase中的数据都是字符串,没有类型。

8) 扩展性:底层依赖HDFS。

9) 高可靠性:WAL机制保证了数据写入时不会因集群异常而导致写入数据丢失,Replication机制保证了在集群出现严重的问题时,数据不会发生丢失或损坏。而且Hbase底层使用HDFS,HDFS本身也有备份。

10) 高性能:底层的LSM数据结构和Rowkey有序排列等架构上的独特设计,使得Hbase具有非常高的写入性能。region切分,主键索引和缓存机制使得Hbase在海量数据下具备一定的随机读取性能,该性能真对Rowkey的查询能到达到毫秒级别。

MapReduce on HBase

在HBase系统上运行批处理运算,最方便和实用的模型依然是MapReduce,如下图:

HBase Table和Region的关系,比较类似HDFS File和Block的关系,HBase提供了配套的TableInputFormat和TableOutputFormat API,可以方便的将HBase Table作为Hadoop MapReduce的Source和Sink,对于MapReduce Job应用开发人员来说,基本不需要关注HBase系统自身的细节。

Table & Region

当Table随着记录数不断增加而变大后,会逐渐分裂成多份splits,成为regions,一个region由[startkey,endkey)表示,不同region会被Master分配给相应的RegionServer进行管理。 

HBase中有两张特殊的Table, -ROOT- 和 .META. 
- .META. :记录了用户表的Region信息,.META.可以有多个region 

表包含所有的用户空间region列表,以及Region Server的服务器地址

- -ROOT-:记录了.META.表的Region信息,-ROOT-只有一个region 

表包含.META.表所在的region列表,该表只有一个Region;Zookeeper中记录了-ROOT-表的location

- Zookeeper中记录了-ROOT-表的location 
Client访问用户数据之前需要先访问zookeeper,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过client端会做cache缓存。

HBase 访问接口

HBase 支持很多种访问,访问HBase的常见接口如下。

1、Native Java API,最常规和高效的访问方式,适合Hadoop MapReduce Job并行

批处理HBase表数据。

2、HBase Shell,HBase的命令行工具,最简单的接口,适合HBase管理使用。

3、Thrift Gateway,利用Thrift序列化技术,支持C++,PHP,Python等多种语言,

适合其他异构系统在线访问HBase表数据。

4、REST Gateway,支持REST 风格的Http API访问HBase, 解除了语言限制。

5、Pig,可以使用Pig Latin流式编程语言来操作HBase中的数据,和Hive类似,本质最终也是编译成MapReduce Job来处理HBase表数据,适合做数据统计。

6、Hive,当前Hive的Release版本尚没有加入对HBase的支持,但在下一个版本Hive 0.7.0中将会支持HBase,可以使用类似SQL语言来访问HBase。

HBase 存储结构(系统结构)

HBase的架构图上可以看出,HBase中的存储包括Client、HMaster、HRegionServer、HRegion、Store、MemStore、StoreFile、HFile、HLog等,接下来绍他们的作用

HBase中的每张表都通过行键按照一定的范围被分割成多个子表(HRegion),默认一个HRegion超过256M就要被分割成两个,这个过程由HRegionServer管理,而HRegion的分配由HMaster管理。

Client

包含访问HBase的接口,并维护cache来加快对HBase的访问,比如region的位置信息

Zookeeper

1. 存放整个 HBase集群的元数据以及集群的状态信息。

2. 实现HMaster主从节点的failover。

3. 保证任何时候,集群中只有一个master

4. 存储所有Region的寻址入口

5. 实时监控Region server的上线和下线信息。并实时通知给master

6. 存储HBase的schema和table元数据

HMaster

1、为Region server分配region。

2、负责Region server的负载均衡。

3、发现失效的Region server并重新分配其上的region。

4、 HDFS上的垃圾文件回收。

5、 处理schema更新请求,ü管理用户对table的增删改查操作

HRegionServer

1、维护master分配给他的region,处理对这些region的io请求。

2、负责切分正在运行过程中变的过大的region。

可以看到,client访问hbase上的数据并不需要master参与(寻址访问zookeeper和 region server,数据读写访问region server),master仅仅维护table和region的元数据信息(table的元数据信息保存在zookeeper上),负载很低。 HRegionServer存取一个子表

时,会创建一个HRegion对象,然后对表的每个列族创建一个Store实例,每个Store都会有一个MemStore和0个或多个StoreFile与之对应,每个StoreFile都会对应一个HFile,

HFile就是实际的存储文件。因此,一个HRegion有多少个列族就有多少个Store。一个

HRegionServer会有多个HRegion和一个HLog。

HRegion

table在行的方向上分隔为多个Region。Region是HBase中分布式存储和负载均衡的最小单元,即不同的region可以分别在不同的Region Server上,但同一个Region是不会拆分

到多个server上。

Region按大小分隔,每个表一般是只有一个region。随着数据不断插入表,region不断增大,当region的某个列族达到一个阈值(默认256M)时就会分成两个新的region。

每个region由以下信息标识:

1、< 表名,startRowkey,创建时间>

2、由目录表(-ROOT-和.META.)记录该region的endRowkey

HRegion定位:Region被分配给哪个Region Server是完全动态的,所以需要机制来定位Region具体在哪个region server。

HBase使用三层结构来定位region:

1、通过zk里的文件/hbase/rs得到-ROOT-表的位置。-ROOT-表只有一个region。

2、通过-ROOT-表查找.META.表的第一个表中相应的region的位置。其实-ROOT-表是.META.表的第一个region;.META.表中的每一个region在-ROOT-表中都是一行记录。

3、通过.META.表找到所要的用户表region的位置。用户表中的每个region在.META.表中都是一行记录。

-ROOT-表永远不会被分隔为多个region,保证了最多需要三次跳转,就能定位到任意的region。client会将查询的位置信息保存缓存起来,缓存不会主动失效,因此如果client上的缓存全部失效,则需要进行6次网络来回,才能定位到正确的region,其中三次用来发现缓存失效,另外三次用来获取位置信息。

Store每一个region由一个或多个store组成,至少是一个store,hbase会把一起访问的数据

放在一个store里面,即为每个ColumnFamily建一个store,如果有几个ColumnFamily,也就有几个Store。一个Store由一个memStore和0或者多个StoreFile组成。 HBase以store的大小来判断是否需要切分region。

MemStore

memStore 是放在内存里的。保存修改的数据即keyValues。当memStore的大小达到

一个阀值(默认64MB)时,memStore会被flush到文件,即生成一个快照。目前hbase 会

有一个线程来负责memStore的flush操作。 StoreFile

memStore内存中的数据写到文件后就是StoreFile,StoreFile底层是以HFile的格式保存。

HFile

HBase中KeyValue数据的存储格式,是hadoop的二进制格式文件。首先HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。Trailer中有指针指向其他数据块

的起始点,FileInfo记录了文件的一些meta信息。 Data Block是hbase io的基本单元,为了提高效率,HRegionServer中有基于LRU的block cache机制。每个Data块的大小可以在创

建一个Table的时候通过参数指定(默认块大小64KB),大号的Block有利于顺序Scan,小号的Block利于随机查询。每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成,Magic内容就是一些随机数字,目的是防止数据损坏,结构如下。

 

HFile结构图如下:

Data Block段用来保存表中的数据,这部分可以被压缩。 Meta Block段(可选的)用来保存用户自定义的kv段,可以被压缩。 FileInfo段用来保存HFile的元信息,不能被压缩,用户也可以在这一部分添加自己的元信息。 Data Block Index段(可选的)用来保存Meta Blcok的索引。 Trailer这一段是定长的。保存了每一段的偏移量,读取一个HFile时,会首先

读取Trailer,Trailer保存了每个段的起始位置(段的Magic Number用来做安全check),然

后,DataBlock Index会被读取到内存中,这样,当检索某个key时,不需要扫描整个HFile,而只需从内存中找到key所在的block,通过一次磁盘io将整个 block读取到内存中,

再找到需要的key。DataBlock Index采用LRU机制淘汰。 HFile的Data Block,Meta Block

通常采用压缩方式存储,压缩之后可以大大减少网络IO和磁盘IO,随之而来的开销当然是需要花费cpu进行压缩和解压缩。目标HFile的压缩支持两种方式:gzip、lzo。

 

另外,针对目前针对现有HFile的两个主要缺陷:

a) 占用过多内存

b) 启动加载时间缓慢

基于此缺陷,提出了HFile Version2设计。 HLog

其实HLog文件就是一个普通的Hadoop Sequence File, Sequence File的value是key

时HLogKey对象,其中记录了写入数据的归属信息,除了table和region名字外,还同时包

括sequence number和timestamp,timestamp是写入时间,sequence number的起始值为0,或者是最近一次存入文件系统中的sequence number。 Sequence File的value是HBase的KeyValue对象,即对应HFile中的KeyValue。

HLog(WAL log):WAL意为write ahead log,用来做灾难恢复使用,HLog记录数据的所有变更,一旦region server 宕机,就可以从log中进行恢复。

LogFlusher

前面提到,数据以KeyValue形式到达HRegionServer,将写入WAL之后,写入一个

SequenceFile。看过去没问题,但是因为数据流在写入文件系统时,经常会缓存以提高性能。这样,有些本以为在日志文件中的数据实际在内存中。这里,我们提供了一个

LogFlusher的类。它调用HLog.optionalSync(),后者根据 hbase.regionserver.optionallogflushinterval (默认是10秒),定期调用Hlog.sync()。另外,HLog.doWrite()也会根据 hbase.regionserver.flushlogentries (默认100秒)定期调用Hlog.sync()。Sync() 本身调用HLog.Writer.sync(),它由SequenceFileLogWriter实现。 LogRoller

Log的大小通过$HBASE_HOME/conf/hbase-site.xml 的

hbase.regionserver.logroll.period 限制,默认是一个小时。所以每60分钟,会打开一个新的log文件。久而久之,会有一大堆的文件需要维护。首先,LogRoller调用

HLog.rollWriter(),定时滚动日志,之后,利用HLog.cleanOldLogs()可以清除旧的日志。

它首先取得存储文件中的最大的sequence number,之后检查是否存在一个log所有的条目

的“sequence number”均低于这个值,如果存在,将删除这个log。每个region server维

护一个HLog,而不是每一个region一个,这样不同region(来自不同的table)的日志会混在一起,这样做的目的是不断追加单个文件相对于同时写多个文件而言,可以减少磁盘寻址次数,因此可以提高table的写性能。带来麻烦的时,如果一个region server下线,为了恢复其上的region,需要将region server上的log进行拆分,然后分发到其他region server上进

行恢复。

HBase与Zookeeper的关系 

 

 1. HBase依赖Zookeeper

       首先HMaster和RegionServer都需要和Zookeeper交互,因为RegionServer上线了还需要交互,之后Zookeeper知道了告诉HMaster,而下线或断开了Zookeeper知道了也告诉HMaster;同时HMaster还管理RegionServer,HMaster还会在HDFS上写Region数据。

       2. 默认情况下,HBase依赖、管理Zookeeper实例,比如,启动或者停止Zookeeper;

       3. HMaster与HRegionServer启动时会向Zookeeper注册;

       4. Zookeeper的引入使得HMaster不再是单点故障。

HBase 设计

HBase 中的每一张表就是所谓的 BigTable。BigTable 会存储一系列的行记录,行记录

有三个基本类型的定义:Row Key、Time Stamp、Column。

1、Row Key 是行在 BigTable 中的唯一标识。

2、Time Stamp 是每次数据操作对应关联的时间戳,可以看做 SVN 的版本。

3、Column 定义为< family>:< label>,通过这两部分可以指定唯一的数据的存储列,family 的定义和修改需要对 HBase 进行类似于 DB 的 DDL 操作,而 label ,不需要定义直接可以使用,这也为动态定制列提供了一种手段。family 另一个作用体现在物理存储优化读写操作上,同 family 的数据物理上保存的会比较临近,因此在业务设计的过程中可以利用这个特性。

HBase逻辑模型

HBase 以表的形式存储数据。表由行和列组成。列划分为若干个列族(row family),如下图所示。

HBase逻辑数据模型图

 

1、 Row Key

与 NoSQL 数据库一样,Row Key 是用来检索记录的主键。访问 HBase table 中的行,只有三种方式:

1)通过单个 Row Key 访问。

2)通过 Row Key 的 range 全表扫描。

3)Row Key 可以使任意字符串(最大长度是64KB,实际应用中长度一般为 10 ~

100bytes),在HBase 内部,Row Key 保存为字节数组。

在存储时,数据按照 Row Key 的字典序(byte order)排序存储。设计 Key 时,要充分排序存储这个特性,将经常一起读取的行存储到一起(位置相关性)。

注意字典序对 int 排序的结果是 1,10,100,11,12,13,14,15,16,17,18,19,20,21,..., 9,91,92,93,94,95,96,97,98,99。要保存整形的自然序,Row Key 必须用 0 进行左填充。

行的一次读写是原子操作(不论一次读写多少列)。这个设计决策能够使用户很容易理解程序在对同一个行进行并发更新操作时的行为。

2、列族

HBase 表中的每个列都归属于某个列族。列族是表的 Schema 的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀,例如 courses:history、

courses:math 都属于 courses 这个列族。

访问控制、磁盘和内存的使用统计都是在列族层面进行的。在实际应用中,列族上的控制权限能帮助我们管理不同类型的应用,例如,允许一些应用可以添加新的基本数据、一些应用可以读取基本数据并创建继承的列族、一些应用则只允许浏览数据(甚至可能因为隐私的原因不能浏览所有数据)。

3、时间戳

HBase 中通过 Row 和 Columns 确定的一个存储单元称为 Cell。每个 Cell 都保存着同

一份数据的多个版本。版本通过时间戳来索引,时间戳的类型是 64 位整型。时间戳可以由HBase(在数据写入时自动)赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显示赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 Cell 中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

为了避免数据存在过多版本造成的管理(包括存储和索引)负担,HBase 提供了两种数据版本回收方式。一是保存数据的最后 n 个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。

4、 Cell

Cell 是由 {row key,column(=< family> + < label>),version} 唯一确定的单元。

Cell 中的数据是没有类型的,全部是字节码形式存储。

HBase物理存储

Table 在行的方向上分割为多个HRegion,每个HRegion分散在不同的RegionServer中。

每个HRegion由多个Store构成,每个Store由一个memStore和0或多个StoreFile组成,每个Store保存一个Columns Family

HRegion与Store关系图

StoreFile以HFile格式存储在HDFS中。

小小总结

1、有关Hbase表的特点

 A、大:一个表可以有上亿行,上百万列

 B、面向列:面向列表(簇)的存储和权限控制,列(簇)独立检索

 C、稀疏:对于为空(NULL)的列,并不占用存储空间,因此,表可以设计的非常稀疏

2、有关HMaster的作用

 A、为Region server分配region

 B、负责Region server的负载均衡

 C、发现失效的Region server并重新分配其上的region

 D、HDFS上的垃圾文件回收

3、HBase定位region

 A、通过zk里的文件/hbase/rs得到-ROOT-表的位置。-ROOT-表只有一个region

 B、通过-ROOT-表查找.META.表的第一个表中相应的region的位置。其实-ROOT-表是.META.表的第一个region;.META.表中的每一个region在-ROOT-表中都是一行记录

 C、通过.META.表找到所要的用户表region的位置。用户表中的每个region在.META.表中都是一行记录

猜你喜欢

转载自blog.csdn.net/zhanaolu4821/article/details/81984107