分布式存储系统Hbase

分布式存储系统Hbase

HBase是google 论文 BigTable的一个实现。

Bigtable 是一个稀疏的、分布式的、持久的多维排序、面向列存储的Map

该(Map)映射由行键、列键和时间戳索引;映射中的每个值都是一个未解释的字节数组。

1.面向列存储

1.1 面向行存储的数据库

数据库的表中的列是固定的,不能动态增加字段。数据库必须把这个二维的表存储在一系列一维的字节中,由操作系统写道内存或磁盘中。如果没有索引的查询会消耗大量I/O,建立索引和视图需要花费大量的时间和资源、面向查询的需求,数据库必须被大量膨胀才能满足性能需求。

1.2 面向列存储的数据库

列存储以列数据集合为单位,称为列族(Column Family)。读取数据时列数据集中的一段或者全部数据,写入时,一行记录被拆分成多列,每一列数据追加到对应列的末尾处。

1.3 行 列存储对比

写入:行存储写入是一次完成的,列存储由于需要把一行记录拆分成单列保存,写入次数明显比行存储要多,再加上磁头再盘片上的移动和定位,实际消耗的时间也更大。行存储在写入上占很大优势

数据修改:数据修改也是一次写入的过程,不同的是在磁盘指定位置的记录做删除和重新写入。列存储是将磁盘定位到多个列上分别写入,所以行存储仍占优势。

数据读取:行存储通常是将一行数据完全取出(所有字段),就会存在冗余列,出于缩短处理时间的考虑,消除几余列的过程通常是在内存中进行的。列存储每次读取的数据是集合的一段或者全部,如果读取多列时,就需要移动磁头,再次定位到下一列的位置继续读取。

列存储的每一列数据类型是同质的,不存在二义性问题,也就是说一列数据的数据类型都是相同的,因此数据解析将会十分容易。相比之下,行存储则要复杂得多,因为在一行记录中保存了多种类型的数据,数据解析需要在多种数据类型之间频繁转换,这个操作很消耗 CPU,增加了解析的时间。所以,列存储的解析过程更有利于分析大数据。

对于行 列存储的改进

行存储的改进。减少冗余数据首先是用户在定义数据时避免冗余列的产生,其次是优化数据存储记录结构,保证从磁盘读出的数据进入内存后能够被快速分解,消除冗余列。

列存储的改进。在计算机上安装多块硬盘,以多线程并行的方式读写它们。多块硬盘并行工作可以减少磁盘读写竞用,这种方式对提高处理效率优势十分明显。

这两种存储方案还有一个共同改进的地方:频繁的小量的数据写入对磁盘影响很大,更好的解决办法是将数据在内存中暂时保存并整理,达到一定数量后一次性写入磁盘,这样消耗时间更少一些。

如果首要考虑是数据的完整性和可靠性,那么行存储是不二选择,列存储只有在增加磁盘并改进软件设计后才能接近这样的目标。如果以保存数据为主,行存储的写入性能比列存储高很多。在需要频繁读取单列集合数据的应用中,列存储是最合适的。

row_column_store_comprasion1

2. HBase的使用场景

当数据量越来越大,关系型数据库在服务响应和时效性上会越来越慢,这就出现了读写分离策略,通过一个Master 专门负责写操作,多个 Slave 负责读操作,服务器成本倍增。随着压力增加,Master 开始承受不住,这时会采用分库机制,把关联不大的数据分开部署,一些join 查询不能使用,需要借助中间层。随着数据量的进一步增加,一个表的记录越来越多,查询就变得很慢,于是又得搞分表,比如按 ID 取模分成多个表以减少单个表的记录数。而采用HBase 就简单了,只需要加机器即可,HBase 会自动水平切分扩展,跟 Hadoop 的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性能 (MapReduce)。

HBase 作为常用的大数据存放工具,基本解决以下三大类场景
在这里插入图片描述

1.平台类
数据通常是细水长流,累加到已有数据库以备将来使用,例如分析、处理和服务。许多HBase 使用场景属于这个类别一一使用 HBase 作为数据存储,捕获来自于各种数据源的增量数据。

2.内容服务类

