Architecting HBase Applications学习(一)——HBase简介和HBase原理

1.什么是HBase

根据HBase官方网站的描述:”Hbase 是一个分布式的,可扩展的,大数据存储数据库”。这个概念具有一定的误导性,更准确的说,HBase并不是一个数据库,它是一个基于Java的,开源的,NOSql,非关系型,基于列的,分布式存储;它以Google的Big Table论文为原型,基于HDFS构建完成。

1.1基于列Vs基于行

在基于列的数据库系统中,系统将表数据稀疏地存储起来而不是想基于行的系统那样一次存储一行。

1.2HBase不能做哪些事情

  • HBase不是关系型数据库的替代者
  • HBase不是事务型数据库
  • HBase不提供基于SQL的API

2.HBase原理

2.1表格式

像关系型数据库一样,HBase同样将数据存储在表中,也有rowkey和列名的概念。但是于传统数据库不同的是:HBase引入了列族的概念,尽管这些概念的定义是相同的,表和列在HBase中的工作方式于关系型数据库大不相同。

在HBase中,有两种类型的表:系统表和用户表。系统表是HBase自身使用的,用来跟踪表的元信息,包括访问控制列表(ACLs),表/分区/命名空间的元信息等等。用户表是用户自己创建的表,如果在创建时不指定命名空间,它们会属于默认命名空间。

2.1.1表布局

一张HBase表有一个或多个列族组成,每个列族里面可以有多个列(columns qualifiers, CQ),与传统关系型数据库不同的是,HBase表的值是稀疏存储的,有些列可能没有值,在这种情形下,HBase不会提前王这一列里面插入一个空值。

只有有值得列才会存储到文件系统中。列族需要在建表的时候指定,但是,列族里面有哪些列是在后续插入数据的时候动态扩展的。

为了让访问数据更快速,行键和列都是按照字母顺序存在表和内存中的。

2.1.2表存储

关于表存储有两个问题需要讨论:第一个问题是HBase怎样把一个单个值存储到表中,第二个问题是HBase怎样把这些值组织在一起形成一张表。
从下面这张图可以看出来,从上到下,一张HBase表由一到多个Regions组成,每个Region由一到多个列族组成,每个列族里面包含唯一的一个Store,每个Store又包含一个唯一的MemStore和一到多个HFiles,而HFile由blocks组成,block由cells组成。

在一个RegionServer上,MemSore的数量等于Region的数量乘以列族的数量,它们共同分享该RegionServer的内存。

HBase存储分层
图1:HBase存储分层

下面详细介绍HBase表存储的每一层:

2.1.2.1Regions

所有的行和相关的列组合到一起就形成一张表。但是为了保证可扩展性和快速随机访问,HBase不得不把这些数据分布到多个server上。为了达到这个目标,hBase表被划分成了多个Regions,每个Region存储一个特定范围的数据。这些Regions被分配到各个RegionServer上来为每个region的内容服务。当新的Regions被创建的时候,经过一段配置好的时间后,HBase负载均衡器就会把它们迁移到不同的RegionServer上去,保证最终他们均衡地分布在整个集群中。围绕着Regions,HBase提供了预分区这类很好的实践。

每个Region会有一个起始key和一个结束key来定义Region的边界。所有这些信息都会被存储到region上的一个文件里面,同时和会存储到系统表hbase:meta(在0.96版本前存储到.META.表)中,这样HBase就可以追踪所有的Region了。当Region太大的时候,可以将Region切分(split),如果有需要,也可以将多个Region合并到一起。

2.1.2.2Column family

