HBase详解

 1.HBase简介

HBase是一个在HDFS上开发的面向列的分布式数据库,能够对大型数据提供随机、实施的读写访问。HBase的运行依赖于其他文件系统,他模仿并提供了基于Google文件系统(GFS)中大表(BigTable)数据库的所有功能。

虽然数据库存储和检索的实现可以选择很多不同的才策略,但是绝大数解决办法--—特别是关系数据库技术的变种----不是为了大规模可伸缩的分布式处理设计的。很多厂商提供复制和分区解决方案,让数据库能够从单节点扩展出去,但是这些技术大都属于“事后”的解决办法,而且非常难以安装和维护。

HBase从另一个方向来解决可伸缩性的问题。它自底向上进行构建,能够简单的通过增加节点来达到线性扩展。HBase并不是关系型数据库,它不支持SQL。它能实现在廉价硬件构成的集群上管理超大规模的稀疏表。

HBase存储的是松散型数据。具体来说,HBase存储的数据介于映射(key/value)和关系型数据之间。


如上图所示,HBase存储的数据可以理解为一种key和value的映射关系,但又不是简简单单的映射关系。除此之外它还具有许多其他的特性。

HBase存储的数据从逻辑上来看就像一张很大的表,并且它的数据行可以根据需要动态增加。除此之外,每个cell(有行和列所确定的位置)中的数据又可以具有多个版本(通过时间戳来区别)。从上图中还可以看出,HBase具有这样的特点:他向下提供了存储,向上提供了运算;另外,在HBase之上还可以使用hadoop的MapReduce计算模型来并行处理大规模数据,这也是它具有强大性能的核心所在,它将数据存储和并行计算完美的结合在一起。

HBase的一个典型应用是webtable,一个以网页URL为主键的表,其中包含爬取的页面和页面的属性。Webtable非常大,行数可以达十亿级。在webtable上连续、批处理的运用分析和解析的MapReduce作业,从而获取相关的统计信息,增加验证的MIME类型列,提供搜索引擎进行索引的解析后的文本内容。与此同时,“爬取器(crawler)”随机的以不同速度访问表中的不同行,更新它们的内容;在用户点击访问网站的缓存页面时,这些随机访问的页面实时提供给它们使用。

2. 概念

2.1.  数据模型简介

应用把数据存放在带标签的表中。表有行和列组成。表格“单元格”----由行和列的坐标交叉决定---是有版本的。默认情况下,版本号自动分配,是HBase插入单元格时的时间戳。单元格的内容是未解释的字节数组。

表中行的键也是字节数组。所以理论上,任何其他东西都可以表示成二进制形式,然后转化为长整型的字符串或直接对数据结构进行序列化,来作为键值。表中的行根据行的键值(也就是表的主键)进行排序。排序根据字节序进行。所有对表的访问都要通过表的主键。

行中的列分为“列族(column family)”。所有的列族成员都有相同的前缀。因此,像列temperature:air和temperature:dew_point都是列族temperature的成员,而station:identifier则属于station族。列族的前缀必须由“可打印的”字符组成。而修饰的结尾字符,即列族修饰符,可以为任意字节。

一个表的列族必须作为表模式定义的一部分预先给出。但是新的列族成员可以随后按需要加入。如:只要目标表中已经有了列族station,那么客户端就在更新时提供新的列station:address,并存储它的值。

物理上,所有的列族成员都一起存放在文件系统中。所以,虽然前面把HBase描述为一个面向列的存储器,但更准确的说法实际上是它是一个面向列族的存储器。由于调优和存储都是在列族这个层次上进行的,所以最好使用所有列族成员都有相同的“访问模式”和大小特征。总之,HBase和RDBMS中的表类似,单元格有版本,行是排序的,而只要列族预先存在,客户端随时可以把列添加都列族中去。

2.2. 区域

HBase自动把表水平划分成“区域”。每个区域由表中行的子集构成。每个区域由它所属于的表、它所包含的第一行及其最后一行来表示。一开始,一个表只有一个区域。但是随着区域开始变大,等到它超出设定的大小阀值,便会在某行的边界上把表分成两个大小基本相同的新分区。在第一次划分之前,所有加载的数据都放在原始区域所在的那台服务器上。随着表变大,区域的个数也会增加。区域是在hbase集群分布数据的最小单位。用这种方式,一个因为太大而无法在单台服务器上的表会被放到服务器集群上,其中每个节点都负责管理表所有区域的一个子集。表的加载也是使用这种方法把数据分布到各个节点去的。在线的所有区域按次序排列就构成了表的所有内容。