此类主要是面向各个业务系统。这里的用户不仅仅指人,也包括物,比如购物收藏夹交易数据、聊天记录等。这里使用比较直接,就直接存放在 HBase 中,再读取。难度就是需要支持千万级别的并发写访问及读取,需要解决服务质量的问题。这种应用场景通常业务简单不需要关系型数据库中的很多特性(如交叉列、交叉表、事务、连接等)。

3.信息展示类
通过 HBase 的高存储、高吞吐等特性,可以将人们感兴趣的信息快速展现出来。比如阿里巴巴的天猫双十一大屏、Facebook 的短信系统。

HBase 并不是适合所有的场景。首先,确信有足够多数据,如果有上亿或上千亿行数据HBase 是很好的选择。如果只有上千或上百万行,则用传统的RDBMS可能是更好的选择。因为所有数据如果只需要在一两个节点上进行存储,会导致集群其他节点闲置。其次,确信可以不依赖于 RDBMS的额外特性,例如列数据类型、第二索引、事务、高级查询语言等。最后确保有足够的硬件。因为HDFS 在小于5个数据节点时,基本上体现不出来它的优势。

3. HBase的模型与架构

3.1 HBase的相关概念

0.Name Space 命名空间

类似于关系型数据库的 database 概念,每个命名空间下有多个表。HBase 两 个自带的命名空间,分别是 hbase 和 default,hbase 中存放的是 HBase 内置的表,default

1.Table(表)
HBase 会将数据组织进一张张的表里面,但需要注意的是表名必须是能用在文件路径里的合法名字,因为HBase 的表是映射成HDFS上面的文件。一个HBase表由多行组成。

2.Row(行)

在表里面,每一行代表着一个数据对象,每一行都是以一个行键(Row Key)来进行唯一标识的。HBase 中的行里面包含一个 Key 和一个或者多个包含值的列。行键并没有什么特定的数据类型,以二进制的字节来存储。Row Key 只能由一个字段组成而不能由多个字段组合组成,HBase对所有行按照 Row Key升序排序,在设计 Row Key 时将经常一起读取的行放到一起。因为这个原因,Row Key 的设计就显得非常重要。数据的存储目标是相近的数据存储到一起,一种常用的行的 Key 的格式是网站域名。如果行的 Key 是域名,应该将域名进行反转 (org.apache.www、org.apache.mailorgapache,jira) 再存储。这样的话,所有 apache 域名将会存储在一起,好过基于子域名的首字母分散在各处。
与NoSQL数据库一样,Row Key 是用来检索记录的主键。访问 HBase 表中的行只有三种方式:通过单个Row Key访问、通过 Row Key 的 Range、全表扫描。Row Key 可以是任意字符串(最大长度是64KB,实际应用中长度一般为 10B~100B),在HBase 内部,Row Key保存为字节数组。

3.Column (列)
HBase 中的列包含分隔开的列族和列的限定符

4.Column Family(列族)

列族包含一个或者多个相关列,列族是表的 Schemm(装模式》的一部分,必须在使用表之前定义。。HBase 表中的每个列都归属于某个列族,列都以列族作为前缀。每一个列族都拥有一系列的存储属性,例如值是否缓存在内存中、数据是否要压缩或者它的行 Key 是否要加密等。表格中的每一行拥有相同的列族,尽管一个给定的行可能没有存储任何数据在一个给定的列族中。

每个列族中可以存放很多列,每个列族中的列数量可以不同,每行都可以动态地增加和减少列。列是不需要静态定义的,HBase 对列数没有限制,可以达到上百万个,但是列族的人数有限制,通常只有几个。在具体实现上,一张表的不同列族是分开独立存放的。HBase的问控制、磁盘和内存的使用统计等都是在列族层面进行的。

5.Column Oualifier(列标识符)

列的标识符是列族中数据的索引。例如给定了一个列族 content,那么标识符可能是content;html,也可以是content;pdf。列族在创建表格时是确定的,但是列的标识符是动态的并且行与行之间的差别也可能是非常大的。列族中的数据通过列标识来进行映射,其实这里大家可以不用拘泥于“列”这个概念,也可以理解为一个键值对,Column Qualifier 就是Key。列标识也没有特定的数据类型,以二进制字节来存储。

在定义 HBase 表的时候需要提前设置好列族,表中所有的列都需要组织在列族里面,列族一旦确定后就不能轻易修改,因为它会影响到 HBase 真实的物理存储结构,但是列族中的列标识以及其对应的值可以动态增删。表中的每一行都有相同的列族,但是不需要每一行的列族里都有一致的列标识和值,所以说是一种稀疏的表结构,这样可以在一定程度上避免数据的几余。例如frowl,userInfo: telephone -> 137XXXXX010和row2,userInfo: address-> Beijing);行1和行2都有同一个列族userInfo,但是行1中的列族只有列标识一-电话号码,而行2中的列族中只有列标识一-地址。