对于同一个Region来说,不同列族的数据会被存储到不同的文件中,可以针对它们做不同的配置。具有同样访问模式的数据和同样格式的数据应该被划分到同一个列族中。关于访问模式的例子:应该将频繁读取但很少写入和经常写入很少读取这两类数据放到不同的列族中;关于数据格式的例子:应该将文本信息和图片信息分别放到两个不同的列族中,一个压缩的(用来存储文本),一个不经过压缩(用来存储图片)。
对于一个给定的RegionServer,写缓存区域是被所有列族共享的,滥用列族会给memstore带来很大的压力,这样做会生成很多小文件,反过来会产生很多的压缩操作,最终会影响系统的性能。关于一个表应该有多少个列族没有技术上的限制,然而,生产经验告诉我们,一个表最好只有一个列族。如果你设计的HBase表有三个或以上的列族,那么,你就需要好好考虑一下是不是真的需要这么多列族了。
如果你的两个列族之间没有一致性的约束,数据也不会同时到达这个表中,这时,你就应该考虑将它们分开变成两张表,每张表拥有一个列族。当我们需要决定Region的大小的时候,该策略还是很有用的。

2.1.2.3Stores

一个列族里面只有一个Store。一个Store里面包括一个memstore和0到多个store files(成为HFiles),Hfile是用来存储所有写入到表中的数据的区域,同时当需要从表中读取数据的时候也需要经过Hfile.

2.1.2.4HFiles

HFiles是memstore占满需要flush到磁盘的时候产生的。HFiles最终会被压缩到一起形成一个大文件。它们是HBase的文件格式,用来存储表数据。HFiles由不同类型的blocks组成(例如:index blocks和data blocks)。Hfiles存储在hdfs上,因此它们也受益于hdfs的一致性和副本机制。

2.1.2.5Blocks

HFiles是由Blocks组成的。要注意的是,不要将HFiles的Blocks和hdfs的Blocks混淆,一个hdfs的Blocks可能包含多个Hfile的Blocks。HFile bolcks通常都在8kb到1Mb之间,默认值是64KB。但是,如果对给定的表进行压缩,HBase仍然会生成64KB的block,然后再将它们压缩在一起。磁盘上压缩后的block大小会基于数据和压缩格式进行变化。大的blocks会产生比较少的索引值,有利于对表数据的连续访问。而小的block会产生更多的索引值,有利于对表数据的随机访问。
对于block的大小,建议采用默认值。
在HFile里面可能会遇到以下几种block:

  • Data blocks

    Data block中存储的数据要么经过压缩了,要么未经过压缩,不能同时存储两种格式。Data block中包括delete标记和puts标记。

  • Index blocks

    当查找某一个特定行的数据时,index blocks被用来快速跳到HFile的特定位置上

  • Bloom filter blocks

    这类block用来存储跟bloom filter index相关的信息。当需要查找某一个特定key的时候,Bloom filter blocks被用来跳过解析文件。

  • Trailer blocks

    这类block被用来记录文件的偏移量。它也包含了HFiles的版本信息。

2.1.2.6Cells

HBase是一个基于列的数据库。这就意味着每一列数据都会被单独存储。由于这些值可能在不同的时间被插入到HBase中,因此,它们可能存在于Hdfs的不同文件中。

在HBase中,每一行都以一种特定的格式来存储。下图展示了一个Hbase cell的格式:
这里写图片描述
keytype字段代表了可能的HBase操作:Put/Delete/DeleteFamilyVersoin/DeleteColumn/DeleteFamily

2.2内部表操作

HBase的可扩展性基于它将数据重组进一个大文件和将一个表数据分散到多个server的能力。为了达到这个目标,HBase有三个主要的机制:compactions/splits/balancing.这三个机制对用户都是透明的。然而,在一个不好的设计或者不正确的使用下,它们可能会影响到服务的性能。因此,有必要了解一下这三个机制都是怎么工作的。

2.2.1comopaction

Hbase将所有收到的操作请求记录到memstore内存区域.当内存buffer被占满的时候,就会溢出到磁盘。这会在hdfs上产生很多小文件,随着时间的推移,再加上一些特定的条件,HBase会选举出一些需要被压缩的文件将它们压缩成一个大文件。这个操作对集群有很多好处:
首先,新的HFile会被写入到本地的RegionServer,这样就保证数据存储在hdfs本地。将数据写到本地就能让RegionServer在本地查找文件而不用跨网络。
第二,当用户请求数据的时候,这样做会降低需要查找的文件数。
第三,压缩会让HBase对原有的文件做一些清理工作:如果TTL让一些cell里面的数据失效,它们就不会被写入到新的目标文件里面去。