2.3. 加锁

无论对行进行访问的事物牵涉到多少列,对行的更新都是“原子的”。这使得“加锁模型”能够保持简单。

2.4.HBase数据模型

2.4.1.Table&column Family

组成部件说明:

RowKey:Table主键 行健 Table中记录按照Row key排序

Column Family: 列族,一个table在水平方向有一个或者多个列族,列族可由任意多个column组成,列族支持动态扩展,无需预定义数据及类型,二进制存储,用户需自进行类型转换。

Column:属于某一个columnfamily,familyName:columnName,每条记录可以动态添加。

Version number:类型为long,模式值是系统时间戳(timestamp),用户可以动态添加

Value(cell):byte array

2.4.2.Table&Regin


    1、Table随着记录增多不断变大,会自动分裂成多份splits,成为Rgions。

    2、一个 region由【startkey、endkey】表示

    3、不同region会被master分配给相应的regionserver进行管理。

2.5.HBase物理模型

  • 每个column family存储在hdfs上的单个文件中,并且空值不会被保存;
  • rowKey和version number在每个column family中均有一份;
  • HBase为了每一个值维护了多级索引,即:<rowkey, timestamp,column family,column name >

2.5.1.物理存储

    1、Table中所有行都会按照rowkey的字典排序列;

    2、Table在行的方向上分割为多个region;

    3、Region按大小分割的,每个表开始只有一个region,随着数据增加,region不断增大,当增大到一个阀值的时候,region会等分分割为列个新的region,之后会越来越多;

    4、Region是HBase中分布式存储和负载均衡的最小单位,不同region分布到不同Regionserver上。


    5、Region虽然是分布式存储的最小单元,但并不是存储的最小单元。Region由一个或者多个store组成,每个store又由一个memStore和0至多个storefile组成,storefile包含HFile;memstore存储在内存中,storefile存储在hdfs上。


3. 实现

正如HDFS和MapReduce由客户端、从属机和协调主控机组成,Hbase也采用相同的模型,他用一个Master节点协调管理一个或多个Regionserver从属机。Hbase主控机负责启动和全新的安装、把区域分配给注册的Regionserver,恢复Regionserver的故障。Master的负载很轻。Regionserver负责零个或多个区域的管理以及响应客户端的去写请求。Regionserver还负责区域的划分,并通知Hbase Master有了新的子区域,这样主控机就可以把父区域设为离线,并用子区域替换父区域。


Hbase依赖于zookeeper。默认情况下,它管理一个zookeeper实例,作为集群的权威。Hbase负责根目录表的位置,当前集群主控机地址类似重要信息的管理。如果区域的分配过程中有服务器崩溃,就通过zookeeper来协调分配。在zookeeper上管理分配事物的状态有助于恢复时可以从崩溃服务器遗留的状态开始继续分配。在启动一个客户端到Hbase集群的连接时,客户端必须至少拿到集群所传递的zookeeper整体的位置。这样,客户端才能访问zookeeper层次,了解集群的属性,如服务器的位置。

类似于在hadoop中可以通过conf/slaves文件查看datanode和tasktracker,Regionserver从属机节点列在Hbase的conf/regionserver文件中。启动和结束服务的脚本也使用hadoop一样基于ssh的远程命令机制来运行。集群的站点配置在HBase的conf/hbase-site.xml和conf/hbase-env.sh文件中。它们的格式和hadoop项目中对应的格式相同。

HBase通过hadoop文件系统API来持久化存储数据。有多种文件系统接口的实现。如:本地接口、kfs文件系统、HDFS等。

3.1. 运行中的HBase

HBase内部保留名称-root-和.meta.的特殊目录表(catalog table)。它们维护着当前集群上所有区域的列表、状态和位置。-root-表包含.meta.表的区域列表。.meta.表包含所有空间区域的列表。表中的项使用区域名称作为键。区域名有所属的表名、区域的起始行、区域的创建时间以及对整体进行的MD5组成。