6.Cell(单元格)

单元格是由行、列族、列标识符、值和代表值版本的时间戳组成的。每个 Cell 都保存着同一份数据的多个版本(默认是三个),并按照时间倒序排序,即最新的数据排在最前面。单元数据也没有特定的数据类型,以二进制字节来存储。

7.Timestamp(时间戳)

时间戳是写在值旁边的一个用于区分值的版本的数据。默认情况下,每一个单元中的数据插入时都会用时间戳来进行版本标识。读取单元数据时,如果时间戳没有被指定,则默认返回最新的数据,写入新的单元数据时,如果没有设置时间戳,默认使用当前时间。每一个列”的单元数据的版本数量都被 HBase 单独维护,默认情况下 HBase保留三个版本数据。

HBase 把同一个列族里面的数据存储在同一个目录下,并且 HBase 的写操作是锁行的,
每一行都是一个原子元素,可以加锁。HBase所有数据库的更新都有一个时间戳标记,每个更新都是一个新的版本,HBase 会保留一定数量的版本,这个值是可以设定的,客户端可以选择获取距离某个时间点最近的版本单元的值,或者一次获取所有版本单元的值。

3.2 HBase 逻辑模型

我们可以将一个表想象成一个大的映射关系,通过行键、行键 + 时间戳或行键 + 列(列族:列修饰符)就可以定位特定数据。HBase 是稀疏存储数据的,因此某些列可以是空白的。HBase的逻辑模型如表2-1 所示。

在这里插入图片描述

从表可以看出,表中有"databasesoftware.www"和"c.software.www“两行数据,并且有anchor和info两个列族,在"databasesoftware.www"中,列族anchor 有三条数据,列族info有两条数据;在"c.software.www"中,列族anchor有两条数据,列族info有一条数据,每一条数据对应的时间戳都用数字来表示,编号越大表示数据越旧,相反表示数据越新。

3.3 Hbase 物理模型

虽然从逻辑模型来看每个表格是由很多行组成的,但是在物理存储方面,它是按照列来保存的。

在这里插入图片描述

需要注意的是,在逻辑模型上面有些列是空白的,这样的列实际上并不会被存储,当请求这些空白的单元格时会返回 null 值。如果在查询的时候不提供时间戳,那么会返回距离在最近的那一个版本的数据,因为在存储的时候数据会按照时间戳来排序。

3.3 HBase的特定

非关系型数据库严格意义上不是一种数据库,而是一种数据结构化存储方法的集合HBase 作为一个典型的非关系型数据库,仅支持单行事务,通过不断增加集群中的节点数据来增加计算能力,其具有以下特点:
(1) 容量巨大。
HBase 在纵向和横向上支持大数据量存储,一个表中可以有百亿行、百万列。
(2)面向列。
HBase 是面向列(族)的存储和权限控制,列(族)独立检索。列式存储是指其数据在表中按照某列存储,在查询少数几个字段的时候能大大减少读取的数据量。
(3)稀疏性。
HBase 是基于列存储的,不存储值为空的列,因此 HBase 的表是稀疏的,这样可以节存储空间,增加数据存储量。

(4)数据多版本

