乐趣区

关于hbase:内含面试一文搞懂HBase的基本原理

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

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

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

从 BigTable 说起

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

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

依赖 BigTbale HBase
数据存储 GFS HDFS
数据处理 MapReduce Hadoop 的 MapReduce
协同服务 Chubby Zookeeper

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 的根本应用,并对常见的、易混同的知识点进行了解释。

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

退出移动版