如前所述,表的键是排序的。因此,要查找一个特定行所在的区域只要在目录表中找到一个键大于或等于给行键即可。区域变化时—即分裂、禁用/启用、删除、为负载均衡新部署区域或由于regionserver崩溃而重新部署区域时—目录表会进行相应的更新。这样,集群上所有区域的状态信息就能保持是最新的。

连接到zookeeper集群上的客户端首先查找-ROOT-的位置。然后客户端通过-root-获取所请求行所在范围所属.meta.区域的位置。客户端接着查找.meta.区域来获取用户空间区域所在节点以及其位置。接着,客户端就可以直接和管理那个区域的Regionserver进行交互。

每个行操作可能要访问三次远程节点。为了节省这些代价,客户端会缓存他们遍历-root-时所获取的信息和.meta.位置以及空间区域的开始行和结束行。这样,他们以后不需要访问.meta.表也能得知区域存放的位置。客户端在碰到错误之前会一直使用所缓存的想。当发生错误时—即区域被移动了—客户端会再次查看.meta.获取区域的新位置。如果.meta.区域也被移动了,客户端会再去查看-root-。

到达Regionserver的写操作首先追加到“提交日志”,然后在加入内存中的memstore。如果memstore满,它的内容会被“刷入”文件系统。

提交日志存放在HDFS中,因此即使一个Regionserver崩溃,提交日志仍然可用。如果发现一个Regionserver不能访问—通常因为服务器的znode在zookeeper中过期了—主控机会根据区域对死掉的Regionserver的提交日志进行分割。在重新分配后,打开并使用死掉的regionserver上的区域之前,这些区域会找到刚分割得到的文件,其中包括还没有持久化存储的更新。这些更新会被“重做”使区域恢复到服务器失败前夕的状态。

在读的时候首先查看区域的memstore。如果在memstore中找到了需要的版本,直接返回即可。否则,需要按照次序从新到旧检查“刷新文件”,直到找到满足查询的版本,或所有刷新文件都处理完为止。

有一个后台进程负责在刷新文件个数到达一个阀值是压缩它们。它把多个文件重新写入一个文件,因为读操作检查的文件越少,他的执行效率越高。在压缩时,超出模式所设最大值的版本以及被删除或过期的单元格会被清理掉。在regionserver上,另外有一个独立的进程监控者刷新文件的大小,一旦文件大小超出设定的最大值,便会对区域进行分割。

3.2.  HBase体系结构

HBase的服务器体系结构遵循了简单的主从服务器架构,它由ReginServer群和Master服务器构成。HBase Master服务器负责管理所有的ReginServer服务器,而HBase中所有的服务器都是通过zookeeper来进行协调,并处理HBase服务器运行期间可能遇到的错误。

3.3.  HBase系统架构图

 

组成部件说明:

3.3.1.Client

   使用HBase RPC机制与HMaster和HRegionServer进行通讯,并维护cache来加速对HBase的访问,比如region的位置信息。

  • Client与HMaster进行通讯进行管理类操作
  • Client与HRegionServer进行数据读写类操作

3.3.2.Master

HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master在运行,主要负责Table和Region的管理工作:

    1 、管理用户对表的增删改查操作
    2 、管理HRegionServer的负载均衡,调整Region分布
    3、 Region Split后,负责新Region的分布
    4、 在HRegionServer停机后,负责失效HRegionServer上Region迁移

3.3.3.Region Server

HRegionServer管理一些列HRegion对象;

每个HRegion对应Table中一个Region,HRegion由多个HStore组成;

每个HStore对应Table中一个Column Family的存储;

Column Family就是一个集中的存储单元,故将具有相同IO特性的Column放在一个Column Family会更高效

3.3.4.Zookeeper

Zookeeper Quorum存储-ROOT-表地址、HMaster地址;HRegionServer把自己以Ephedral方式注册到Zookeeper中,HMaster随时感知各个HRegionServer的健康状况。Zookeeper避免HMaster单点问题。

  • 通过选举,保证任何时候,集群中只有一个Master,Master与RegionServer启动会向zookeeper注册;
  • 贮存所有Region的寻址入口;
  • 实时监控Region Server的上线和下线信息,并实时通知给Master;
  • 存储Hbase的schema和Table元数据;
  • 默认情况下,Hbase管理zookeeper实例,比如:启动或者停止zookeeper;
  • Zookeeper的引入使得Master不再是单点故障;
    

