本文会对HBase的基本原理进行分析,通过本文你能够理解到:

  • CAP实践
  • NoSQL呈现的起因
  • HBase的特点及应用场景
  • HBase的数据模型和基本原理
  • 客户端API的根本应用
  • 易混同知识点面试总结

舒适提醒:本文内容较长,如果感觉有用,倡议珍藏。另外记得分享、点赞、在看,素质三连哦!

从BigTable说起

HBase是在谷歌BigTable的根底之上进行开源实现的,是一个高牢靠、高性能、面向列、可伸缩的分布式数据库,能够用来存储非结构化和半结构化的稠密数据。HBase反对超大规模数据存储,能够通过程度扩大的形式解决超过10亿行数据和百万列元素组成的数据表。

BigTable是一个分布式存储系统,利用谷歌提出的MapReduce分布式并行计算模型来解决海量数据,应用谷歌分布式文件系统GFS作为底层的数据存储,并采纳Chubby提供协同服务治理,具备宽泛的应用型、可扩展性、高可用性及高性能性等特点。对于BigTable与HBase的比照,见下表:

依赖BigTbaleHBase
数据存储GFSHDFS
数据处理MapReduceHadoop的MapReduce
协同服务ChubbyZookeeper

CAP实践

2000年,Berkerly大学有位Eric Brewer传授提出了一个CAP实践,在2002年,麻省理工学院的Seth Gilbert(赛斯·吉尔伯特)Nancy Lynch(南希·林奇)发表了布鲁尔猜测的证实,证实了CAP实践的正确性。所谓CAP实践,是指对于一个分布式计算零碎来说,不可能同时满足以下三点:

  • 一致性(Consistency)

    等同于所有节点拜访同一份最新的数据正本。即任何一个读操作总是可能读到之前实现的写操作的后果,也就是说,在分布式环境中,不同节点拜访的数据是统一的。

  • 可用性(Availability)

    每次申请都能获取到非错的响应——然而不保障获取的数据为最新数据。即疾速获取数据,能够在确定的工夫内返回操作后果。

  • 分区容错性(Partition tolerance)

    以实际效果而言,分区相当于对通信的时限要求。零碎如果不能在时限内达成数据一致性,就意味着产生了分区的状况,必须就以后操作在C和A之间做出抉择。即指当呈现网络分区时(零碎中的一部分节点无奈与其余的节点进行通信),拆散的零碎也可能失常运行,即可靠性。

如上图所示:一个分布式的零碎不可能同时满足一致性、可用性和分区容错性,最多同时满足两个。当解决CAP的问题时,能够有一下几个抉择:

  • 满足CA,不满足P。将所有与事务相干的内容都放在同一个机器上,这样会影响零碎的可扩展性。传统的关系型数据库。如MySQL、SQL Server 、PostgresSQL等都采纳了此种设计准则。
  • 满足AP,不满足C。不满足一致性(C),即容许零碎返回不统一的数据。其实,对于WEB2.0的网站而言,更加关注的是服务是否可用,而不是一致性。比方你发了一篇博客或者写一篇微博,你的一部分敌人立马看到了这篇文章或者微博,另一部分敌人却要等一段时间之后能力刷出这篇文章或者微博。尽管有延时,然而对于一个娱乐性质的Web 2.0网站而言,这几分钟的延时并不重要,不会影响用户体验。相同,当公布一篇文章或微博时,不可能立刻公布(不满足可用性),用户对此必定不爽。所以呢,对于WEB2.0的网站而言,可用性和分区容错性的优先级要高于数据一致性,当然,并没有齐全放弃一致性,而是最终的一致性(有延时)。如Dynamo、Cassandra、CouchDB等NoSQL数据库采纳了此准则。
  • 满足CP,不满足A。强调一致性性(C)和分区容错性(P),放弃可用性性(A)。当呈现网络分区时,受影响的服务须要期待数据统一,在期待期间无奈对外提供服务。如Neo4J、HBase 、MongoDB、Redis等采纳了此种设计准则。

为什么呈现NoSQL