有两种类型的压缩:

2.2.1.1Minor Compaction

Minor Compaction是指HBase只选出几个HFiles做压缩,而不是对所有的HFiles进行压缩。默认的可配置的触发HBase压缩操作的门槛是在当前region中有三个或者更多的HFile。如果压缩操作被触发,HBase会根据压缩策略从当前文件中选择几个文件。如果现有的所有文件都被选中,那么本次压缩就被提升未Major Compaction。
Minor Compactions可以对数据做一些清理工作,但不是所有数据都能被清理。当你删除某一个cell的数据的时候,HBase会存储一个标记,表示任何和该cell有同样key但是早于这个时间戳的该cell的数据都应该被删除。当HBase进行压缩操作并发现一个删除标记时,它就需要确保所有对应于这个cell的老版本数据都应该被删除。如果删除标记存在于一个没有被选举到做压缩的文件中,可能还存在应该被删除的cells,所以删除标记仍然存在,直到进行主压缩才会真正被删除。定义在列族层面的基于TTL的过期数据将会被删除,因为它们不依赖于其他未被选举到的文件的内容,除非该表配置了必须保留最小数量的版本数。

2.2.1.2Major Compaction

Major Compaction是将所有的HFiles都选出来做压缩。Major compaction和MinorCompaction的区别在于当删除标记被应用到所有相关的cells并且同一个cell的所有多余的版本记录都被删除之后,删除标记也会被清除掉。Major Compactions可以被手动触发,同时可以选择进行Major Compaction的级别,可以在某一个特定Region的列族级别做,或者在Region级别做,或者在表级别做。HBase还配置了每周进行主压缩。

强烈建议关闭掉所有的自动主压缩,改为定时任务手工执行;同时,建议不要同时对所有的表进行主压缩。最好将所有表的主压缩任务平均分配到一周当中。如果你的集群中真的有很多表和很多分区,强烈建议你自己实现一个方法,检查每个分区HFiles的数量和最旧版本的时间,如果文件数量超出了你的预期或者最近版本比配置的周期要长(一开始最好配置成一个星期),这时候就可以触发一次Region级别的major compaction。这样做可以保证region的数据本地性,降低你集群的IO。

2.2.2Splits (Auto-Sharding)

Splits是compactions操作的相反操作。当HBase把多个文件压缩到一起的时候,如果在压缩过程中删除的内容不多的话,就会产生一个很大的文件。输入文件越大,解析和压缩它们就会话费越多的时间。因此,HBase会把文件控制在一个可控的最大大小之内。在0.94以前的版本,HFiles的最大大小是1G,后来,这个值就变成了10G。当某一个Region的某一个列族达到这么大的时候,为了提高负载均衡,HBase会对这个Region触发一次split操作,让它变成两个region。由于region的边界会应用到给定region的所有列族上,所有的列族都会以同样的方式进行split,即使有些列族远远小于配置的最大大小。当一个region被split之后,它就会变成两个小一点的regions,第一个region的start key就是原来region的start key,第二个region的end key就是原来region的end key,第一个region的end key和第二个region的start key是由HBase来决定的,HBase会选择一个最佳的中间点。
关于Splits有几点需要牢记。首先,HBase永远不会对同一个row的两个column做split操作。所有的列都会在同一个region中。因此,如果你有很多列,或者它们非常大,一个row可能就远远大于了配置的最大容量,HBase也无法对这种情况进行split。你应该避免出现这种整个region就为一个row服务的情况。
还应该记住HBase会split所有的列族。即使你的第一个列族达到了10G的限额,但是另外一个列族只有几行或者几kb,它们都会被split。这样做就会导致第二个列族在每个region中都只有很少的files。这不是我们想要的结果,在设计schema的时候应该尽量避免出现这种情况。如果你的HBase出现了这种情况并且在你的两个列族之间没有很强的一致性要求,就考虑把它们拆分成两张表吧。
最后,别忘了,splits操作从来都不是免费的午餐。当一个region经过split之后平衡的同时,它也失去了数据本地行这个特性,直到下一次压缩操作。这会影响系统的性能,因为客户端会访问包含这个region的regionServer,但是,此时必须通过网络请求数据来满足这一次请求。同时,Region的数量越多,给master造成的压力就越大。在HBase中,splits操作是好的和正常的,但是你必须紧紧地盯着它们。
下图展示了一个有两个列族的region经过split操作后的效果,可以看到其中一个列族明显大于另外一个。
这里写图片描述

