image.pngimage.png

HBase是一种关系型的分布式数据库,可以用来存储海量的数据,满足海量数据的实时响应查询计算的应用要求。


image.png

在介绍正式内容之前,我们可以先想一想,大数据平台所提供的主要功能是什么?
大数据平台主要提供的是存储和计算,对于所学习的每一种组件,应该考虑其应用场景。
那么HBase除了能够应对海量数据的存储,同时也能够支撑实时响应查询计算。
接下来对HBase进行讲解。


HBase 基本介绍

image.png

HBase简介

image.png

HBase是谷歌的bigTable的开源实现,它能够提供高可靠、高性能、面向列、可伸缩的分布式存储服务。
采用谷歌的bigTable大表机制,存储的规模能够达到数十亿行级别以及数百万列的级别,并且对大数据的读和写能够达到实时响应的服务。
HBase的底层文件系统时采用的HDFS进行存储的,因此能够提供高可靠的文件读写。
HBase用zookeeper提供协同服务,zookeeper为HBase提供了三种服务,分别是:

  1. 分布式锁服务
  2. 监听服务
  3. 数据库服务

HBase与RDB的对比

image.png
上面是HBase与传统的关系型数据库的对比。

  1. 数据索引

对于HBase来说,它的数据索引仅仅只有行键作为的索引。
传统的关系型数据库,通常可以对不同的列,构建比较复杂的索引,来提高数据的访问性能。
但是HBase如果通过巧妙的设计,HBase的访问方法都能够利用行键对行键进行扫描,或者是扫描行键的某一个区域,从而查询到数据。使得整个系统的性能不至于下降。

  1. 数据维护

HBase的更新操作不会去替换当前的值,只会增加一个新的版本。
而对于传统的关系型数据库来说,新值将会替换旧值。旧值被覆盖后就不存在了。

  1. 可伸缩性

关系数据库很难实现横向扩展,纵向扩展的空间也比较有限。
相反,HBase和BigTable这些分布式数据库就是为了实现灵活的水平扩展而开发的,能够轻易地通过在集群中增加或者减少硬件数量来实现性能的伸缩。


HBase应用场景

image.png

  1. HBase是面向于海量数据存储的,存储的数据可以达到TB和PB级别。
  2. HBase不需要完全拥有关系型数据库的ACID特性
    1. A代表事务的原子性
    2. C代表事务的一致性
    3. I代表事务的独立性
    4. D代表事务的持久性
  3. HBase采用zookeeper为其提供服务,可以提供高吞吐量的客户端查询,在海量的数据中实现高效的随机读取机制,这是通过HBase行键实现的。
  4. HBase具有很强的性能伸缩能力,通过增加HBase的节点,能够水平扩展HBase的存储以及查询能力
  5. HBase能够同时处理结构化、半结构化、非结构化的数据

数据模型

image.png

  • 总体上来说,应用程序是以表的方式在HBase存储数据的。
  • 表是由行和列构成的,所有的列是从属于某一个列族的。
  • 行和列的交叉点称之为cell,cell种存储的内容是具有版本化的。cell的内容是不可分割的字节数组。这个也是与传统的关系型数据库一个显著的区别。
  • 表的行键也是一段字节数组,所以任何东西都可以保存进去,不论是字符串或者数字。
  • 另外HBase的表是按key排序的,排序方式是针对字节的。
  • 所有的表都必须要有主键-key。

Hbase表结构-1
image.png

可以看到Hbase每一行记录都是有行键的。
对于Hbase是有列族的概念,在列族下又有不同的列。
行键和列相交的地方成为cell,实际上是单元格的内容。
对于每一个单元格的内容有版本,版本是根据时间戳来决定的。
比如在t1时刻存进去的是male,那么在t2时刻对male进行修改,实际上存储的是female,那么male和female都存储在Hbase的cell种。

Hbase表结构-2

image.png
上面是对表结构的进一步解释

  • 表:HBase采用表来组织数据,表由行和列组成,列划分为若干个列族。
  • 行:每个HBase表都由若干行组成,每个行由行键(row key)来标识。
  • 列族:一个HBase表被分组成许多“列族”(Column Family)的集合,列族里面有很多列,一般称这个列的名称为列限定符。列族是基本的访问控制单元。
  • 列限定符:列族里的数据通过列限定符(或列)来定位。
  • 单元格:在HBase表中,通过行、列族和列限定符确定一个“单元格”(cell),单元格中存储的数据没有数据类型,总被视为字节数组byte[]。
  • 时间戳:每个单元格都保存着同一份数据的多个版本,这些版本采用时间戳进行索引。

数据存储概念视图

image.png