3.3.5.HLog

    1、引入HLog原因:在分布式系统环境中,无法避免系统出错或者宕机,一旦HRegionServer以外退出,MemStore中的内存数据就会丢失,引入HLog就是防止这种情况。

    2、工作机制:每个HRegionServer中都会有一个HLog对象,HLog是一个实现Write Ahead Log的类,每次用户操作写入Memstore的同时,也会写一份数据到HLog文件,HLog文件定期会滚动出新,并删除旧的文件(已持久化到StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知,HMaster首先处理遗留的HLog文件,将不同region的log数据拆分,分别放到相应region目录下,然后再将失效的region重新分配,领取到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

    3、HLog File:

 

HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。

HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue。

3.3.6.HFile

  

HFile文件不定长,长度固定的块只有两个:Trailer和FileInfo。Trailer中指针指向其他数据块的起始点;FileInfo中记录了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。

Data Index和Meta Index块记录了每个Data块和Meta块的起始点。

Data Block是HBase I/O的基本单元,为了提高效率,HRegionServer中有基于LRU的Block Cache机制

每个Data块的大小可以在创建一个Table的时候通过参数指定,大号的Block有利于顺序Scan,小号Block利于随机查询;每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成, Magic内容就是一些随机数字,目的是防止数据损坏

HFile里面的每个KeyValue对就是一个简单的byte数组。这个byte数组里面包含了很多项,并且有固定的结构。

总结:HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,格式主要有两种--1 HFile HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile;2 HLog File,HBase中WAL(Write Ahead Log) 的存储格式,物理上是Hadoop的Sequence File;

3.3.7.Table与HFILE的关系

  在上图中所示table表中存在两个CF,分别是info和pwd。它们在hbase中的物理存储方式如下:

    从上图可以看到row1和row5的数据分布在两个cf中,并且每个cf对应一个Hfile。并且逻辑上每一行的一个单元格数据,对应于HFile中的一行,然后用户按照row-key查询数据的时候,Hbase会遍历两个hfile,通过相同的row-key标识,将相关的单元格组织成行返回,这样便有了逻辑上的行数据。

3.4.  HBase数据的容错和回复

3.4.1. Write-Ahead-log(WAL)

 

该机制用于数据的错误和恢复:

每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户写操作写入MemStore的同时,也会写一个数据到HLog文件中,HLog文件定期会滚动出新的,并删除旧的文件(已持久化到storefile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper通知到,HMaster首先会处理遗留的HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应的Region的目录下,然后在将失效的Region重新分配,领取到这些Region的HRegionServer在load Region的过程中,会发现有历史的Hlog需要处理,因此会Replay HLog中的数据到Memstore中,然后flush到StoreFiles,完成数据恢复;

3.4.2.HBase容错性

    1、Master容错:Zookeeper重新选择一个新的Master;

  • 无Master过程中,数据读取仍照常进行;
  • 无Master过程中,Region切分、负载均衡等无法进行;

    2、 RegionServer容错:定时向zookeeper汇报心跳,如果一旦时间内未出现心跳,Master将该regionserver上的Region重新分配到其他RegionServer上,失效服务器上“预写”日志由主服务器进行分割并派送给新的RegionServer。

    3、Zookeeper容错:zookeeper是一个可靠的服务,一般配置3或5个zookeeper实例;

3.5. Region定位流程

 

3.5.1.需找RegionServer

    Zookeeperà-ROOT-(单Region)à.META.-->用户表

3.5.2.-ROOT-

  表包含.META.表所在的额Region列表,该表只会有一个Region;

    Zookeeper中记录了-ROOT-表的location;

3.5.3..META.

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

4.   HBase操作

安装完成Hbase以后,进入HBase shell之后,输入help,可以获取HBase Shell所支持的命令,如下图:


5.   HBase和RDBMS的比较

HBase和其他面向列的数据库查查被拿来和更流行的传统关系数据库进行比较。虽然他们在实现和设计上的出发点有着较大的区别,但他们都力图解决相同的问题。所以,虽然他们有很多不同点,但我们仍然能够对他们进行公证的比较。

HBase是一个分布式的、面向列的数据存储系统。他通过在HDFS上提供随机读写来解决hadoop不能处理的问题。HBase自底层设计开始即聚焦于各个可伸缩性问题:表可以很“高”;表可以很“宽”;水平分区并在上千个普通商业用机节点上自动复制。表的模式是物理存储的直接反应,是系统有可能提供高效的数据结构的序列化、存储和检索。但是,应用程序的开发者必须承担重任,选择以正确的方式使用这种存储和检索方式。

严格来说,RDBMS是一个遵循“codd的12条规则”的数据库。标准的RDBMS的模式固定、面向行的数据库且具有ACID性质和复杂的SQL查询处理引擎。RDBMS强调事物的“强一致性”、操作完整性、数据抽象和物理存储层相对独立,以及基于SQL语言的复杂查询支持。在RDBMS中,可以非常容易的建立“二级索引”,执行复杂的内连接和外连接,执行计数、求和、排序、分组等操作,或对表、行和列中的数据进行分页存放。

对于大多数中小规模的应用,mysql和PostgreSQL之类的开源RdbMS解决方案所提供的易用性、灵活性、产品成熟度以及强大、完整的功能特性几乎是无可替代的。但是,如果要在数据规模和并发读写这两方面中的任何一个或全部上进行大规模扩展,就会很快发现RDBMS的易用性会让你损失不少性能,而如果要进行分布式处理,更是非常困难。RDBMS的扩展通常要求打破Coddle的规则,如放松ACID的限制,是DBA的管理变得复杂,同事放弃大多数关系型数据库引以为荣的易用性。

5.1.  RDBMS成功的服务

这里将简单介绍一个典型的RDBMS如果进行扩展。下面给出一个成功服务从小到大的生长过程。

服务首次提供公开访问:服务从本地工作站迁移到已定义模式的共享、远程mysql实例;

服务越来越受欢饮,数据库收到太多的读请求:用memcached来缓存常用查询结果,这是读不再是一个严格意义上的ACID,缓存数据必须在某个时间到期;

对服务的使用继续增多,数据库收到太多的写请求:通过购买一个16核、128GRAM、配备一组15KRPM硬盘驱动器的增强型服务器来垂直升级mysql,非常昂贵。

新的特性增加了查询的复杂度,包含很多连接操作:对数据进行反范式化以减少连接次数;

服务被广泛使用,所有的服务都会变得非常慢:停止使用任何服务器端计算;

有些查询仍然太慢:定期对复杂的查询进行“预物化”,尝试在大多数情况下停使用连接;

读性能尚可,但写仍然越来越慢:放弃使用二级索引和触发器。

迄今为止,如果解决以上扩展问题并没有一个清晰的解决办法。无论怎样,都需要开始航向进行扩展。可以尝试在大表上进行某种分区或查看一些提供多主控机的商业解决方案。

无数应用、行业以及网站都成功实现了RDBMS的可伸缩性、容错和分布式数据系统。他们都使用了前面提到的很多策略。但最终,你所拥有的已经不再是一个真正的RDBMS。由于妥协和复杂性问题,系统放弃了很多易用性特征。任何种类丛书副本或外部缓存都会对反规范化的数据引入弱一致性。连接和二级索引的低效意味着绝大多数查询成为主键查找。而对于多写入机制的设置和可能意味着根本没有实际的连接,而分布式事物会成为一个噩梦。这是,要管理一个单独用于缓存的集群,网络拓扑会变得异常复杂。即使有一个做了那么多妥协的系统,你仍然忍不住会担心主控机崩溃,或在几个月后,数据或负载可能会增长到当前的10倍。

5.2.  Hbase

没有真正的索引:行是顺序存储的,每行中的列也是,所以不存在索引膨胀的问题,而且插入性能和表的大小无关。

自动分区:在表增长的时候,表会自动分裂成区域,并分布到可以用的节点上;

线性扩展和对于新节点的自动处理:增加一个节点,把它指向现有集群,并运行Regionserver。区域自动重新进行平衡,负载会均衡分布。

普通商用硬件支持:集群可以用1000到5000美金的打个节点搭建,而不需要使用打个的花5万美金的节点。RDBMS需要大量I/O,因此需要更昂贵的硬件。

容错:大量节点以为着每个节点的重要性并不突出,不用担心单个节点失效。

批处理:MapReduce集成功能使我们可以用全并行的分布式作业根据“数据的位置”来处理他们。

猜你喜欢

转载自student-lp.iteye.com/blog/2158002