每个单元中的数据可以有多个版本,默认情况下版本号是数据插入时的时间戳,用户可以根据需要查询历史版本数据。(5)可扩展性。
HBase 数据文件存储在HDFS 上,由于HDFS 具有动态增加节点的特性,因此HBase 也可以很容易实现集群扩展。
(6) 高可靠性。
WAL(Write Ahead Log,预写日志)机制保证了数据写入时不会因集群故障而导致写入数据丢失;HBase位于HDFS 上,而HDFS也有数据备份功能:同时HBase引入 ZooKeepcr避免 Master出现单点故障。
(7)高性能。
传统的关系型数据库是基于行的,在进行查找的时候是按行遍历数据,不管某一列数据是否需要都会进行遍历,而基于列的数据库会将每列单独存放,当查找一个数量较小的列的时候其查找速度很快。HBase 采用了读写缓存机制,具有高并发快速读写能力;采用主键定位数据机制,使其查询响应在毫秒级。
(8) 数据类型单一。
HBase 中的数据都是字符串,没有其他类型

3.5 HBase的基本系统架构

在这里插入图片描述

HBase 具有容量大、面向列、稀疏性、多版本、可扩展性和高可靠性等HBase 分布式存储系统应用特点。HBase 采用主从分布式架构,由 Client、ZooKeeper、HMaster、HRegionServer 和 HRegion组件构成。Client 包含访间 HBase 的接口,ZooKeeper 负责提供稳定可靠的协同服务,HMaster负责表和 HRegion 的分配工作,HRegionServer 负责 HRegion 的启动和维护,HRegion 响应来自Client的请求。

4. HBase的系统架构

4.0 Zookeeper

ZooKeeper 的引入使得 Master 不再是单点故障。通过选举,保证任何时候集群中只有个处于Active状态的Master,HMaster 和 HRegionServer启动时会向ZooKeeper注册。ZooKeepe的主要作用如下
(1) 存储所有 HRegion 的寻址入口,从而完成数据的读写操作。
(2) 实时监控HRegionServer 的上线和下线信息,并通知给 HMaster。
(3) 存放整个 HBase 集群的元数据以及集群的状态信息。

zookeeper

4.1 HMaster

hmaster

(1 )管理用户对表的增、删、改、查操作
(2) 为HRegionServer 分配 HRegion。
(3) 管理 HRegionServer 的负载均衡,调整 HRegion 分布(4)发现失效的 HRegionServer 并重新分配其上的 HRegion(5)当HRegion 切分后,负责两个新生成HRegion 的分配
(6) 处理元数据的更新请求。

4.2 HRegionServer

hregionserver
4.2.1 WAL in HRegionServer

分布式系统环境中,无法避免系统出错或者死机,因此一旦 HRegionServer 意外退出,MemStore中的内存数据将会丢失,这就需要引入 WAL。WAL即 Write Ahead Log,在早期版本中称为HLog,它是 HDFS上的一个文件,如其字所表示的,所有写操作都会先保证将数据写入这个Log 文件后,才会真正更新到 MemStore,最后写入 HFile 中。每个HRegionServer 维护一个 HLog,而不是每个 HRegion 一个。这样不同HRegion(来自不同表)的日志会混在一起,这样做的目的是不断追加单个文件,相对于同时写多个文件而言,可以减少磁盘寻址次数,因此可以提高对表的写性能。带来的麻烦是,如果一台HRegionServer 下线,为了恢复其上的 HRegion,需要将 HRegionServer 上的 HLog进
行拆分,然后分发到其他 HRegionServer 上进行恢复。

4.2.2 MemStore in HRegionServer

MemStore 是一个写缓存(In Memory Sorted Buffer),所有要写的数据在完成 WAL日志写后会写入MemStore中,由MemStore根据一定的算法将数据 Flush 到底层HDFS文件中(HFile).通常在每个HStore 中都有一个MemStore,即它是HRegion 中的 Column Family 对应的一个实例。它的排列顺序以 Row Key、Column Family、Column 的顺序以及 Timestamp 的倒序

memstore
4.2.3 BlockCache in HRegionServer

客户的读请求会先到 MemStore 中查数据,若查不到就到 BlockCache 中查,再查不到会从磁盘上读,并把读入的数据同时放入 BlockCache。我们知道缓存有三种不同的更新策略分别是 FIFO(先入先出)、LRU(最近最少使用)和LFU(最近最不常使用),HBase 的 BlockCach采用的是LRU策略。当BlockCache 的大小达到上限 (heapsize* hfile.block.cachesize* 0.85)后,会触发缓存淘汰机制,将最老的一批数据淘汰掉。一个HRegionServer 上有一个 BlockCach和多个MemStore。