这是一个名为webtable的表,包含两个列族:contents和anchor
在这个例子里面
anchor有两个列 (anchor:aa.com, anchor:bb.com),
contents仅有一列(contents:html)
从表中可以发现,不同的行键、时间戳、列族、以及列限定符,构成一行数据。
并且可以从表中看到有一些地方是空白的。这表示HBase存储表示具有稀疏性。

数据存储物理视图

image.png

尽管在概念视图里,表可以被看成是一个稀疏的行的集合。但在物理上,它的是区分列族存储的。新的columns可以不经过声明直接加入一个列族。

对于新的列可以不加声明的直接加一个列族。
在程序运行的时候,可以通过添加数据的方式,不经过声明加入一个列族,这两个表是针对于不同列族的存储物理视图。


行存储

image.png
为进一步加深对HBase存储的理解,分别给出行存储和列存储的机制。

行存储,数据按行存储在底层文件系统中。通常,每一行会被分配固定的空间。
优点:有利于增加/修改整行记录等操作;有利于整行数据的读取操作。
缺点:单列查询时,会读取一些不必要的数据。

列存储

image.png

HBase采用列存储
列存储,数据以列为单位,存储在底层文件系统中。
大家可以看到这个图,这是一个传统的二维表结构,包含ID、Name、Phone、Address。那么针对于每一列数据,会把它取出来,当然,会做一些变化,为具体的每个单元格里面的值去加上一个键。
采用这种方式,它的优点是有利于面向单列数据的读取/统计等操作。比如想读取一批用户的电话号码,可以直接把相应的这一列取出来,就没有必要像行存储的样子,要去除所有的数据,然后再进行投影。
它的缺点:如果想要整行读取时,可能需要多次I/O操作。


HBase架构介绍

HBase架构介绍 - 1

image.png
HBase架构介绍
从上至下对HBase架构中的主要组件进行介绍
这里有client,client是HBase的客户端。client包含了一些接口。
HBase要使用到zookeeper集群,前面给大家介绍过zookeeper主要向HBase提供三种服务。
HBase架构中,HMaster是处于主控节点的地位,相应的slaver节点就是HRegionServer。
HMaster负责存储表的结构以及对HRegionServer进行控制,而RegionServer主要是用来存储数据以及返回客户端的查询请求。
在底层可以看到,HBase最终的文件是存储在HDFS上,这些文件最后都要转换成DataNode种的block。

HBase架构介绍 - 2

image.png
HBase的架构包括三个主要的功能组件:

  • 库函数:链接到每个客户端
  • 一个HMaster主服务器
  • 多个HRegionServer服务器

    HBase架构介绍 - 3

    image.png
    接下来对HBase的主要组件功能进行介绍

  • 主服务器HMaster负责管理和维护HBase表的分区信息,维护HRegionServer列表,分配Region,负载均衡。

  • HRegionServer负责存储和维护分配给自己的Region,处理来自客户端的读写请求。

请注意,如果有客户端要读或者写某些数据,客户端是直接向zookeeper发送请求的,zookeeper知道了要读和写的Region,然后找到相应的HRegionServer。从这个流程来看,客户端并没有直接跟Master进行通信。

  • 客户端并不是直接从HMaster主服务器上读取数据,而是在获得Region的存储位置信息后,直接从HRegionServer上读取数据。
  • 客户端并不依赖HMaster,而是通过Zookeeper来获得Region位置信息,大多数客户端甚至从来不和HMaster通信,这种设计方式使得HMaster负载很小 。也有特殊情况,比如说想创建表以及创建表的结构,这时候客户端是需要与Master进行通信的。

    HBase架构介绍 - 4

    image.png

接下来介绍HBase的存储架构
HBase中表是怎么一回事,表根据rowkey进行了横向划分,也就是起始rowkey和结束rowkey划成一个区域,用来存储Region。
一个Region下面包含若干个store,每一个store根据列族存储相应的Region数据。
store里面又分为memstore,memstore是一个缓存, 主要是方便临时写以及读取数据的查找。
再有就是storeFile,是每一个store把相应的Region数据存储到具体的物理表上。
再就是block,block是实际的一个具体的数据表。数据表采用block的方式,最后存储到HDFS上,这就是HBase的存储架构。


表和Region

image.png

来研究一下HBase中的表哥Region的关系。
开始的时候,HBase表开始只有一个Region,随着数据的不断增多,这个Redion就要不断的进行分裂。就是一个Region会分成两个Region,两个Region再分成多个Region。
比如上上图的中间这个表中又一个Region,就会分裂成右侧这个表中的两个Region。Region拆分操作非常快,接近瞬间,如果说此时有客户端请求去读取Redion中的数据,还是从被拆分的Region里面读取数据,并不受影响。知道分裂过程结束,把存储文件异步地写到独立的文件之后,才会从新的Region里面读相应的数据。
这就是表和Region的关系。