所谓NoSQL,即Not Only SQL的缩写,意思是不只是SQL。下面提到的CAP实践正是NoSQL的设计准则。那么,为什么会衰亡NoSQL数据库呢?因为WEB2.0以及大数据时代的到来,关系型数据库越来越不能满足需要。大数据、物联网、挪动互联网和云计算的倒退,使得非结构化的数据比例高达90%以上,关系型数据库因为模型不灵便以及扩大程度较差,在面对大数据时,暴露出了越来越多的缺点。由此NoSQL数据库应运而生,更好地满足了大数据时代及WEB2.0的需要。

面对WEB2.0以及大数据的挑战,关系型数据库在以下几个方面体现欠佳:

  • 对于海量数据的解决性能较差

    WEB2.0时代,尤其是挪动互联网的倒退,UGC(用户生成内容,User Generated Content)以及PGC(公众生成内容,Public Generated Content)占据了咱们的日常。现如今,自媒体倒退遍地开花,简直每个人都成了内容的创造者,比方博文、评论、意见、新闻音讯、视频等等,不一而足。可见,这些数据产生的速度之快,数据量之大。比方微博、公众号、抑或是淘宝,在一分钟内产生的数据可能就会十分的惊人,面对这些千万级、亿级的数据记录,关系型数据库的查问效率显然是不能承受的。

  • 无奈满足高并发需要

    WEB1.0时代,大部分是动态网页(即提供什么就看什么),从而在大规模用户拜访时,能够实现较好的响应能力。然而,在WEB2.0时代,强调的是用户的交互性(用户发明内容),所有信息都须要事实动静生成,会造成高并发的数据库拜访,可能每秒上万次的读写申请,对于很多关系型数据库而言,这显示是难以承受的。

  • 无奈满足扩展性和高可用性的需要

    在当今娱乐至死的时代,热点问题(吸引人眼球,满足好奇心理)会引来一窝蜂的流量,比方微博曝出某明星出轨,热搜榜会迅速引来少量用户围观(俗称吃瓜大众),从而产生大量的互动交换(蹭热点),这些都会造成数据库的读写负荷急剧减少,从而须要数据库可能在短时间内迅速晋升性能以应答突发需要(毕竟宕机会十分影响户体验)。然而关系型数据库通常难以程度扩大,不可能像网页服务器和应用服务器那样简略地通过减少更多的硬件和服务节点来扩大性能和负载能力。

综上,NoSQL数据库应运而生,是IT倒退的必然。

HBase的特点及应用场景

特点

  • 强一致性读写

HBase 不是 最终一致性(eventually consistent) 数据存储. 这让它很适宜高速计数聚合类工作

  • 主动分片(Automatic sharding)

HBase 表通过region散布在集群中。数据增长时,region会主动宰割并从新散布

  • RegionServer 主动故障转移
  • Hadoop/HDFS 集成

    HBase 反对本机外HDFS 作为它的分布式文件系统

  • MapReduce集成

    HBase 通过MapReduce反对大并发解决, HBase 能够同时做源(Source)和汇(Sink)

  • Java 客户端 API

    HBase 反对易于应用的 Java API 进行编程拜访

  • Thrift/REST API

反对Thrift 和 REST 的形式拜访HBase

  • Block Cache 和 布隆过滤器(Bloom Filter)

HBase反对 Block Cache 和 布隆过滤器进行查问优化,晋升查问性能

  • 运维治理

HBase提供内置的用于运维的网页和JMX 指标

应用场景

HBase并不适宜所有场景

首先,数据量方面 。确信有足够多数据,如果有上亿或十亿行数据,至多单表数据量超过千万,HBase会是一个很好的抉择。 如果只有上千或上百万行,用传统的RDBMS可能是更好的抉择。

其次,关系型数据库个性方面。确信能够不依赖所有RDBMS的额定个性 (如列数据类型、二级索引、事务、高级查询语言等) 。一个建设在RDBMS上利用,并不能通过简略的扭转JDBC驱动就能迁徙到HBase,须要一次齐全的从新设计。

再次,硬件方面。 确信你有足够硬件。比方因为HDFS 的默认正本是3,所以个别至多5个数据节点才可能施展其个性,另外 还要加上一个 NameNode节点。

最初,数据分析方面。数据分析是HBase的弱项,因为对于HBase乃至整个NoSQL生态圈来说,基本上都是不反对表关联的。如果次要需要是数据分析,比方做报表,显然HBase是不太适合的。

