HBase-是什么
Posted hanease
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HBase-是什么相关的知识,希望对你有一定的参考价值。
HBase 是一个开源的、分布式的、版本化的非关系型数据库,它利用 Hadoop 分布式文件系统(Hadoop Distributed File System,HDFS)提供分布式数据存储。
HBase 是一个可以进行随机访问的存取和检索数据的存储平台,存储结构化和半结构化的数据,因此一般的网站可以将网页内容和日志信息都存在 HBase 里。
如果数据量不是非常庞大,HBase 甚至可以存储非结构化的数据。它不要求数据有预定义的模式,允许动态和灵活的数据模型,也不限制存储数据的类型。
HBase 是非关系型数据库,它不具备关系型数据库的一些特点,例如,它不支持 SQL 的跨行事务,也不要求数据之间有严格的关系,同时它允许在同一列的不同行中存储不同类型的数据。
HBase 作为 Hadoop 框架下的数据库,是被设计成在一个服务器集群上运行的。
HBase 是典型的 NoSQL 数据库,通常被描述成稀疏的、分布式的、持久化的,由行键、列键和时间戳进行索引的多维有序映射数据库,主要用来存储非结构化和半结构化的数据。因为 HBase 基于 Hadoop 的 HDFS 完成分布式存储,以及 MapReduce 完成分布式并行计算,所以它的一些特点与 Hadoop 相同,依靠横向扩展,通过不断增加性价比高的商业服务器来增加计算和存储能力。
HBase 虽然基于 Bigtable 的开源实现,但它们之间还是有很多差别的,Bigtable 经常被描述成键值数据库,而 HBase 则是面向列存储的分布式数据库。
下面介绍 HBase 具备的显著特性,这些特性让 HBase 成为当前和未来最实用的数据库之一。
容量巨大
HBase 的单表可以有百亿行、百万列,可以在横向和纵向两个维度插入数据,具有很大的弹性。
当关系型数据库的单个表的记录在亿级时,查询和写入的性能都会呈现指数级下降,这种庞大的数据量对传统数据库来说是一种灾难,而 HBase 在限定某个列的情况下对于单表存储百亿甚至更多的数据都没有性能问题。
HBase 采用 LSM 树作为内部数据存储结构,这种结构会周期性地将较小文件合并成大文件,以减少对磁盘的访问。
列存储
与很多面向行存储的关系型数据库不同,HBase 是面向列的存储和权限控制的,它里面的每个列是单独存储的,且支持基于列的独立检索。通过下图的例子来看行存储与列存储的区别。
从上图可以看到,行存储里的一张表的数据都放在一起,但在列存储里是按照列分开保存的。在这种情况下,进行数据的插入和更新,行存储会相对容易。而进行行存储时,查询操作需要读取所有的数据,列存储则只需要读取相关列,可以大幅降低系统 I/O 吞吐量。
稀疏性
通常在传统的关系性数据库中,每一列的数据类型是事先定义好的,会占用固定的内存空间,在此情况下,属性值为空(NULL)的列也需要占用存储空间。
而在 HBase 中的数据都是以字符串形式存储的,为空的列并不占用存储空间,因此 HBase 的列存储解决了数据稀疏性的问题,在很大程度上节省了存储开销。所以 HBase 通常可以设计成稀疏矩阵,同时这种方式比较接近实际的应用场景。
扩展性强
HBase 工作在 HDFS 之上,理所当然地支持分布式表,也继承了 HDFS 的可扩展性。HBase 的扩展是横向的,横向扩展是指在扩展时不需要提升服务器本身的性能,只需添加服务器到现有集群即可。
HBase 表根据 Region 大小进行分区,分别存在集群中不同的节点上,当添加新的节点时,集群就重新调整,在新的节点启动 HBase 服务器,动态地实现扩展。这里需要指出,HBase 的扩展是热扩展,即在不停止现有服务的前提下,可以随时添加或者减少节点。
高可靠性
HBase 运行在 HDFS 上,HDFS 的多副本存储可以让它在岀现故障时自动恢复,同时 HBase 内部也提供 WAL 和 Replication 机制。
WAL(Write-Ahead-Log)预写日志是在 HBase 服务器处理数据插入和删除的过程中用来记录操作内容的日志,保证了数据写入时不会因集群异常而导致写入数据的丢失;而 Replication 机制是基于日志操作来做数据同步的。
当集群中单个节点出现故障时,协调服务组件 ZooKeeper 通知集群的主节点,将故障节点的 HLog 中的日志信息分发到各从节点进行数据恢复。
Google 公司的 Bigtable 建模,而 Bigtable 是基于 GFS 来完成数据的分布式存储的,因此,HBase 与 HDFS 有非常紧密的关系,它使用 HDFS 作为底层存储系统。虽然 HBase 可以单独运行在本地文件系统上,但这不是 HBase 设计的初衷。
HBase 是在 Hadoop 这种分布式框架中提供持久化的数据存储与管理的工具。在使用 HBase 的分布式集群模式时,前提是必须有 Hadoop 系统。
Hadoop 系统为 HBase 提供给了分布式文件存储系统,同时也使得 MapReduce 组件能够直接访问 HBase 进行分布式计算。
HBase 最重要的访问方式是 Java API(Application Programming Interface,应用程序编程接口),MapReduce 的批量操作方式并不常用。
下图展示了 HBase 在 Hadoop 生态系统中的位置。
本节的知识点都基于 HBase 1.2.6 稳定版本,因为 HBase 底层依赖 Hadoop,所以对 Hadoop 的版本也有要求。
一、spark与storm的比较
比较点 |
Storm |
Spark Streaming |
实时计算模型 |
纯实时,来一条数据,处理一条数据 |
准实时,对一个时间段内的数据收集起来,作为一个RDD,再处理 |
实时计算延迟度 |
毫秒级 |
秒级 |
低 |
高 |
|
事务机制 |
支持完善 |
支持,但不够完善 |
健壮性 / 容错性 |
ZooKeeper,Acker,非常强 |
Checkpoint,WAL,一般 |
动态调整并行度 |
支持 |
不支持 |
对于Storm来说:
1、建议在那种需要纯实时,不能忍受1秒以上延迟的场景下使用,比如实时金融系统,要求纯实时进行金融交易和分析
2、此外,如果对于实时计算的功能中,要求可靠的事务机制和可靠性机制,即数据的处理完全精准,一条也不能多,一条也不能少,也可以考虑使用Storm
3、如果还需要针对高峰低峰时间段,动态调整实时计算程序的并行度,以最大限度利用集群资源(通常是在小型公司,集群资源紧张的情况),也可以考虑用Storm
4、如果一个大数据应用系统,它就是纯粹的实时计算,不需要在中间执行SQL交互式查询、复杂的transformation算子等,那么用Storm是比较好的选择
对于Spark Streaming来说:
1、如果对上述适用于Storm的三点,一条都不满足的实时场景,即,不要求纯实时,不要求强大可靠的事务机制,不要求动态调整并行度,那么可以考虑使用Spark Streaming
2、考虑使用Spark Streaming最主要的一个因素,应该是针对整个项目进行宏观的考虑,即,如果一个项目除了实时计算之外,还包括了离线批处理、交互式查询等业务功能,而且实时计算中,可能还会牵扯到高延迟批处理、交互式查询等功能,那么就应该首选Spark生态,用Spark Core开发离线批处理,用Spark SQL开发交互式查询,用Spark Streaming开发实时计算,三者可以无缝整合,给系统提供非常高的可扩展性
Spark Streaming与Storm的优劣分析
事实上,Spark Streaming绝对谈不上比Storm优秀。这两个框架在实时计算领域中,都很优秀,只是擅长的细分场景并不相同。
Spark Streaming仅仅在吞吐量上比Storm要优秀,而吞吐量这一点,也是历来挺Spark Streaming,贬Storm的人着重强调的。但是问题是,是不是在所有的实时计算场景下,都那么注重吞吐量?不尽然。因此,通过吞吐量说Spark Streaming强于Storm,不靠谱。
事实上,Storm在实时延迟度上,比Spark Streaming就好多了,前者是纯实时,后者是准实时。而且,Storm的事务机制、健壮性 / 容错性、动态调整并行度等特性,都要比Spark Streaming更加优秀。
Spark Streaming,有一点是Storm绝对比不上的,就是:它位于Spark生态技术栈中,因此Spark Streaming可以和Spark Core、Spark SQL无缝整合,也就意味着,我们可以对实时处理出来的中间数据,立即在程序中无缝进行延迟批处理、交互式查询等操作。这个特点大大增强了Spark Streaming的优势和功能。
HDFS 的基本架构
HDFS 主要由 3 个组件构成,分别是 NameNode、SecondaryNameNode 和 DataNode。
HDFS 是以 Master/Slave 模式运行的,其中,NameNode 和 SecondaryNameNode 运行在 Master 节点 上,而 DataNode 运行在 Slave 节点上,所以 HDFS 集群一般由一个 NameNode、一个 SecondaryNameNode 和许多 DataNode 组成,其架构如下图所示。
在 HDFS 中,文件是被分成块来进行存储的,一个文件可以包含许多个块,每个块存储在不同的 DataNode 中。从上图中可知,当一个客户端请求读取一个文件时,它需要先从 NameNode 中获取文件的元数据信息,然后从对应的数据节点上并行地读取数据块。
下面介绍 HDFS 架构中 NameNode、SecondaryNameNode 和 DataNode 的功能。
NameNode
NameNode 是主服务器,负责管理文件系统的命名空间以及客户端对文件的访问。当客户端请求数据时,仅仅从 NameNode 中获取文件的元数据信息,具体的数据传输不经过 NameNode,而是直接与具体的 DataNode 进行交互。
这里文件的元数据信息记录了文件系统中的文件名和目录名,以及它们之间的层级关系,同时也记录了每个文件目录的所有者及其权限,甚至还记录每个文件由哪些块组成,这些元数据信息记录在文件 fsimage 中,当系统初次启动时,NameNode 将读取 fsimage 中的信息并保存到内存中。
这些块的位置信息是由 NameNode 启动后从每个 DataNode 获取并保存在内存当中的,这样既减少了 NameNode 的启动时间,又减少了读取数据的查询时间,提高了整个系统的效率。
SecondaryNameNode
从字面上来看,SecondaryNameNode 很容易被当作是 NameNode 的备份节点,其实不然。可以通过下图看 HDFS 中 SecondaryNameNode 的作用。
NameNode 管理着元数据信息,元数据信息会定期保存到 edits 和 fsimage 文件中。其中的 edits 保存操作日志信息,在 HDFS 运行期间,新的操作日志不会立即与 fsimage 进行合并,也不会存到 NameNode 的内存中,而是会先写到 edits 中。
当 edits 文件达到一定域值或间隔一段时间后触发 SecondaryNameNode 进行工作,这个时间点称为 checkpoint。
SecondaryNameNode 的角色就是定期地合并 edits 和 fsimage 文件,其合并步骤如下。
- 在进行合并之前,SecondaryNameNode 会通知 NameNode 停用当前的 editlog 文件, NameNode 会将新记录写入新的 editlog.new 文件中。
- SecondaryNameNode 从 NameNode 请求并复制 fsimage 和 edits 文件。
- SecondaryNameNode 把 fsimage 和 edits 文件合并成新的 fsimage 文件,并命名为 fsimage.ckpto
- NameNode 从 SecondaryNameNode 获取 fsimage.ckpt,并替换掉 fsimage,同时用 edits.new 文件替换旧的 edits 文件。
- 更新 checkpoint 的时间。
最终 fsimage 保存的是上一个 checkpoint 的元数据信息,而 edits 保存的是从上个 checkpoint 开始发生的 HDFS 元数据改变的信息。
DataNode
DataNode 是 HDFS 中的工作节点,也是从服务器,它负责存储数据块,也负责为客户端提供数据块的读写服务,同时也响应 NameNode 的相关指令,如完成数据块的复制、删除等。
另外, DataNode 会定期发送心跳信息给 NameNode,告知 NameNode 当前节点存储的文件块信息。当客户端给 NameNode 发送读写请求时,NameNode 告知客户端每个数据块所在的 DataNode 信息,然后客户端直接与 DataNode 进行通信,减少 NameNode 的系统开销。
当 DataNode 在执行块存储操作时,DataNode 还会与其他 DataNode 通信,复制这些块到其他 DataNode 上实现冗余。
HDFS 的分块机制和副本机制
在 HDFS 中,文件最终是以数据块的形式存储的,而副本机制极大程度上避免了宕机所造成的数据丢失,可以在数据读取时进行数据校验。
分块机制
HDFS 中数据块大小默认为 64MB,而一般磁盘块的大小为 512B,HDFS 块之所以这么大,是为了最小化寻址开销。
如果块足够大,从磁盘传输数据的时间会明显大于寻找块的地址的时间,因此,传输一个由多个块组成的大文件的时间取决于磁盘传输速率。
随着新一代磁盘驱动器传输速率的提升,寻址开销会更少,在更多情况下 HDFS 使用更大的块。当然块的大小不是越大越好,因为 Hadoop 中一个 map 任务一次通常只处理一个块中的数据,如果块过大,会导致整体任务数量过小,降低作业处理的速度。
HDFS 按块存储还有如下好处。
1) 文件可以任意大,不会受到单个节点的磁盘容量的限制。理论上讲,HDFS 的存储容量是无限的。
2) 简化文件子系统的设计。将系统的处理对象设置为块,可以简化存储管理,因为块大小固定,所以每个文件分成多少个块,每个 DataNode 能存多少个块,都很容易计算。同时系统中 NameNode 只负责管理文件的元数据,DataNode 只负责数据存储,分工明确,提高了系统的效率。
3) 有利于提高系统的可用性。HDFS 通过数据备份来提供数据的容错能力和高可用性,而按照块的存储方式非常适合数据备份。同时块以副本方式存在多个 DataNode 中,有利于负载均衡,当某个节点处于繁忙状态时,客户端还可以从其他节点获取这个块的副本。
副本机制
HDFS 中数据块的副本数默认为 3,当然可以设置更多的副本数,这些副本分散存储在集群中,副本的分布位置直接影响 HDFS 的可靠性和性能。
一个大型的分布式文件系统都是需要跨多个机架的,如下图中,HDFS 涉及两个机架。
如果把所有副本都存放在不同的机架上,可以防止机架故障从而导致数据块不可用,同时在多个客户端访问文件系统时很容易实现负载均衡。如果是写数据,各个数据块需要同步到不同机架上,会影响写数据的效率。
在 HDFS 默认 3 个副本情况下,会把第一个副本放到机架的一个节点上,第二副本放在同一 个机架的另一个节点上,第三个副本放在不同的机架上。
这种策略减少了跨机架副本的个数,提高了数据块的写性能,也可以保证在一个机架出现故障时,仍然能正常运转。
HDFS 的读写机制
前面讲到,客户端读、写文件是与 NameNode 和 DataNode 通信的,下面详细介绍 HDFS 中读写文件的过程。
读文件
HDFS 通过 RPC 调用 NameNode 获取文件块的位置信息,并且对每个块返回所在的 DataNode 的地址信息,然后再从 DataNode 获取数据块的副本。
HDFS 读文件的过程如图所示。
操作步骤如下:
- 客户端发起文件读取的请求。
- NameNode 将文件对应的数据块信息及每个块的位置信息,包括每个块的所有副本的位置信息(即每个副本所在的 DataNode 的地址信息)都传送给客户端。
- 客户端收到数据块信息后,直接和数据块所在的 DataNode 通信,并行地读取数据块。
在客户端获得 NameNode 关于每个数据块的信息后,客户端会根据网络拓扑选择与它最近的 DataNode 来读取每个数据块。当与 DataNode 通信失败时,它会选取另一个较近的 DataNode,同时会对出故障的 DataNode 做标记,避免与它重复通信,并发送 NameNode 故障节点的信息。
写文件
当客户端发送写文件请求时,NameNode 负责通知 DataNode 创建文件,在创建之前会检查客户端是否有允许写入数据的权限。通过检测后,NameNode 会向 edits 文件写入一条创建文件的操作记录。
HDFS 中写文件的过程如图所示。
操作步骤如下:
1) 客户端在向 NameNode 发送写请求之前,先将数据写入本地的临时文件中。
2) 待临时文件块达到系统设置的块大小时,开始向 NameNode 请求写文件。
3) NameNode 在此步骤中会检查集群中每个 DataNode 状态信息,获取空闲的节点,并在检查客户端权限后创建文件,返回客户端一个数据块及其对应 DataNode 的地址列表。列表中包含副本存放的地址。
4) 客户端在获取 DataNode 相关信息后,将临时文件中的数据块写入列表中的第一个 DataNode,同时第一个 DataNode 会将数据以副本的形式传送至第二个 DataNode,第二个节点也会将数据传送至第三个 DataNode。
DataNode 以数据包的形式从客户端接收数据,并以流水线的形式写入和备份到所有的 DataNode 中,每个 DataNode 收到数据后会向前一个节点发送确认信息。 最终数据传输完毕,第一个 DataNode 会向客户端发送确认信息。
5) 当客户端收到每个 DataNode 的确认信息时,表示数据块已经持久化地存储在所有 DataNode 当中,接着客户端会向 NameNode 发送确认信息。如果在第(4 )步中任何一个 DataNode 失败,客户端会告知 NameNode,将数据备份到新的 DataNode 中。
适合存储超大文件
HDFS 支持 GB 级别甚至 TB 级别的文件,每个文件大小可以大于集群中任意一个节点的磁盘容量,文件的所有数据块存在不同节点中,在进行大文件读写时采用并行的方式提高数据的吞吐量。
HDFS 不适合存储大量的小文件,这里的小文件指小于块大小的文件。因为 NameNode 将文件系统的元数据信息存在内存当中,所以 HDFS 所能存储的文件总数受到 NameNode 内存容量的限制。
下面通过举例来计算同等容量的单个大文件和多个小文件所占的文件块的个数。
假设 HDFS 中块的大小为 64MB,备份数量为 3,—般情况下,一条元数据记录占用 200B 的内存。那么,对于 1GB 的大文件,将占用 1GB/64MB x 3 个文件块;对于 1024 个 1MB 的小文件,则占用 1024 x3 个文件块。可以看到,存储同等大小的文件,单个文件越小,所需的元数据信息越大,占用的内存越大,因此 HDFS 适合存储超大文件。
适用于流式的数据访问
HDFS 适用于批量数据的处理,不适用于交互式处理。它设计的目标是通过流式的数据访问保证高吞吐量,不适合对低延迟用户响应的应用。可以选择 HBase 满足低延迟用户的访问需求。
支持简单的一致性模型
HDFS 中的文件支持一次写入、多次读取,写入操作是以追加的方式添加在文件末尾,不支持多个写入者的操作,也不支持对文件的任意位置进行修改。
计算向数据靠拢
在 Hadoop 系统中,对数据进行计算时,采用将计算向数据靠拢的方式,即选择最近的数据进行计算,减少数据在网络中的传输延迟。
底层基于 Hadoop 的 HDFS 来存储数据。本节将介绍 HBase 的系统架构以及每个组件的功能。
上图展示了 HBase 的系统架构,包括客户端、ZooKeeper 服务器、HMaster 主服务器和 RegionServer。Region 是 HBase 中数据的物理切片,每个 Region 中记录了全局数据的一小部分,并且不同的 Region 之间的数据是互不重复的。
ZooKeeper 是一个高性能、集中化、分布式应用程序协调服务,主要是用来解决分布式应用中用户经常遇到的一些数据管理问题,例如,数据发布/订阅、命名服务、分布式协调通知、集群管理、Master 选举、分布式锁和分布式队列等功能。其中,Master 选举是 ZooKeeper 最典型的应用场景。
在 Hadoop 中,ZooKeeper 主要用于实现高可靠性(High Availability, HA),包括 HDFS 的 NameNode 和 YARN 的 ResourceManager 的 HA。 以 HDFS 为例,NameNode 作为 HDFS 的主节点,负责管理文件系统的命名空间以及客户端对文件的访问,同时需要监控整个 HDFS 中每个 DataNode 的状态,实现负载均衡和容错。
为了实现 HA,必须有多个 NameNode 并存,并且只有一个 NameNode 处于活跃状态,其他的则处于备用状态。当活跃的 NameNode 无法正常工作时, 处于备用状态的 NameNode 会通过竞争选举产生新的活跃节点来保证 HDFS 集群的高可靠性。
从上图中可以看到,在 HBase 的系统架构中,ZooKeeper 是串联 HBase 集群和 Client 的关键。
ZooKeeper 在 HBase 中的负责协调的任务如下。
Master 选举
同 HDFS 的 HA 机制一样,HBase 集群中有多个 HMaster 并存,通过竞争选举机制保证同一时刻只有一个 HMaster 处于活跃状态,一旦这个 HMaster 无法使用,则从备用节点中选出一个顶上,保证集群的高可靠性。
系统容错
在 HBase 启动时,每个 RegionServer 在加入集群时都需要到 ZooKeeper 中进行注册,创建一个状态节点,ZooKeeper 会实时监控每个 RegionServer 的状态,同时 HMaster 会监听这些注册的 RegionServer。
当某个 RegionServer 挂断的时候,ZooKeeper 会因为一段时间内接收不到它的心跳信息而删除该 RegionServer 对应的状态节点,并且给 HMaster 发送节点删除的通知。这时,HMaster 获知集群中某节点断开,会立即调度其他节点开启容错机制。
Region 元数据管理
在 HBase 集群中,Region 元数据被存储在 Meta 表中。每次客户端发起新的请求时,需要查询 Meta 表来获取 Region 的位置,而 Meta 表是存在 ZooKeeper 中的。
当 Region 发生变化时,例如,Region 的手工移动、进行负载均衡的移动或 Region 所在的 RegionServer 出现故障等,就能够通过 ZooKeeper 来感知到这一变化,保证客户端能够获得正确的 Region 元数据信息。
Region 状态管理
HBase 集群中 Region 会经常发生变更,其原因可能是系统故障,配置修改,或者是 Region 的分裂和合并。只要 Region 发生变化,就需要让集群的所有节点知晓,否则就会出现某些事务性的异常。
而对于 HBase 集群,Region 的数量会达到 10 万,甚至更多。如此规模的 Region 状态管理如果直接由 HMaster 来实现,则 HMaster 的负担会很重,因此只有依靠 ZooKeeper 系统来完成。
提供 Meta 表存储位置
在 HBase 集群中,数据库表信息、列族信息及列族存储位置信息都属于元数据。这些元数据存储在 Meta 表中,而 Meta 表的位置入口由 ZooKeeper 来提供。
在分布式集群中,HMaster 服务器通常运行在 HDFS 的 NameNode上,HMaster 通过 ZooKeeper 来避免单点故障,在集群中可以启动多个 HMaster,但 ZooKeeper 的选举机制能够保证同时只有一个 HMaster 处于 Active 状态,其他的 HMaster 处于热备份状态。
HMaster 主要负责表和 Region 的管理工作。
1) 管理用户对表的增、删、改、查操作。
HMaster 提供了下表中的一些基于元数据方法的接口,便于用户与 HBase 进行交互。
相关接口 | 功能 |
---|---|
HBase 表 | 创建表、删除表、启用/失效表、修改表 |
HBase 列表 | 添加列、修改列、移除列 |
HBase 表 Region | 移动 Region、分配和合并 Region |
2) 管理 RegionServer 的负载均衡,调整 Region 的分布。
3) Region 的分配和移除。
4) 处理 RegionServer 的故障转移。
当某台 RegionServer 出现故障时,总有一部分新写入的数据还没有持久化地存储到磁盘中,因此在迁移该 RegionServer 的服务时,需要从修改记录中恢复这部分还在内存中的数据,HMaster 需要遍历该 RegionServer 的修改记录,并按 Region 拆分成小块移动到新的地址下。
另外,当 HMaster 节点发生故障时,由于客户端是直接与 RegionServer 交互的,且 Meta 表也是存在于 ZooKeeper 当中,整个集群的工作会继续正常运行,所以当 HMaster 发生故障时,集群仍然可以稳定运行。
但是 HMaster 还会执行一些重要的工作,例如,Region 的切片、RegionServer 的故障转移等,如果 HMaster 发生故障而没有及时处理,这些功能都会受到影响,因此 HMaster 还是要尽快恢复工作。 ZooKeeper 组件提供了这种多 HMaster 的机制,提高了 HBase 的可用性和稳健性。
在 HDFS 中,DataNode 负责存储实际数据。RegionServer 主要负责响应用户的请求,向 HDFS 读写数据。一般在分布式集群中,RegionServer 运行在 DataNode 服务器上,实现数据的本地性。
每个 RegionServer 包含多个 Region,它负责的功能如下:
- 处理分批给它的 Region。
- 处理客户端读写请求。
- 刷新缓存到 HDFS 中。
- 处理 Region 分片。
- 执行压缩。
RegionServer 是 HBase 中最核心的模块,其内部管理了一系列 Region 对象,每个 Region 由多个 HStore 组成,每个 HStore 对应表中一个列族的存储。
HBase 是按列进行存储的,将列族作为一个集中的存储单元,并且 HBase 将具备相同 I/O 特性的列存储到一个列族中,这样可以保证读写的高效性。
在上图中,RegionServer 最终将 Region 数据存储在 HDFS 中,采用 HDFS 作为底层存储。
HBase 自身并不具备数据复制和维护数据副本的功能,而依赖 HDFS 为 HBase 提供可靠和稳定的存储。
当然,HBase 也可以不采用 HDFS,如它可以使用本地文件系统或云计算环境中的 Amazon S3。本专题中 HBase 的内容都是以 HDFS 为底层存储来描述的。
HBase 解决不了所有的问题,但是针对某些特点的数据可以使用 HBase 高效地解决,如以下的应用场景。
- 数据模式是动态的或者可变的,且支持半结构化和非结构化的数据。
- 数据库中的很多列都包含了很多空字段,在 HBase 中的空字段不会像在关系型数据库中占用空间。
- 需要很高的吞吐量,瞬间写入量很大。
- 数据有很多版本需要维护,HBase 利用时间戳来区分不同版本的数据。
- 具有高可扩展性,能动态地扩展整个存储系统。
HBase 的基本概念
HBase 不支持关系模型,它可以根据用户的需求提供更灵活和可扩展的表设计。与传统的关系型数据库类似,HBase 也是以表的方式组织数据,应用程序将数据存于 HBase 的表中,HBase 的表也由行和列组成。
但有一点不同的是,HBase 有列族的概念,它将一列或多列组织在一起,HBase 的每个列必须属于某一个列族。
下面具体介绍 HBase 数据模型中一些名词的概念。
1) 表(Table)
HBase 中的数据以表的形式存储。同一个表中的数据通常是相关的,使用表主要是可以把某些列组织起来一起访问。表名作为 HDFS 存储路径的一部分来使用,在 HDFS 中可以看到每个表名都作为独立的目录结构。
2) 行(Row)
在 HBase 表里,每一行代表一个数据对象,每一行都以行键(Row Key)来进行唯一标识,行键可以是任意字符串。在 HBase 内部,行键是不可分割的字节数组,并且行键是按照字典排序由低到高存储在表中的。在 HBase 中可以针对行键建立索引,提高检索数据的速度。
3) 列族(Colunm Family)
HBase 中的列族是一些列的集合,列族中所有列成员有着相同的前缀,列族的名字必须是可显示的字符串。列族支持动态扩展,用户可以很轻松地添加一个列族或列,无须预定义列的数量以及类型。所有列均以字符串形式存储,用户在使用时需要自行进行数据类型转换。
4) 列标识(Column Qualifier)
列族中的数据通过列标识来进行定位,列标识也没有特定的数据类型,以二进制字节来存储。通常以 Column Family:Colunm Qualifier 来确定列族中的某列。
5) 单元格(Cell)
每一个行键、列族、列标识共同确定一个单元格,单元格的内容没有特定的数据类型,以二进制字节来存储。每个单元格保存着同一份数据的多个版本,不同时间版本的数据按照时间先后顺序排序,最新的数据排在最前面。单元格可以用 <RowKey,Column Family: Column Qualifier,Timestamp> 元组来进行访问。
6) 时间戳(Timestamp)
在默认情况下,每一个单元格插入数据时都会用时间戳来进行版本标识。读取单元格数据时,如果时间戳没有被指定,则默认返回最新的数据;写入新的单元格数据时,如果没有设置时间戳,默认使用当前时间。每一个列族的单元数据的版本数量都被 HBase 单独维护,默认情况下 HBase 保留 3 个版本数据。
数据模型
表是 HBase 中数据的逻辑组织方式,从用户视角来看,HBase 表的逻辑模型如表 1 所示。HBase 中的一个表有若干行,每行有多个列族,每个列族中包含多个列,而列中的值有多个版本。
行键 | 列族 StuInfo | 列族 Grades | 时间戳 | |||||
---|---|---|---|---|---|---|---|---|
Name | Age | Sex | Class | BigData | Computer | Math | ||
0001 | Tom Green | 18 | Male | 80 | 90 | 85 | T2 | |
0002 | Amy | 19 | 01 | 95 | 89 | T1 | ||
0003 | Allen | 19 | Male | 02 | 90 | 88 | T1 |
表 1 展示的是 HBase 中的学生信息表 Student,有三行记录和两个列族,行键分别为 0001、0002 和 0003,两个列族分别为 Stulnfo 和 Grades,每个列族中含有若干列,如列族 Stulnfo 包括 Name、Age、Sex 和 Class 四列,列族 Grades 包括 BigData、Computer 和 Math 三列。
在 HBase 中,列不是固定的表结构,在创建表时,不需要预先定义列名,可以在插入数据时临时创建。
从表 1 的逻辑模型来看,HBase 表与关系型数据库中的表结构之间似乎没有太大差异,只不过多了列族的概念。但实际上是有很大差别的,关系型数据库中表的结构需要预先定义,如列名及其数据类型和值域等内容。
如果需要添加新列,则需要修改表结构,这会对已有的数据产生很大影响。同时,关系型数据库中的表为每个列预留了存储空间,即表 1 中的空白 Cell 数据在关系型数据库中以“NULL”值占用存储空间。因此,对稀疏数据来说,关系型数据库表中就会产生很多“NULL”值,消耗大量的存储空间。
在 HBase 中,如表 1 中的空白 Cell 在物理上是不占用存储空间的,即不会存储空白的键值对。因此,若一个请求为获取 RowKey 为 0001 在 T2 时间的 Stulnfo:class 值时,其结果为空。类似地,若一个请求为获取 RowKey 为 0002 在 T1 时间的 Grades Computer 值时,其结果也为空。
与面向行存储的关系型数据库不同,HBase 是面向列存储的,且在实际的物理存储中,列族是分开存储的,即表 1 中的学生信息表将被存储为 Stulnfo 和 Grades 两个部分。
MapReduce 是 Hadoop 框架的重要组成部分,是在可扩展的方式下处理超过 TB 级数据的分布式处理的组件。它遵循分而治之的原则,通过将数据拆分到分布式文件系统中的不同机器上, 让服务器能够尽快直接访问和处理数据,最终合并全局结果。
以下图所示网站点击率排行为例,简单介绍 MapReduce 处理数据的过程。
首先将网站的日志文件拆分成大小合理的块,每个服务器使用 map 任务处理一个块。一般来说,拆分过程要尽可能地利用可用的服务器和基础设施。
网站的日志文件是非常大的,处理时划分为大小相等的分片,每台服务器完成一个分片的处理后通过 shuffle,最终通过 reduce 任务将所有结果进行汇总。
HBase 中 MapRecude 包
MapReduce 可用于完成批量数据的分布式处理,而 HBase 中表格的数据是非常庞大的,通常是 GB 或 TB 级,将 MapReduce 和 HBase 结合,能快速完成批量数据的处理。
在应用过程中,HBase 可以作为数据源,即将表中的数据作为 MapReduce 的输入;同时,HBase 可以在 MapReduce 作业结束时接收数据,甚至在 MapReduce 任务过程中使用 HBase 来共享资源。
HBase 支持使用 org.apache.hadoop.hbase.mapieduce 包中的方法来实现 MapReduce 作业,完成 HBase 表中数据的功能如下表所示。
类名 | 描述 |
---|---|
CellCounter | 利用 MapReduce 计算表中单元格的个数 |
Export | 将 HBase 中的表导出序列化文件,存储在 HDFS 中 |
GroupingTableMapper | 从输入记录中抽取列进行组合 |
HFileOutputFormat2 | 写入 HFile 文件 |
HRegionPartitioner<KEY,VALUE> | 将输出的 key 分到指定的 key 分组中。key 是根据已存在的 Region 进行分组的,所以每个 Reducer 拥有一个单独的 Region |
Import | 导入 HDFS 中的序列化文件这些文件是由 Export 导出的 |
ImportTsv | 导入 TSV 文件的数据 |
KeyValueSortReducer | 产生排序的键值 |
LoadIncrementalHFiles | 将 HFileOutputFormat2 的输出导入 HBase 表 |
MultiTableInputFormat | 将表格数据转换为 MapReduce 格式 |
MultiTableOutputFormat | 将 Hadoop 的输出写到一个或多个 HBase 表中 |
TableInputFormat | 将 HBase 表的数据转化为 MapReduce 格式 |
TableOutputFormat<KEY> | 转化 MapReduce 的输出,写入 HBase 中 |
TableSplit | 对表进行拆分 |
WALInputFormat | 作为输入格式用于 WAL |
HBase 还提供了 HBase MapReduce 作业中用到的输入/输出格式化等其他辅助工具,这些都是利用 MapReduce 框架完成的。
读者若要了解更多功能请参考 HBase MapReduce API 官网。
执行 HBase MapReduce 任务
HBase 可以通过执行 hbase/lib 中的 hbase-server-1.2.6.jar 来完成一些简单的 MapReduce 操作。
下面通过 hbase/bin/hbase mapredcp 命令来查看执行 MapReduce 会用到的 jar 文件。
[root@localhost bin]# ./hbase mapredcp/usr/local/hbase/lib/zookeeper-3.4.6.jar:/usr/local/hbase/lib/hbase-client-1.2.6.j ar:/usr/local/hbase/lib/netty-all-4.0.23.Final.jar:/usr/local/hbase/lib/metrics-core-2 .2.0.jar:/usr/local/hbase/lib/protobuf-java—2.5.0.jar:/usr/local/hbase/lib/guava-12.0. 1.jar:/usr/local/hbase/lib/hbase-protocol-1.2.6.jar:/usr/local/hbase/lib/hbase-prefix-tree-1.2.6.jar:/usr/local/hbase/lib/htrace-core-3.1.0-incubating.jar:/usr/local/hbase/ lib/hbase-common-1.2.6.jar:/usr/local/hbase/lib/hbase-hadoop-compat-1.2.6.jar:/usr/loc al/hbase/lib/hbase-server-1.2.6.jar
在执行这些任务之前,需要将这些库绑定到 Hadoop 框架中,确保这些库在任务执行之前已 经可用,通过修改 hadoop/etc/hadoop-env.sh 文件来配置库文件。
在 hadoop-env.sh 中加入以下两行代码:
#hbase的安装路径
export HBASE_HOME=/usr/local/hbase
#加载hbase/lib下的所有库
export HADOOP_CLASSPATH= $HBASE_HOME/lib/*:classpath
完成以上配置后,重新启动 Hadoop 服务,然后在 hadoop 的 bin 目录中执行以下命令:
hbase-server-1.2.6.jar 包提供 CellCounter、export、 import、rowcounter 等类,用户可以直接使用,下图所示为使用 rowcounter 类来统计表中的行数。
Meta 表
有了 Region 标识符,就可以唯一标识每个 Region。为了定位每个 Region 所在的位置,可以构建一张映射表。
映射表的每个条目包含两项内容,一项是 Region 标识符,另一项是 Region 服务器标识。这个条目就表示 Region 和 Region 服务器之间的对应关系,从而就可以使用户知道某个 Region 存储在哪个 Region 服务器中。这个映射表包含了关于 Region 的元数据,因此也被称为“元数据表”,又名“Meta表”。
核心模块是 Region 服务器。Region 服务器由多个 Region 块构成,Region 块中存储一系列连续的数据集。Region 服务器主要构成部分是 HLog 和 Region 块。HLog 记录该 Region 的操作日志。
Region 对象由多个 Store 组成,每个 Store 对应当前分区中的一个列族,每个 Store 管理一块内存,即 MemStoreo 当 MemStore 中的数据达到一定条件时会写入 StoreFile 文件中,因此每个 Store 包含若干个 StoreFile 文件。StoreFile 文件对应 HDFS 中的 HFile 文件。
HBase 群集数据的构成如图所示。
MemStore
当 Region 服务器收到写请求的时候,Region 服务器会将请求转至相应的 Region。数据先被写入 MemStore,当到达一定的阈值时,MemStore 中的数据会被刷新到 HFile 中进行持久化存储。
HBase 将最近接收到的数据缓存在 MemStore 中,在持久化到 HDFS 之前完成排序,再顺序写入 HDFS,为后续数据的检索进行优化。因为 MemStore 缓存的是最近增加的数据,所以也提高了对近期数据的操作速度。
在持久化写入之前,在内存中对行键或单元格进行优化。例如,当数据的 version 被设为 1 时,对某些列族中的一些数据,MemStore 缓存单元格的最新数据,在写入 HFile 时,仅需要保存一个最新的版本。
Store
Store 是 Region 服务器的核心,存储的是同一个列族下的数据,每个 Store 包含一块 MemStore 和 StoreFile( 0 个或多个)。StoreFile 是 HBase 中最小的数据存储单元。
数据写入 MemStore 缓存,当 MemStore 缓存满时,内存中的数据会持久化到磁盘中一个 StoreFile 文件中,随着 StoreFile 文件数量的不断增加,数量达到一个阈值后,就会促使文件合并成一个大的 StoreFile 文件。
由于 StoreFile 文件的不断合并,造成 StoreFile 文件的大小超过一定的阈值,因此,会促使文件进行分裂操作。同时,当前的一个父 Region 会被分成两个子 Region, 父 Region 会下线,新分裂出的两个子 Region 会被 Master 分配到相应的 Regio n服务器上。
Store 的合并和分裂过程如下图所示。
HFile
将 MemStore 内存中的数据写入 StoreFile 文件中,StoreFile 底层是以 HFile 格式保存的。
HFile 的存储格式如下图所示。
HFile 文件是不定长的,长度固定的只有其中的两块:Trailer 和 File Info。Trailer 中有指针指向其他数据块的起始点,File Info 记录了文件的一些 Meta 信息。每个 Data 块的大小可以在创建一个 Table 的时候通过参数指定(默认块大小为 64KB)。每个 Data 块除了开头的 Magic 以外就是由一个键值对拼接而成的,Magic 内容是一些随机数字,用于防止数据损坏。
HFile 里面的每个键值对就是一个简单的 Byte 数组。但是这个 Byte 数组里面包含了很多项, 并且有固定的结构,其具体结构如图所示。
键值对结构以两个固定长度的数值开始,分别表示 Key 的长度和 Value 的长度。紧接着是 Key,Key 以 RowLength 开始,是固定长度的数值,表示 RowKey 的长度;接着是 Row,然后是固定长度的数值 ColumnFamilyLength,表示 Family 的长度;之后是 Family 列族,接着是 Qualifier 列标识符,Key 最后以两个固定长度的数值 Time Stamp 和 Key Type(Put/Delete) 结束。Value部分没有这么复杂的结构,就是纯粹的二进制数据。
HBase 数据写入流程
1) 客户端访问 ZooKeeper,从 Meta 表得到写入数据对应的 Region 信息和相应 的Region 服务器。
2) 客户端访问相应的 Region 服务器,把数据分别写入 HLog 和 MemStore。MemStore 数据容量有限,当达到一个阈值后,则把数据写入磁盘文件 StoreFile 中,在 HLog 文件中写入一个标记,表示 MemStore 缓存中的数据已被写入 StoreFile 中。如果 MemStore 中的数据丢失,则可以从 HLog 上恢复。
3) 当多个 StoreFile 文件达到阈值后,会触发 Store.compact() 将多个 StoreFile 文件合并为一个 大文件。
HBase 数据读取流程
1) 客户端先访问 ZooKeeper,从 Meta 表读取 Region 信息对应的服务器。
2) 客户端向对应 Region 服务器发送读取数据的请求,Region 接收请求后,先从 MemStore 查找数据;如果没有,再到 StoreFile 上读取,然后将数据返回给客户端。
HBase WAL机制
在分布式环境下,用户必须要考虑系统出错的情形,例如,Region服务器发生故障时, MemStore 缓存中还没有被写入文件的数据会全部丢失。因此,HBase 采用 HLog 来保证系统发生故障时能够恢复到正常的状态。
如上图所示,每个 Region 服务器都有一个 HLog 文件,同一个 Region 服务器的 Region 对象共用一个 HLog,HLog 是一种预写日志(Write Ahead Log)文件。
也就是说,用户更新数据必须先被记入日志后才能写入 MemStore 缓存,当缓存内容对应的日志已经被写入磁盘后,即日志写成功后,缓存的内容才会被写入磁盘。
ZooKeeper 会实时监测每个 Region 服务器的状态,当某个 Region 服务器发生故障时,ZooKeeper 会通知 Master,Master 首先会处理该故障 Region 服务器上遗留的 HLog 文件。
由于一个 Region 服务器上可能会维护着多个 Region 对象,这些 Region 对象共用一个 HLog 文件,因此这个遗留的 HLog 文件中包含了来自多个 Region 对象的日志记录。
系统会根据每条日志记录所属的 Region 对象对 HLog 数据进行拆分,并分别存放到相应 Region 对象的目录下。再将失效的 Region 重新分配到可用的 Region 服务器中,并在可用的 Region 服务器中重新进行日志记录中的各种操作, 把日志记录中的数据写入 MemStore 然后刷新到磁盘的 StoreFile 文件中,完成数据恢复。
在 HBase 系统中每个 Region 服务器只需要一个 HLog 文件,所有 Region 对象共用一个 HLog,而不是每个 Region 使用一个 HLog。在这种 Region 对象共用一个 HLog 的方式中,多个 Region 对象在进行更新操作需要修改日志时,只需要不断地把日志记录追加到单个日志文件中,而不需要同时打开、写入多个日志文件中,因此可以减少磁盘寻址次数,提高对表的写操作性能。
HBase Region管理(拆分+合并+负载均衡)
HFile 合并
每个 RegionServer 包含多个 Region,而每个 Region 又对应多个 Store,每一个 Store 对应表中一个列族的存储,且每个 Store 由一个 MemStore 和多个 StoreFile 文件组成。
StoreFile 在底层文件系统中由 HFile 实现,也可以把 Store 看作由一个 MemStore 和多个 HFile 文件组成。MemStore 充当内存写缓存,默认大小 64MB,当 MemStore 超过阈值时,MemStore 中的数据会刷新到一个新的 HFile 文件中来持久化存储。
久而久之,每个 Store 中的 HFile 文件会越来越多,I/O 操作的速度也随之变慢,读写也会延时,导致慢操作。因此,需要对 HFile 文件进行合并,让文件更紧凑,让系统更有效率。
HFile 的合并分为两种类型,分别是 Minor 合并和 Major 合并。这两种合并都发生在 Stow 内部,不是 Region 的合并,如下图所示。
图 1:Minor 合并与 Major 合并
Minor 合并
Minor 合并是把多个小 HFile 合并生成一个大的 HFile。
执行合并时,HBase 读出已有的多个 HFile 的内容,把记录写入一个新文件中。然后把新文件设置为激活状态,并标记旧文件为删除。
在 Minor 合并中,这些标记为删除的旧文件是没有被移除的,仍然会出现在 HFile 中,只有在进行 Major 合并时才会移除这些旧文件。对需要进行 Minor 合并的文件的选择是触发式的,当达到触发条件才会进行 Minor 合并,而触发条件有很多,例如, 在将 MemStore 的数据刷新到 HFile 时会申请对 Store下符合条件的 HFile 进行合并,或者定期对 Store 内的 HFile 进行合并。
另外对选择合并的 HFile 也是有条件的,如下表所示。
参数名 | 配置项 | 默认值 | 备注 |
---|---|---|---|
minFileToCompact | hbase.hstore.compaction.min | 3 | 至少需要三个满足条件的 HFile 才启动合并 |
minFileToCompact | hbase.hstore.compaction.max | 10 | 一次合并最多选择 10 个 |
maxCompactSize | hbase.hstore.compaction.max.size | Long.MAX_VALUE | HFile 大于此值时被排除合并,避免对大文件的合并 |
minCompactSize | hbase.hstore.compaction.min.size | MemStoreFlushSize | HFile 小于 MemStore 的默认值时被加入合并队列 |
在执行 Minor 合并时,系统会根据上述配置参数选择合适的 HFile 进行合并。Minor 合并对 HBase 的性能是有轻微影响的,因此,合并的 HFile 数量是有限的,默认最多为 10 个。
Major 合并
Major 合并针对的是给定 Region 的一个列族的所有 HFile,如图 1 所示。它将 Store 中的所有 HFile 合并成一个大文件,有时也会对整个表的同一列族的 HFile 进行合并,这是一个耗时和耗费资源的操作,会影响集群性能。
一般情况下都是做 Minor 合并,不少集群是禁止 Major 合并的,只有在集群负载较小时进行手动 Major 合并操作,或者配置 Major 合并周期,默认为 7 天。另外,Major 合并时会清理 Minor 合并中被标记为删除的 HFile。
Region 拆分
Region 拆分是 HBase 能够拥有良好扩展性的最重要因素。一旦 Region 的负载过大或者超过阈值时,它就会被分裂成两个新的 Region,如图 2 所示。
图 2:Region 拆分
这个过程是由 RegionServer 完成的,其拆分流程如下。
- 将需要拆分的 Region下线,阻止所有对该 Region 的客户端请求,Master 会检测到 Region 的状态为 SPLITTING。
- 将一个 Region 拆分成两个子 Region,先在父 Region下建立两个引用文件,分别指向 Region 的首行和末行,这时两个引用文件并不会从父 Region 中复制数据。
- 之后在 HDFS 上建立两个子 Region 的目录,分别复制上一步建立的引用文件,每个子 Region 分别占父 Region 的一半数据。复制登录完成后删除两个引用文件。
- 完成子 Region 创建后,向 Meta 表发送新产生的 Region 的元数据信息。
- 将 Region 的拆分信息更新到 HMaster,并且每个 Region 进入可用状态。
以上是 Region 的拆分过程,那么,Region 在什么时候才会触发拆分呢?常用的拆分策略如下表所示
策略 | 原理 | 描述 |
---|---|---|
ConstantSizeRegionSplitPolicy | Region 中最大 Store 的大小大于设置阈值(hbase.hregion.max.filesize)之后才会触发拆分。 拆分策略原理相同,只是阈值的设置不同 |
拆分策略对于大表和小表没有明显的区分。阈值设置较大时小表可能不会触发分裂。如果阈值设置较小,大表就会在整个集群产生大量的 Region,影响整个集群的性能 |
IncreasingToUpper BoundRegionSplitPolicy |
阈值在一定条件下不断调整,调整规则与 Region 所属表在当前 Region 服务器上的 Region 个数有关系 | 很多小表会在大集群中产生大量小 Region,分散在整个集群中 |
SteppingSplitPolicy | 阈值可变。如果 Region 个数等于 1,则拆分阈值为 flushsize × 2;否则为 MaxRegionFileSize | 小表不会再产生大量的小 Region,而是适可而止 |
DisabledRegionSplitPolicy | 关闭策略,手动拆分 | 可控制拆分时间,选择集群空闲时间 |
上表中列举的拆分策略中,拆分点的定义是一致的,即当 Region 中最大 Store 的大小大于设置阈值之后才会触发拆分。而在不同策略中,阈值的定义是不同的,且对集群中 Region 的分布有很大的影响。
Region 合并
从 Region 的拆分过程中可以看到,随着表的增大,Region 的数量也越来越大。如果有很多 Region,它们中 MemStore 也过多,会频繁出现数据从内存被刷新到 HFile 的操作,从而会对用户请求产生较大的影响,可能阻塞该 Region 服务器上的更新操作。过多的 Region 会增加 ZooKeeper 的负担。
因此,当 Region 服务器中的 Region 数量到达阈值时,Region 服务器就会发起 Region 合并,其合并过程如下。
- 客户端发起 Region 合并处理,并发送 Region 合并请求给 Master。
- Master 在 Region 服务器上把 Region 移到一起,并发起一个 Region 合并操作的请求。
- Region 服务器将准备合并的 Region下线,然后进行合并。
- 从 Meta 表删除被合并的 Region 元数据,新的合并了的 Region 的元数据被更新写入 Meta 表中。
- 合并的 Region 被设置为上线状态并接受访问,同时更新 Region 信息到 Master。
Region 负载均衡
当 Region 分裂之后,Region 服务器之间的 Region 数量差距变大时,Master 便会执行负载均衡来调整部分 Region 的位置,使每个 Region 服务器的 Region 数量保持在合理范围之内,负载均衡会引起 Region 的重新定位,使涉及的 Region 不具备数据本地性。
Region 的负载均衡由 Master 来完成,Master 有一个内置的负载均衡器,在默认情况下,均衡器每 5 分钟运行一次,用户可以配置。负载均衡操作分为两步进行:首先生成负载均衡计划表, 然后按照计划表执行 Region 的分配。
执行负载均衡前要明确,在以下几种情况时,Master 是不会执行负载均衡的。
- 均衡负载开关关闭。
- Master 没有初始化。
- 当前有 Region 处于拆分状态。
- 当前集群中有 Region 服务器出现故障。
Master 内部使用一套集群负载评分的算法,来评估 HBase 某一个表的 Region 是否需要进行重新分配。这套算法分别从 Region 服务器中 Region 的数目、表的 Region 数、MenStore 大小、 StoreFile 大小、数据本地性等几个维度来对集群进行评分,评分越低代表集群的负载越合理。
确定需要负载均衡后,再根据不同策略选择 Region 进行分配,负载均衡策略有三种,如下表所示。
策略 | 原理 |
---|---|
RandomRegionPicker | 随机选出两个 Region 服务器下的 Region 进行交换 |
LoadPicker | 获取 Region 数目最多或最少的两个 Region 服务器,使两个 Region 服务器最终的 Region 数目更加平均 |
LocalityBasedPicker | 选择本地性最强的 Region |
根据上述策略选择分配 Region 后再继续对整个表的所有 Region 进行评分,如果依然未达到标准,循环执行上述操作直至整个集群达到负载均衡的状态。
HBase集群的管理(非常全面)
运维管理
在集群运行时,有些操作任务是必需的,包括移除和增加节点。
移除 Region 服务器节点
当集群由于升级或更换硬件等原因需要在单台机器上停止守护进程时,需要确保集群的其他 部分正常工作,并且确保从客户端应用来看停用时间最短。满足此条件必须把这台 Region 服务器服务的 Region 主动转移到其他 Region 服务器上,而不是让 HBase 被动地对此 Region 服务器的下线进行反应。
用户可以在指定节点的 HBase 目录下使用hbase-damon.sh stop
命令来停止集群中的一个 Region 服务器。执行此命令后,Region 服务器先将所有 Region 关闭,然后再把自己的进程停止,Region 服务器在 ZooKeeper 中对应的临时节点将会过期。
Master 检测到 Region 服务器停止服务后,将此 Region 服务器上的 Region 重新分配到其他机器上。这种停止服务器方法的坏处是,Region 会下线一段时间,时间长度由 ZooKeeper 超时时间来决定,而且会影响集群性能,同时整个集群系统会经历一次可用性的轻微降级。
HBase 也提供了脚本来主动转移 Region 到其他 Region 服务器,然后卸掉下线的 Region 服务器,这样会让整个过程更加安全。在 HBase 的 bin 目录下提供了 gracefiil_stop.sh 脚本,可以实现这种主动移除节点的功能。
此脚本停止一个 Region 服务器的过程如下。
- 关闭 Region 均衡器。
- 从需要停止的 Region 服务器上移出 Region,并随机把它们分配给集群中其他服务器。
- 停止 Region 服务器进程。
graceful_stop.sh 脚本会把 Region 从对应服务器上一个个移出以减少抖动,并且会在移动下一 个 Region 前先检测新服务器上的 Region 是否已经部署好。
此脚本关闭了需要停止的 Region 服务器,Master 会检测到停止服务的 Region 服务器,但此时 Master 无须再来转移 Region。同时,由于 Region 服务器关闭时已经没有 Region 了,所以不会执行 WAL 拆分的相关操作。
增加 Region 服务器节点
随着应用系统需求的增长,整个 HBase 集群需要进行扩展,这时就需要向 HBase 集群中增加 一个节点。添加一个新的 Region 服务器是运行集群的常用操作,首先需要修改 conf 目录下的 Region 服务器文件,然后将此文件复制到集群中的所有机器上,这样使用启动脚本就能够添加新的服务器。
HBase 底层是以 HDFS 来存储数据的,一般部署 HBase 集群时,HDFS 的 DataNode 和 HBase 的 Region 服务器位于同一台物理机上。因此,向 HBase 集群增加一个 Region 服务器之前,需要向 HDFS 里增加 DataNode。
等待 DataNode 进程启动并加入 HDFS 集群后,再启动 HBase 的 Region 服务器进程。启动新增节点上的 Region 服务器可以使用命令 hbase-damon.sh start,启动成功后,用户可以在 Master 用户界面看到此节点。如果需要重新均衡分配每个节点上的 Region,则可使用 HBase 的负载均衡功能。
增加 Master 备份节点
为了增加 HBase 集群的可用性,可以为 HBase 增加多个备份 Master。当 Master 出现故障后, 备份 Master 可以自动接管整个 HBase 的集群。
配置备份 Master 的方式是在 HBase 的 conf 下增加文件 backup-masters,然后通过 hbase-damon.sh start 命令启动。
Master 进程使用 ZooKeeper 来决定哪一个是当前活动的进程。当集群启动时,所
以上是关于HBase-是什么的主要内容,如果未能解决你的问题,请参考以下文章