Region的定位 (1)

image.png
接下来学习Region的定位
在Hadoop的早期版本中采用的时三级模式。
就是采用zookeeper存储root表的位置。一般情况下root表只有一个Region,当然root表还是存储在HBase上。
root表中又记录了若干个meta表,meta表里面就存储了若干个region的位置信息。
因此客户端去查找某个具体Region里面数据的时候它经过三级模式。

在最新的HBase的版本中采用的是两级模式。
也就是采用zookeeper直接存储meta表的信息,而meta表里面又记录了用户表,也就是Region的具体信息。
这个过程是先找寻Meta Region地址。再由Meta Region找寻User Region地址。
新的这种方式较之前的方式少了一个级别。

Region的定位 - 2

image.png

  • 为了加快访问速度,hbase:meta表会被保存在内存中。
  • 假设hbase:meta表的每行(一个映射条目)在内存中大约占用1KB,并且每个Region限制为128MB。
  • 两层结构可以保存的Region数目是128MB/1KB = 217个Region。

注意,即使采用的是两层架构,按照现在一般情况下设置每个Region的大小大概是1~2个GB。HBase也能够支撑海量数据的存储。


客户端

image.png


HMaster高可用

image.png

接下来介绍HMaster高可用性
采用zookeeper的锁机制,可以帮助集群的一个Master做集群的总管。其他的Master都作为备用Master,当一个Master当季的时候,通过投票机制可以选择备用的Master作为主Master,这样就避免了Master的单点失效问题。

HMaster

image.png
主服务器HMaster主要负责表和Region的管理工作:

  • 管理用户对表的增加、删除、修改、查询等操作。
  • 实现不同HRegionServer之间的负载均衡。
  • 在Region分裂或合并后,负责重新调整Region的分布。
  • 对发生故障失效的HRegionServer上的Region进行迁移。

HRegionServer

image.png
HRegionServer是HBase中最核心的模块。

  • 负责维护分配给自己的Region。
  • 响应用户的读写请求。

如果使用了zookeeper,HRegionServer还要报告自己的心跳信息给zookeeper。


HBase 关键流程

用户读写数据过程

image.png

  • 用户写入数据时,首先是访问zookeeper,被分配到相应HRegionServer去执行。
  • 用户数据首先被写入到Hlog中,得到一个返回值之后,再写入MemStore中,最终写到磁盘上形成StoreFile。
  • 只有当操作写入Hlog之后,commit()调用才会将其返回给客户端。
  • 当用户读取数据时, HRegionServer会首先访问MemStore缓存,如果找不到,再去磁盘上面的StoreFile中寻找。

缓存的刷新

image.png

  • 系统会周期性地把MemStore缓存里的内容刷写到磁盘的StoreFile文件中,清空缓存,并在Hlog里面写入一个标记
  • 每次刷写都生成一个新的StoreFile文件,因此,每个Store包含多个StoreFile文件
  • 每个HRegionServer都有一个自己的HLog 文件,每次启动都检查该文件,确认最近一次执行缓存刷新操作之后是否有客户端在刷新的时候往Hlog写数据;如果发现更新,则先写入MemStore,再刷写到StoreFile,开始为用户提供服务

StoreFile的合并

image.png

  • 每次刷写都生成一个新的StoreFile,数量太多,影响查找速度
  • 调用Store.compact()把多个合并成一个
  • 合并操作比较耗费资源,只有数量达到一个阈值才启动合并

Store工作原理

image.png

  • Store是HRegionServer的核心
  • 多个StoreFile合并成一个
  • 单个StoreFile过大时,又触发分裂操作,1个父Region被分裂成两个子Region

HLog工作原理 - 1

image.png

  • 分布式环境必须要考虑系统出错。HBase采用HLog保证系统恢复
  • HBase系统为每个HRegionServer配置了一个HLog文件,它是一种预写式日志(Write Ahead Log)
  • 用户更新数据必须首先写入日志后,才能写入MemStore缓存,并且,直到MemStore缓存内容对应的日志已经写入磁盘,该缓存内容才能被刷写到磁盘

HLog工作原理 - 2