HBase的数据模型

根本术语

HBase是一个稠密、多维、长久化存储的映射表,采纳的row key、列族、列限定合乎工夫戳进行索引,每个cell的值都是字节数组byte[]。理解HBase须要先晓得上面的一些概念:

  • Namespace

    Namespace,即命名空间,是表的逻辑分组,相似于关系型数据库管理系统的database。HBase存在两个预约义的非凡的命名空间:hbasedefault,其中hbase属于零碎命名空间,用来存储HBase的外部的表。default属于默认的命名空间,即如果建表时不指定命名空间,则默认应用default。

  • 由行和列组成,列划分为若干个列族

  • row key是未解释的字节数组,在HBase外部,row key是按字典排序由低到高存储在表中的。每个HBase的表由若干行组成,每个行由行键(row key)标识。能够利用这一个性,将常常一起读取的行存储在一起。

  • 列族

    HBase中,列是由列族进行组织的。一个列族所有列成员是有着雷同的前缀,比方,列courses:historycourses:math都是 列族 courses的成员。冒号(:)是列族的分隔符,用来辨别前缀和列名。列族必须在表建设的时候申明,而列则能够在应用时进行申明。另外,存储在一个列族中的所有数据,通常都具备雷同的数据类型,这能够极大进步数据的压缩率。在物理上,一个的列族成员在文件系统上都是存储在一起。

  • 列族外面的数据通过列限定符来定位。列通常不须要在创立表时就去定义,也不须要在不同行之间保持一致。列没有明确的数据类型,总是被视为字节数组byte[]。

  • cell

    单元格,即通过row key、列族、列确定的具体存储的数据。单元格中存储的数据也没有明确的数据类型,总被视为字节数组byte[]。另外,每个单元格的数据是多版本的,每个版本会对应一个工夫戳。

  • 工夫戳

    因为HBase的表数据是具备版本的,这些版本是通过工夫戳进行标识的。每次对一个单元格进行批改或删除时,HBase会主动为其生成并存储一个工夫戳。一个单元格的不同版本是依据工夫戳降序的程序进行存储的,即优先读取最新的数据。

    对于HBase的数据模型,详见下图:

概念模型

在HBase概念模型中,一个表能够被看做是一个稠密的、多维的映射关系,如下图所示:

如上表所示:

该表蕴含两行数据,别离为com.cnn.wwwcom.example.www;

三个列族,别离为:contents, anchorpeople

对于第一行数据(对应的row key为com.cnn.www),列族anchor蕴含两列:anchor:cssnsi.comanchor:my.look.ca;列族contents蕴含一列:contents:html;

对于第一行数据(对应的row key为com.cnn.www),蕴含5个版本的数据

对于第二行数据(对应的row key为com.example.www),蕴含1个版本的数据

上表中能够通过一个四维坐标定位一个单元格数据:[row key,列族,列,工夫戳],比方[com.cnn.www,contents,contents:html,t6]

物理模型

从概念模型上看,HBase的表是稠密的。在物理存储的时候,是依照列族进行存储的。一个列限定符(column_family:column_qualifier)能够被随时增加到曾经存在的列族上。

从物理模型上看,概念模型中存在的空单元格是不会被存储的。比方要拜访contents:html,工夫戳为t8,则不会返回值。值得注意的是,如果拜访数据时没有指定工夫戳,则默认拜访最新版本的数据,因为数据是依照版本工夫戳降序排列的。

如上表:如果拜访行com.cnn.www,列contents:html,在没有指定工夫戳的状况下,则返回t6对应的数据;同理如果拜访anchor:cnnsi.com,则返回t9对应的数据。

HBase的原理及运行机制

整体架构

通过下面的形容,应该对HBase有了肯定的理解。当初咱们在来看一下HBase的宏观架构,如下图:

咱们先从宏观的角度看一下HBase的整体架构。从HBase的部署架构上来说,HBase有两种服务器:Master服务器RegionServer服务器。个别一个HBase集群有一个Master服务器和几个RegionServer服务器。