2.2.3balancing

Regions会进行split,servers有时候会挂掉,还可能有新的servers加入到集中当中,因此,有时候负载在各个regionServer上会不均衡。为了帮助维护集群间的均衡状态,每五分钟(默认配置),Hbase Master会执行一次负载均衡,确保所有的RegionServer管理和服务的Regions数量大致相同。

HBase有几种不同的负载均衡算法。直到0.94版本,HBase使用的是SimpleLoadBalancer,但是从0.96开始,HBase使用StochasticLoadBalancer算法。尽管强烈建议维持默认配置的balnacer,开发人员还是可以开发自己的balancer并让HBase使用它。

需要注意的是,当一个region被balancer从一个server迁移到另一个的时候,它会在几毫秒内不可访问,而且直到下一次主压缩发生之前,这些数据会失去数据本地行特性。
下图展示了一次负载均衡操作过程及结果:
这里写图片描述

2.3依赖

HBase需要保证在含有HBase的节点上有hdfs,但是并不要求所有hdfs节点上都有HBase,尽管如此,为了保证数据平衡,还是强烈建议在所有Hdfs节点上都安装HBase。
HBase也依赖于zk来监控服务的健康状况,提供高可用特性,跟踪复制过程,当前活跃的HMaster,table列表等等信息

2.4HBase角色

HBase由两个主要的角色组成:master(有时候被称为HBase Master,Hmaster,HM)和RegionServers(RS).
下图展示了不同的服务如何分配到不同的server上,最新版本的HDFS允许超过两个NameNodes。它允许所有的Master服务拥有正在运行的服务的一致性列表(Hmaster/NameNode/ZooKeeper)。只运行两个NameNode也是可以的。
这里写图片描述

2.4.1Master Server

HBase Master是集群的领导者,负有以下责任:

  • 分配region
  • 负载均衡
  • RegionServer恢复
  • Region split完成监控
  • 追踪server状态(active/dead)

为了高可用性,最好在一个集群里面安装多个Master。然而,同一时间只能由一个master处于active状态。

和RegionServer不同的是,HMaster不会承担很多的工作负载,因此可以安装在一些有较少内存和CPU内核的机器上,也由于HMaster是整个集群的核心,因此必须保证高可靠性。

如果没有RegionServer失败或者没有region进行split,即使没有HMaster,HBase集群也能够存活,但是应该避免这种情况。

2.4.2RegionServer

RegionServer是保存HBase数据并为HBase regions提供服务的组件。当需要从特定的region读取或者写入数据的时候,来自Java客户端的请求会直接进入到RegionServer。这是为了确保HBase Master和ZooKeeper不会是系统瓶颈。

RegionServer会决定和处理splits和compactoins操作但是需要想master汇报。
强烈建议一台机器上只安装一个RegionServer,实际搭建集群的时候都是这么做的。

Tips:
当客户端第一次尝试从HBase读取数据的时候,它会先到ZooKeeper中找到Master server,定位到hbase:meta region,从这里它能找到它需要查找的region和RegionServer在哪里。后续从同一个客户端到同一个region的请求,客户端都会直接和相关的RegionServer打交道,从而省去了中间的调用过程。这就是为什么对多个操作要尽量复用同一个客户端。

参考书目

Architecting HBase Applications学习系列文章参考自《Architecting HBase Applications-A GUIDE FOR SUCCESSFUL DEVELOPMENT AND DESIGN》,作者:Jean-Marc Spaggiari & Kevin O’Dell,文章中大部分内容来源于该书,在此,对本书作者的辛勤付出表示由衷的感谢,本书给HBase用户进阶提供了很好的帮助,如果对原书内容感兴趣,建议阅读原版图书。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值