HBase基本原理

HBase概述

HBase是一款基于HDFS做存储的,Zookeeper做调度的能够存储半结构化与非结构化数据的数据库。它不同于Hive它是一个真正的数据库产品,它的内部基于顺序IO与内存读写,能够非常高效的实现数据的增删改查。

 

HBase的总体架构                      

HBase有如下几个部件协调服务:

HMaster:主要负责,给HRegionServer分配Region,HRegionServer的负载均衡。负责HDFS上的垃圾回收。(待讨论)HMaster一般都会配置成双机热备。一个HMaster与一个BackUpHMaster。

Zookeeper:负责协调HBase集群,保证集群中只有一个HMaster、将HRegionServer的在线情况告诉HMaster、存储meta表的的Region的地址信息、存储HBase的元数据信息。

HRegionServer:维护HMaster分配给自己的Region。处理这些Region的IO信息,包括Region的拆分。

Client:访问HBase保存一些消息以提高效率。

HBase表逻辑结构

HBase表的逻辑结构如下图所示:

HBase基本原理_第1张图片

总共由以下几个元素构成:

行键:每一行数据由一个行键来标识,我们在查询HBase中的数据时就是通过行键来定位的。一般的查询有三种方式,①根据行键查询,②根据行键范围查询,③全表扫描

列族:列族是一Hbase表从纵向来切分的逻辑结构,一个列族包含若干列。它是Hbase元数据的一部分。

列:一个列族中包含多个列,在创建HBase表的时候不需要创建列因为它可以在表创建之后动态的添加。它不是元数据的一部分。

单元格:由一个行键所标识的行和某一个列族中的某一列相交形成,这是Hbase中存储数据的最小单位。它里面可以存放若干值,他们分别代表这个单元格中的数据的不同版本。其中不同版本的单元格会被时间戳锁标识。需要注意的是Hbase中没有数据类型所有的类型都是二进制。

数据存储核心组件HRegion

HBase将一个表从逻辑上横向切分成若干个HRegion,这些HRegion会分布在不同的机器上我们把这些·机器称之为HRegionServer。我们也可以看到HRegion是实现HBase分布式与负载均衡的基础。

HBase基本原理_第2张图片

起初,一个表中只包含一个HRegion,所有的数据都放在一个HRegion中。但是随着数据量的积累,HRegion中的数据会越来越多,这时HRegion就会产生分裂。以此类推数据不断增大就会不断的分裂产生更多的HRegion。如下图所示:

HBase基本原理_第3张图片

而HRegion的内部结构如下图所示:

HBase基本原理_第4张图片

一个HBase表包含着多个HRegion;

一个HRegion中包含着多个Store(Store的数量与表中列族的数量是一致的);

一个Store中又包含了两种组件:

  • memStore,这是一块基于内存的区域,一般情况下用户对数据的操作直接与memStore打交道(这也是为什么HBase效率高的原因);
  • storeFile,这时一块基于硬盘的区域,当memStore写数据溢出时就会开启一个新的memStore而旧的memStore会讲之前的数据写到一个storeFile中。而这只是逻辑上的结构,实务上所有的storeFile都会存到HDFS中,在HDFS中storeFile的名字会改名为HFile。

HBase写数据流程

当我们要写入一条数据时

①首先通过表名与行键找到我们需要操作的HRegion(由于是横向切割所以使用的是行键来确定HRegion)。

②然后根据列族找到对应的Store。对该Store中的memStore中写数据。当memStore写数据溢出时就会开启一个新的memStore而旧的memStore会讲之前的数据写到一个storeFile中。最后持久化到HDFS中存储为HFile文件。

③HFile会越存越大然后产生分裂。成不同的小文件。又,memStore的会不断的更新数据,这就使得HFile中的数据过期或者是同一条数据在多个HFile中不一致。这样HFile就会定时触发合并再分裂的机制。具体来说就是将几个HFile合并起来,然后将最新版本的数据覆盖旧版本的数据。最后再将这个文件分裂开来。

写入的过程常常会伴随两个问题:

一个就是memStore写满的问题,这个我们在上面已近做了介绍。还有一个问题就是内存数据断电丢失的问题。解决这个问题的核心组件叫做HLog,每当我们写入一条数据的时候就会提前向HLog中写入一条数据。与此同时,当memStore写满并且开始同步时会向Zookeeper集群发送一个位置信息也叫做redo point。当断电丢失数据时我们首先去找Zookeeper集群然后获得redo point这样我们就会能够定位到HLog中需要恢复的数据了。由于HLog是顺序IO所以即使是基于硬盘的读写但是效率不会太差。最后为了避免太多的HLog文件HBase规定每一个HRegion只能有一个HLog文件。

写入文件的流程如下图所示:

HBase基本原理_第5张图片

HBase读数据流程

HBase写数据需要用到一些概念,我们来分别介绍。

HBase的寻址过程

给定一个表、一个行键、一个列族、一个列如何查到这个值。这个过程必然会先得到目标Region(也就是对应的HRegionServer)。而寻址就是如何根据上述的信息从而定位到那台HRegion的。在HBase中有一张特殊的表(HBase:Meta表),这个表中存放着所有数据的元信息。也就是通过上面的信息再结合这张元数据的表我们就能够很轻易的找到我们要找的目标HRegion。