Master服务器负责保护表构造信息,理论的数据都存储在RegionServer服务器上。在HBase的集群中,客户端获取数据由客户端直连RegionServer的,所以你会发现Master挂掉之后你仍然能够查问数据,然而不能创立新的表了。

  • Master

咱们都晓得,在Hadoop采纳的是master-slave架构,即namenode节点为主节点,datanode节点为从节点。namenode节点对于hadoop集群而言至关重要,如果namenode节点挂了,那么整个集群也就瘫痪了。

然而,在HBase集群中,Master服务的作用并没有那么的重要。尽管是Master节点,其实并不是一个leader的角色。Master服务更像是一个‘打杂’的,相似于一个辅助者的角色。因为当咱们连贯HBase集群时,客户端会间接从Zookeeper中获取RegionServer的地址,而后从RegionServer中获取想要的数据,不须要通过Master节点。除此之外,当咱们向HBase表中插入数据删除数据等操作时,也都是间接跟RegionServer交互的,不须要Master服务参加。

那么,Master服务有什么作用呢?Master只负责各种协调工作,比方建表删表挪动Region合并等操作。这些操作有一个共性的问题:就是须要跨RegionServer。所以,HBase就将这些工作调配给了Master服务。这种构造的益处是大大降低了集群对Master的依赖。而Master节点个别只有一个到两个,一旦宕机,如果集群对Master的依赖度很大,那么就会产生单点故障问题。在HBase中即便Master宕机了,集群仍然能够失常地运行,仍然能够存储和删除数据。

  • RegionServer

RegionServer就是寄存Region的容器,直观上说就是服务器上的一个服务。RegionServer是真正存储数据的节点,最终存储在分布式文件系统HDFS。当客户端从ZooKeeper获取RegionServer的地址后,它会间接从RegionServer获取数据。对于HBase集群而言,其重要性要比Master服务大。

  • Zookeeper

RegionServer十分依赖ZooKeeper服务,ZooKeeper在HBase中表演的角色相似一个管家。ZooKeeper治理了HBase所有RegionServer的信息,包含具体的数据段寄存在哪个RegionServer上。客户端每次与HBase连贯,其实都是先与ZooKeeper通信,查问出哪个RegionServer须要连贯,而后再连贯RegionServer。

咱们能够通过zkCli拜访hbase节点的数据,通过上面命名能够获取hbase:meta表的信息:

[zk: localhost:2181(CONNECTED) 17] get /hbase/meta-region-server

简略总结Zookeeper在HBase集群中的作用如下:对于服务端,是实现集群协调与管制的重要依赖。对于客户端,是查问与操作数据必不可少的一部分

须要留神的是:当Master服务挂掉时,仍然能够进行能读能写操作;然而把ZooKeeper一旦挂掉,就不能读取数据了,因为读取数据所须要的元数据表hbase:meata的地位存储在ZooKeeper上。可见zookeeper对于HBase而言是至关重要的。

  • Region

Region就是一段数据的汇合。HBase中的表个别领有一个到多个Region。Region不能跨服务器,一个RegionServer上有一个或者多个Region。当开始创立表时,数据量小的时候,一个Region足以存储所有数据,等到数据量逐步减少,会拆分为多个region;当HBase在进行负载平衡的时候,也有可能会从一台RegionServer上把Region挪动到另一台RegionServer上。Region是存储在HDFS的,它的所有数据存取操作都是调用了HDFS的客户端接口来实现的。一个Region就相当于关系型数据库中分区表的一个分区。

宏观架构

上一大节对HBase的整体架构进行了阐明,接下来再看一下外部细节,如下图所示:展现了一台RegionServer的外部架构。

如上图所示:一个RegionServer能够存储多个region,Region相当于一个数据分片。每一个Region都有起
始rowkey和完结rowkey,代表了它所存储的row范畴。在一个region外部,包含多个store,其中一个store对应一个列族,每个store的外部又蕴含一个MemStore,次要负责数据排序,等超过肯定阈值之后将MemStore的数据刷到HFile文件,HFile文件时最终存储数据的中央。