HBase RegionServer 包含三个级别的 Block 优先级队列:
(1) Single 队列:如果一个 Block 第一次被访问,则放在这一优先级队列中。
(2)Multi 队列:如果一个 Block 被多次访问,则从 Single 队列移到 Muti 队列中。成。(3)InMemory 队列:如果一个 Block 是 InMemory 的,则放到这个队列中。将 Cache分设置,级思想的好处在于:首先,通过IMemory 类型 Cache,可以有选择地将 in-memory 的列族放越多,到 RegionServer 内存中,例如 Meta 元数据信息;其次,通过区分 Sigle 和 Multi类型 Cacht可以防止由于 Scan 操作带来的 Cache 频繁颠簸,将最少使用的 Block 加入到淘汰算法中。

4.2.4 HFile in HRegionServer

HBase 的数据以 KeyValue (Cell) 的形式顺序存储在 HFile 中,在 MemStore 的 Flush程中生成HFile,在HFile中的数据是按 Row Key、Column Family、Colum 排序,对相同Cell(即这三个值都一样)则按 Timestamp 倒序排列。由于 MemStore 中存的 Cell 遵循相的排列顺序,因而 Flush 过程是顺序写,因此效率很高。

4.2.5 HRegionServer的恢复

当一台 HRegionServer 死机时,由于它不再发送心跳包给 ZooKeeper 而被监测到,此时ZooKeeper 会通知 HMaster,HMaster 会检测到哪台 HRegionServer 死机,它将死机的HRegionServer 中的 HRegion 重新分配给其他的 HRegionServer,同时 HMaster 会把死机的HRegionServer 相关的 WAL 分分配给相应的HRegionServer (将拆分出的WAL 文件写入对应 HRegionServer 的 WAL 目录中,并写入相应的 DataNode),从而使这些 HReionServer 可滚动分到的WAL来重建MemStore。

4.3 Regin

HBase 中的每张表都通过行键按照一定的范围被分割成多个 HRegion (子表)。每个HRegion都记录了它的起始 Row Key 和结束 Row Key,其中第一个HRegion 的起始 Row Ke为空,最后一个HRegion 的结束 Row Key 为空。由于 Row Key 是有序的,因而 Client可以通过HMaster 快速地定位到 Row Key 位于哪个 HRegion 中。

HRegion负责和Client 通信,实现数据的读写。HRegion 是HBase 中分布式存储和负载均衡的最小单元,不同的HRegion 分布到不同的HRegionServer 上,每个HRegion 大小也都不-样。HRegion 虽然是分布式存储的最小单元,但并不是存储的最小单元。HRegion 由一个或者多个Store组成,每个Store保存一个列族,因此一个HRegion中有多少个列族就有多少个Store。每个 Store 又由一个 MemStore 和0 至多个 StoreFile 组成。MemStore 存储在内存中,一个StoreFile对应一个HFile 文件。HFile 存储在 HDFS 上,在 HFile 中的数据是按 Row Key、ColumnFamily、Column 排序,对相同的单元格 (即这三个值都一样)则按时间戳倒序排列。

4.3.1 HRegion 分配

任何时刻,一个HRegion 只能分配给一个 HRegionServer。HMaster 记录了当前有哪些可用的 HRegionServer,以及当前哪些 HRegion 分配给了哪些 HRegionServer,哪些 HRegion还没有分配。当存在未分配的 HRegion,并且有一个 HRegionServer 上有可用空间时,HMaster就给这个HRegionServer 发送一个装载请求,把 HRegion 分配给这个 HRegionServer。HRegionServer得到请求后,就开始对此HRegion 提供服务。

4.3.2 HRegion Split