image.png

  • Zookeeper会实时监测每个HRegionServer的状态,当某个HRegionServer发生故障时,Zookeeper会通知HMaster.。
  • HMaster首先会处理该故障HRegionServer上面遗留的HLog文件,这个遗留的HLog文件中包含了来自多个Region对象的日志记录。
  • 系统会根据每条日志记录所属的Region对象对HLog数据进行拆分,分别放到相应Region对象的目录下,然后,再将失效的Region重新分配到可用的HRegionServer中,并把与该Region对象相关的HLog日志记录也发送给相应的HRegionServer 。
  • HRegionServer领取到分配给自己的Region对象以及与之相关的HLog日志记录以后,会重新做一遍日志记录中的各种操作,把日志记录中的数据写入到MemStore缓存中,然后,刷新到磁盘的StoreFile文件中,完成数据恢复。共用日志优点:提高对表的写操作性能;缺点:恢复时需要分拆日志。

Hbase突出特点

多HFile的影响

image.png
如图所示,横坐标表示HFile文件的数目,纵坐标表示读取的时延。可以看到在HFile文件数目较少的情况下,读取的时延大概在两个毫秒左右。
但是随着HFile文件数目的不断增多,读取的时延将会越来越大。
如图所示,当HFile文件数目达到14400个左右的时候,读取的时延将达到20毫秒。上升了一个级别。


Compaction - 1

image.png
为了降低读取读取时延,采用了压缩的方法。

  • Compaction(压缩)的目的,是为了减少同一个Region中同一个ColumnFamily下面的小文件(HFile)数目,从而提升读取的性能。
  • Compaction分为Minor、Major两类:
    • Minor:小范围的Compaction。有最少和最大文件数目限制。通常会选择一些连续时间范围的小文件进行合并。
    • Major:涉及该Region该ColumnFamily下面的所有的HFile文件。
    • Minor Compaction选取文件时,遵循一定的算法。

Compaction - 2

image.png
如图所示,这是minor压缩以及major压缩的区别。
可以看到minor只会对部分HFile进行压缩,采用major压缩的时候会对所有的HFile进行压缩。
要注意的是,不管是minor压缩还是major压缩,处于这两个阶段的时候都不能够读取数据,因此压缩式是会影响读写性能的。


OpenScanner

image.png
为了进一步提升读写的性能,采用了OpenScanner机制。

  • OpenScanner的过程中,会创建两种不同的Scanner来读取Hfile、 MemStore的数据:
    • HFile对应的Scanner为StoreFileScanner。
    • MemStore对应的Scanner为MemStoreScanner。

BloomFilter

image.png
为了查找过程中缩小对数据的查找范围,采用BloomFilter

  • BloomFilter用来优化一些随机读取的场景,即Get场景。 它可以被用来快速的判断一条用户数据在一个大的数据集合(该数据集合的大部分数据都没法被加载到内存中)中是否存在。
  • BloomFilter在判断一个数据是否存在时,拥有一定的误判率。但对于“用户数据 XXXX不存在” 的判断结果是可信的。
  • HBase的BloomFilter的相关数据,被保存在HFile中。

Hbase性能优化

行键(Row Key)

image.png

  • 行键是按照字典序存储,因此,设计行键时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。
  • 举个例子:如果最近写入HBase表中的数据是最可能被访问的,可以考虑将时间戳作为行键的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE - timestamp作为行键,这样能保证新写入的数据在读取时可以被快速命中。

构建HBase二级索引 - 1

image.png

  • HBase只有一个针对行健的索引
  • 访问HBase表中的行,只有三种方式:
    • 通过单个行健访问
    • 通过一个行健的区间来访问
    • 全表扫描

HBase在新的版本中增加了coprocessor这个特性,基于这个特性有很多二级索引的工具
比如华为的Hindex,Hindex可以对多个表进行索引,也可以对多个列进行索引,也可以基于部分的列值进行索引。
当然,像redis还是有solor也都可以对HBase来进行二级索引。


构建HBase二级索引 - 2

image.png

  • Hindex二级索引
    • Hindex 是华为公司开发的纯 Java 编写的HBase二级索引,兼容 Apache HBase 0.94.8。当前的特性如下:
      • 多个表索引
      • 多个列索引
      • 基于部分列值的索引

HBase常用Shell命令

HBase常用Shell命令

image.png

  • create:创建表
  • list:列出HBase中所有的表信息
  • put:向表、行、列指定的单元格添加数据

值得注意的是,我们向HBase的表中添加数据,我们只能够一个单元格一个单元格的添加数据,不能够整行添加数据。

  • scan:浏览表的相关信息
  • get:通过表名、行、列、时间戳、时间范围和版本号来获得相应单元格的值
  • enable/disable:使表有效或无效
  • drop:删除表

HBase中如果想要删除一个表,必须先使用disable停用表,然后再采取drop删除表


总结

image.png

思考题

HBase中的数据以什么形式存储?( )

  1. Int
  2. Long
  3. String
  4. Byte[]

HBase的分布式存储的最基本单元是?( )

  1. Region
  2. Column
  3. FamilyColumn
  4. Cell