值得注意的是:一台RegionServer共用一个WAL(Write-Ahead Log)预写日志,如果开启了WAL,那么当写数据时会先写进WAL,能够起到容错作用。WAL是一个保险机制,数据在写到Memstore之前,先被写到WAL了。这样当故障复原的时候能够从WAL中复原数据。另外,每个Store都有一个MemStore,用于数据排序。一台RegionServer也只有一个BlockCache,用于读数据是进行缓存。

  • WAL预写日志

Write Ahead Log (WAL)会记录HBase中的所有数据,WAL起到容错复原的作用,并不是必须的选项。在HDFS上,WAL的默认门路是/hbase/WALs/,用户能够通过hbase.wal.dir进行配置。

WAL默认是开启的,如果敞开,能够应用上面的命令Mutation.setDurability(Durability.SKIP_WAL)。WAL反对异步和同步的写入形式,异步形式通过调用上面的办法Mutation.setDurability(Durability.ASYNC_WAL)。同步形式通过调用上面的办法:Mutation.setDurability(Durability.SYNC_WAL),其中同步形式是默认的形式。

对于异步WAL,当有Put、Delete、Append操作时,并不会立刻触发同步数据。而是要等到肯定的工夫距离,该工夫距离能够通过参数hbase.regionserver.optionallogflushinterval进行设定,默认是1000ms。

  • MemStore

每个Store中有一个MemStore实例。数据写入WAL之后就会被放入MemStore。MemStore是内存的存储对象,只有当MemStore满了的时候才会将数据刷写(flush)到HFile中。

为了让数据顺序存储从而进步读取效率,HBase应用了LSM树结构来存储数据。数据会先在Memstore中
整顿成LSM树,最初再刷写到HFile上。

对于MemStore,很容易让人混同。数据在被刷到HFile之前,曾经被存储到了HDFS的WAL上了,那么为什么还要在放入MemStore呢?其实很简略,咱们都晓得HDFS是不能批改的,而HBase的数据又是依照Row Key进行排序的,其实这个排序的过程就是在MemStore中进行的。值得注意的是:MemStore的作用不是为了放慢写速度,而是为了对Row Key进行排序。

  • HFile

HFile是数据存储的理论载体,咱们创立的所有表、列等数据都存储在HFile外面。当Memstore达到肯定阀值,或者达到了刷写工夫距离阀值的时候,HBaes会被这个Memstore的内容刷写到HDFS零碎上,称为一个存储在硬盘上的HFile文件。至此,咱们数据真正地被长久化到硬盘上。

Region的定位

在开始解说HBase的数据读写流程之前,先来看一下Region是怎么定位的。咱们晓得Region是HBase十分重要的一个概念,Region存储在RegionServer中,那么客户端在读写操作时是如何定位到所须要的region呢?对于这个问题,老版本的HBase与新版本的HBase有所不同。

老版本HBase(0.96.0之前)

老版本的HBase采纳的是为三层查问架构,如下图所示:

如上图:第一层定位是Zookeeper中的节点数据,记录了-ROOT-表的地位信息;

第二层-ROOT-表记录了.META.region地位信息,-ROOT-表只有一个region,通过-ROOT-表能够拜访.META.表中的数据

第三层.META.表,记录了用户数据表的region地位信息,.META.表能够有多个region。

整个查问步骤如下:

第一步:用户通过查找zk(ZooKeeper)的/hbase/root-regionserver节点来晓得-ROOT-表的RegionServer地位。

第二步:拜访-ROOT-表,查找所须要的数据表的元数据信息存在哪个.META.表上,这个.META.表在哪个RegionServer上。

第四步:拜访.META.表来看你要查问的行键在什么Region范畴外面。

第五步:连贯具体的数据所在的RegionServer,这个一步才开始在很正的查问数据。

新版本HBase

老版本的HBase寻址存在很多弊病,在新版本中进行了改良。采纳的是二级寻址的形式,仅仅应用 hbase:meta表来定位region,那么 从哪里获取hbase:meta的信息呢,答案是zookeeper。在zookeeper中存在一个/hbase/meta-region-server节点,能够获取hbase:meta表的地位信息,而后通过hbase:meta表查问所须要数据所在的region地位信息。

整个查问步骤如下:

第一步:客户端先通过ZooKeeper的/hbase/meta-region-server节点查问hbase:meta表的地位。