但是HBase:Mate本身也是一张表也需要去寻找,但有所不同的是这张表所对应的HRegion的信息会放在Zookeepr集群中。所以,我们找到一个目标HRegion的正确姿势就是:

  • 先通过Zookeeper集群获得meta-region-server的值,这个值对应着一个HRegion。
  • 通过①中获得的值找到对应的HBase:Mate所在的HRegionServer进而找到对应的HRegion。
  • 通过查询②里面的值而且再加上我们的表、行键等信息就能够定位目标HRegion。整个寻址过程如下图所示:

 

HBase基本原理_第6张图片

HFile的组成

HBase基本原理_第7张图片

HFile主要由以下几部分组成:

  • DataBlocks段,里面含有多个DataBlock,DataBlock中含有表中的数据,并且它们的底层都是KV对构成的。其中行键是键,值是对应列上的某一个值。(可压缩)
  • DataIndex段,DataBlock的索引,通过它可以快速定位一个DataBlock。
  • MetaBlocks段,保存着用户自定义的KV对。(可压缩)
  • MetaIndex段,MetaBlocks的索引。
  • FileInfo段,HFile的元数据。(不可被压缩)
  • Trailer段,一个定长的保存着,各个段的偏移量,通过访问它可以快速定位其它段。所以读取一个HFile时会首先读取它的Trailer。

 

LSM树的存储策略

LSM树就是一种特殊的B+Tree。它的核心思想就是,将一颗大的数分解成多棵小树,然后等待时机到来时再将小树与大树合并。对应到HBase中就是,在memStore中记录着临时的数据,这些数据按照行键构建成一棵小的B+Tree,随着数据量越来越大当内存中的B+树达到一个阈值时,HBase就会将内存中的小树持久化到硬盘中。然后再将这颗小树与硬盘中已经存在的大树所合并。这样的话会出现内存中的数据与硬盘上的数据不一致的问题,因为这是一个批处理。但是基于搜索树对数级时间复杂度的情况下效率还是非常高的。这就是HBase中的数据存储策略,他的构造如下图所示:

HBase基本原理_第8张图片

HBase的读取数据流程

现在开始正式聊HBase的读取数据流程,首先树是寻址过程。我们会根据表明,行键、列族找到对应的RegionServer然后通过,找到对应的HRegion,然后根据列族找到对应的Store。首先在memStore中寻找这对应的值,如果找到的话就立即返回。如果没有找到的话就开始在所有的StoreFile中找,首先我们找到对应的Trailer它里面包含着各个其它块的偏移量,这样的话就能够轻易地定位到各个数据段。通过Trailer段找到对应的DataBlocksIndex段,然后首先查看索引中是否存在如果不存在直接返回空,如果存在的话就将对应的DataBlock。

这样的话多个StoreFile会返回多个HFile而这里面可能包含一个数据的不同版本的数据。最后再选择一个版本最高的数据。在硬盘上查数据是要比在内存中查数据慢一个数量级。

 

这里总结一下HBase的特点:基于内存与顺序IO读写效率高,按照有序的行键进行查找数据底层基于LSM树查找复杂度低,由于最终的数据都在HDFS上面所以能够存储大量的数据而且数据有很好的可靠性。再加上HMaster与BackUpHMaster的双机热备使得主节点更加的可靠。对于稀疏的数据存储效率高,空闲的部分不会占用任何空间。只支持行级别的事务是一款正儿八经的数据库产品。

 

 

HBase最佳实践法则

HBase表的设计

列族!列族!

当一个HBase表设计完成时是很难改变的,标设计的不好效率会大打折扣。我们通常需要考虑到的指标是行键与列族。

  • 在设计列族的时候要尽量将列族的数量减小,因为一个列族会对应一个Store而一个Store中就会至少开启一个memStore,如果数量太多就会过于耗费内存资源。
  • 在设计列族的时候通常要将常常一起查的数据放在一起(让我想起了操作系统中的局部性原理),如果放到多个列族中当我们要查询这些数据的时候就会发生跨列族的查找。实务上我们通常只使用一个列族。
  • 要避免列族数据倾斜(分配不均匀)的情况发生。首先我们需要明白一个事实就是Region的切割是横向进行的。所以当一个列族中的数据增长很快而另一个列族增长很慢时Region的分割主要是在依赖增长快的一方如下图所示。当这样进行几轮下去就会出现增长小的列族在对应的Region中的数据很少。这样我们在查询数据的时候就可能会发生跨Region的数据查询,这样的话会使得效率十分低下。

 

HBase基本原理_第9张图片

行键

行键在HBase中相当于索引所以他的设计也是非常考究的。实务上通常会遵循以下的规则:

  • 行键尽可能的有意义,可读性要强。
  • 行键不宜过长,因为会占用大量计算机资源。
  • 行键最好是字符串类型,这样可以轻易的适应各种平台。
  • 长度最好保持一致,保证排序的一致性,(有时候10要比2小,对,就是要避免这种情况)。
  • 行键必须唯一,它唯一标识一条数据。

 

你可能感兴趣的:(大数据)