最初,一个 Table 只有一个HRegion。随着数据写入增加,如果一个HRegion 到达一定的大小,就需要 Split 成两个HRegion,其大小由 hbase.hregionmax.filesize指定,默认为10GB。当Split 时,两个新的 HRegion 会在同一个 HRegionServer 中创建,它们各自包含父 HRegion一半的数据。当 Split 完成后,父HRegion 会下线,而新的两个子 HRegion 会向 HMaster 注册上线。出于负载均衡的考虑,这两个新的 HRegion 可能会被 HMaster 分配到其他的HRegionServer中,此时会引起有些HRegionServer处理的数据在其他节点上,直到下一次MajorCompaction将数据从远端的节点移动到本地节点。

4.3.3 HRegion Compact

当文件达到一定数量(默认3)时就会触发 Compact 操作,将多个 HFile 文件合并成一个HFile 文件,将多个StoreFile 文件合并成一个 StoreFile文件,而大文件恰恰又是HDFS 所擅长。合并过程中会进行版本合并和数据删除,因此可以看出 HBase 只是增加数据,所有的更新和删除操作都是在合并阶段做的,客户端写操作只需要进入到内存即可立即返回,从而保证
表在HRegion 中是按照 Row Key来排序的,并且一个Row Key 所对应的行只会存储在一HBase 读写的高性能。个HRegion 中,而一个列族占用一个StoreFile,因此当切分的时候一个HRegion中的 StoreFile文件大小各不相同。甚至有可能出现一个列族已经有 1000万行,而另外一个才100行的情况当HRegion 分割的时候,会导致 100 行的列会同样分布到多个HRegion 中,所以一般建议不
要设置多个列族。当合并的时候,会将 HRegion 中的同一列族对应的 StoreFile 合并,又会逐渐形成越来越大的 StoreFile,当单个 StoreFile 大小超过一定闽值后,又会触发所在 HRegion 的 Split 操作也就是说 HRegion 再循环地执行 Split Compact,但并不是无限地执行下去,一般来说单个StoreFile 文件大小达到6.2GB 时就会停止 Split,避免在 HRegion过大时频繁 Split 而影响 HBase的性能。

5 HBase的读写删除操作

5.1 HBase 写流程

在这里插入图片描述

(1)首先访问 zookeeper,获取 hbase:meta 表位于哪个 Region Server; (2)访问对应的 Region Server,获取 hbase:meta 表,将其缓存到连接中,作为连接属 性 MetaCache,由于 Meta 表格具有一定的数据量,导致了创建连接比较慢; 之后使用创建的连接获取 Table,这是一个轻量级的连接,只有在第一次创建的时候会 检查表格是否存在访问 RegionServer,之后在获取 Table 时不会访问 RegionServer; (3)调用Table的put方法写入数据,此时还需要解析RowKey,对照缓存的MetaCache, 查看具体写入的位置有哪个 RegionServer; (4)将数据顺序写入(追加)到 WAL,此处写入是直接落盘的,并设置专门的线程控 制 WAL 预写日志的滚动(类似 Flume)(5)根据写入命令的 RowKey 和 ColumnFamily 查看具体写入到哪个 MemStory,并且 在 MemStory 中排序; (6)向客户端发送 ack; (7 )等达到 MemStore 的刷写时机后,将数据刷写到对应的 story 中

5.2 HBase 读流程

(1)创建 Table 对象发送 get 请求。 (2)优先访问 Block Cache,查找是否之前读取过,并且可以读取 HFile 的索引信息和 布隆过滤器。 (3)不管读缓存中是否已经有数据了(可能已经过期了),都需要再次读取写缓存和 store 中的文件。 (4)最终将所有读取到的数据合并版本,按照 get 的要求返回即可。

6. HBase的优化

注意:HBase 中对 Row Key采用了MD5加密处理,而 Row Key是唯一索引,对索引加密之后如何进行查询?实际使用中用作索引的数值可能是有规律递增的,直接用这个作 RowKey 会使得新插入的大量数据很有可能被插入到同一个 Region 上,而其他 Region 空闲,这样读和写都产生了热点,影响读写效率。对 Row Key 使用 MDS 或者其他Hash做散列之后再和原来的 Row Key组合作为实际的 Row Key,这样在持续产生数据的时候 Row Key会被散列到不同的 Region上,有效避免了热点问题,可见HBase 使用MD5 并不是为了加密。在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值