第二步:客户端连贯hbase:meta表所在的RegionServer。hbase:meta表存储了所有Region的行键范畴信息,通过这个表就能够查问出你要存取的rowkey属于哪个Region的范畴外面,以及这个Region属于哪个
RegionServer。

第三步:获取这些信息后,客户端就能够直连领有你要存取的rowkey的RegionServer,并间接对其操作。

第四步:客户端会把meta信息缓存起来,下次操作就不须要进行以上加载hbase:meta的步骤了。

客户端API根本应用

public class Example {  private static final String TABLE_NAME = "MY_TABLE_NAME_TOO";  private static final String CF_DEFAULT = "DEFAULT_COLUMN_FAMILY";  public static void createOrOverwrite(Admin admin, HTableDescriptor table) throws IOException {    if (admin.tableExists(table.getTableName())) {      admin.disableTable(table.getTableName());      admin.deleteTable(table.getTableName());    }    admin.createTable(table);  }  public static void createSchemaTables(Configuration config) throws IOException {    try (Connection connection = ConnectionFactory.createConnection(config);         Admin admin = connection.getAdmin()) {      HTableDescriptor table = new HTableDescriptor(TableName.valueOf(TABLE_NAME));      table.addFamily(new HColumnDescriptor(CF_DEFAULT).setCompressionType(Algorithm.NONE));      System.out.print("Creating table. ");      createOrOverwrite(admin, table);      System.out.println(" Done.");    }  }  public static void modifySchema (Configuration config) throws IOException {    try (Connection connection = ConnectionFactory.createConnection(config);         Admin admin = connection.getAdmin()) {      TableName tableName = TableName.valueOf(TABLE_NAME);      if (!admin.tableExists(tableName)) {        System.out.println("Table does not exist.");        System.exit(-1);      }      HTableDescriptor table = admin.getTableDescriptor(tableName);      // 更新table      HColumnDescriptor newColumn = new HColumnDescriptor("NEWCF");      newColumn.setCompactionCompressionType(Algorithm.GZ);      newColumn.setMaxVersions(HConstants.ALL_VERSIONS);      admin.addColumn(tableName, newColumn);      // 更新column family      HColumnDescriptor existingColumn = new HColumnDescriptor(CF_DEFAULT);      existingColumn.setCompactionCompressionType(Algorithm.GZ);      existingColumn.setMaxVersions(HConstants.ALL_VERSIONS);      table.modifyFamily(existingColumn);      admin.modifyTable(tableName, table);      // 禁用table      admin.disableTable(tableName);      // 删除column family      admin.deleteColumn(tableName, CF_DEFAULT.getBytes("UTF-8"));      // 删除表,首先要禁用表      admin.deleteTable(tableName);    }  }  public static void main(String... args) throws IOException {    Configuration config = HBaseConfiguration.create();    config.addResource(new Path(System.getenv("HBASE_CONF_DIR"), "hbase-site.xml"));    config.addResource(new Path(System.getenv("HADOOP_CONF_DIR"), "core-site.xml"));    createSchemaTables(config);    modifySchema(config);  }}

易混同知识点总结

Q1:MemStore的作用是什么?

在HBase中,一个表能够有多个列族,一个列族在物理上是存储在一起的,一个列族会对应一个store,在store的外部会存在一个MemStore,其作用并不是为了晋升读写速度,而是为了对RowKey进行排序。咱们晓得,HBase的数据是存储在HDFS上的,而HDFS是不反对批改的,HBase为了按RowKey进行排序,首先会将数据写入MemStore,数据会先在Memstore中整顿成LSM树,最初再刷写到HFile上。

总之一句话:Memstore的实现目标不是减速数据写入或读取,而是维持数据结构。

Q2:读取数据时会先从MemStore读取吗?

MemStore的作用是为了按RowKey进行排序,其作用不是为了晋升读取速度的。读取数据的时候是有专门的缓存叫BlockCache,如果开启了BlockCache,就是先读BlockCache,而后才是读HFile+Memstore的数据。

Q3:BlockCache有什么用?

块缓存(BlockCache)应用内存来记录数据,实用于晋升读取性能。当开启了块缓存后,HBase会优先从块缓存中查问是否有记录,如果没有才去检索存储在硬盘上的HFile。

值得注意的是,一个RegionServer只有一个BlockCache。BlockCache不是数据存储的必须组成部分,只是用来优化读取性能的。

BlockCache的基本原理是:在读申请到HBase之后,会先尝试查问BlockCache,如果获取不到所需的数据,就去HFile和Memstore中去获取。如果获取到了,则在返回数据的同时把Block块缓存到BlockCache中。

Q4:HBase是怎么删除数据的?

HBase删除记录并不是真的删除了数据,而是标识了一个墓碑标记(tombstone marker),把这个版本连同之前的版本都标记为不可见了。这是为了性能着想,这样HBase就能够定期去清理这些曾经被删除的记录,而不必每次都进行删除操作。所谓定期清理,就是依照肯定工夫周期在HBase做主动合并(compaction,HBase整顿存储文件时的一个操作,会把多个文件块合并成一个文件)。这样删除操作对于HBase的性能影响被降到了最低,即使是在很高的并发负载下大量删除记录也是OK的。

合并操作分为两种:Minor CompactionMajor Compaction

其中Minor Compaction是将Store多个HFile合并为一个HFile。在这个过程中达到TTL的数据会被移除,然而被手动删除的数据不会被移除。这种合并触发频率较高。

Major Compaction合并Store中的所有HFile为一个HFile。在这个过程中被手动删除的数据会被真正地移除。同时被删除的还有单元格内超过MaxVersions的版本数据。这种合并触发频率较低,默认为7天一次。不过因为Major Compaction耗费的性能较大,个别倡议手动管制MajorCompaction的机会。

须要留神的是:Major Compaction删除的是那些带墓碑标记的数据,而Minor Compaction合并的时候间接会疏忽过期数据文件,所以过期的这些文件会在Minor Compaction的时候就被删除。

Q5:为什么HBase具备高性能的读写能力?

因为HBase应用了一种LSM的存储构造,在LSM树的实现形式中,会在数据存储之前先对数据进行排序。LSM树是Google BigTable和HBase的根本存储算法,它是传统关系型数据库的B+树的改良。算法的外围在于尽量保证数据是顺序存储到磁盘上的,并且会有频率地对数据进行整顿,确保其程序性。

LSM树就是一堆小树,在内存中的小树即memstore,每次flush,内存中的memstore变成磁盘上一个新的storefile。这种批量的读写操作使得HBase的性能较高。

Q6:Store与列簇是什么关系?

Region是HBase的外围模块,而Store则是Region的外围模块。每个Store对应了表中的一个列族存储。每个Store蕴含一个MemStore和若干个HFile。

Q7:WAL是RegionServer共享的,还是Region级别共享的?

在HBase中,每个RegionServer只须要保护一个WAL,所有Region对象共用一个WAL,而不是每个Region都保护一个WAL。这种形式对于多个Region的更新操作所产生的的日志批改,只须要一直地追加到单个日志文件中,不须要同时关上并写入多个日志文件,这样能够缩小磁盘寻址次数,进步写性能。

然而这种形式也存在一个毛病,如果RegionServer产生故障,为了复原其上的Region对象,须要将RegionServer上的WAL依照其所属的Region对象进行拆分,而后散发到其余RegionServer上执行复原操作。

Q8:Master挂掉之后,还能查问数据吗?

能够的。Master服务次要负责表和Region的管理工作。次要作用有:

  • 治理用户对表的减少、删除、批改操作
  • 实现不同RegionServer之前的负载平衡
  • Region的决裂与合并
  • 对产生故障的RegionServer的Region进行迁徙

客户端拜访HBase时,不须要Master的参加,只须要连贯zookeeper获取hbase:meta地址,而后直连RegionServer进行数据读写操作,Master仅仅保护表和Region的元数据信息,负载很小。然而Master节点也不能长时间的宕机。

总结

本文首先从谷歌的BigTable说起,而后介绍了CAP相干实践,并剖析了NoSQL呈现的起因。接着对HBase的数据模型进行了分析,而后详细描述了HBase的原理和运行机制。最初给出了客户端API的根本应用,并对常见的、易混同的知识点进行了解释。

公众号『大数据技术与数仓』,回复『材料』支付大数据资料包