HBase概述 第 5 章 HBase分布式数据库 HBase是一个高可靠性、高性能、基于列进行数据存储的分布式数据 库,可以随着存储数据的不断增加而实时、动态地增加列。本章主要介绍 HBase系统架构和数据访问流程、HBase数据表、HBase安装与配置、HBase 的Shel 操作、HBase的JavaAPI操作、HBase案例实战和利用Python操作 HBase。 5.1 HBase概述 5.1 HBse的技术特点 1.a HBase是一个建立在HDFS之上的分布式数据库。HBase的主要技术特 点如下: (1)容量大。HBase中的一个表可以存储数十亿行、上百亿列。当关系数 据库的单个表的记录在亿级时,查询和写入的性能都会呈现指数级下降;而 HBase对于单表存储百亿级或更多的数据都没有性能问题。 (2)无固定模式(表结构不固定)。HBase可以根据需要动态地增加列,同 一张表中不同的行可以有截然不同的列。 (3)列式存储。HBase中的数据在表中是按照列存储的,可动态地增加列, 并且可以单独对列进行各种操作。 (4)稀疏性。HBase的表中的空列不占用存储空间,表可以非常稀疏。 (5)数据类型单一。HBase中的数据都是字符串。 5.2 HBse与传统关系数据库的区别 1.a HBase与传统关系数据库的区别主要体现在以下几方面: (1)数据类型方面。关系数据库具有丰富的数据类型,如字符串型、数值 型、日期型、二进制型等。HBase只有字符串数据类型,即HBase把数据存储为 未经解释的字符串,数据的实际类型都是交由用户自己编写程序对字符串进行 解析的。 第5章HBase分布式数据库133(2)数据操作方面。关系数据库包含了丰富的操作,如插入、删除、更新、查询等,其 中还涉及各式各样的函数和连接操作。HBase只有很简单的插入、查询、删除、清空等操 作,表和表之间是分离的,没有复杂的表和表之间的关系。 (3)存储模式方面。关系数据库是基于行存储的。在关系数据库中读取数据时,需 要按顺序扫描每个元组,然后从中筛选出要查询的属性。HBase是基于列存储的。 HBase将列划分为若干列族(columnfamily),每个列族都由几个文件保存,不同列族的 文件是分离的。它的优点是:可以降低I/O开销,支持大量并发用户查询,仅需要处理要 查询的列,不需要处理与查询无关的大量数据列。 (4)数据维护方面。在关系数据库中,更新操作会用最新的当前值替换元组中原来 的旧值。而HBase执行的更新操作不会删除数据旧的版本,而是添加一个新的版本,旧 的版本仍然保留。 (5)可伸缩性方面。HBase分布式数据库就是为了实现灵活的水平扩展而开发的, 所以它能够轻松增加或减少硬件的数量以实现性能的伸缩。而传统数据库通常需要增加 中间层才能实现类似的功能,很难实现横向扩展,纵向扩展的空间也比较有限。 5.1.3HBase与Hadoop中其他组件的关系 HBase作为Hadoop生态系统的一部分,一方面它的运行依赖于Hadoop生态系统 中的其他组件;另一方面,HBase又为Hadoop生态系统的其他组件提供了强大的数据存 储和处理能力。HBase与Hadoop生态系统中其他组件的关系如图5-1所示。 图5- 1 HBase与Hadop生态系统中其他组件的关系 HBase使用HDFS作为高可靠的底层存储,利用廉价集群提供海量数据存储能力。 HBase使用MapReduce处理海量数据,实现高性能计算。 HBase用ZooKeper提供协同服务,ZooKeper用于提供高可靠的锁服务。 ZooKeper保证了集群中所有的计算机看到的视图是一致的。例如,节点A通过 ZooKeper抢到了某个独占的资源,那么就不会有节点B也宣称自己获得了该资源(因为 ZooKeper提供了锁机制),并且这一事件会被其他所有的节点观测到。HBase使用 ZooKeper服务进行节点管理以及表数据的定位。 此外,为了方便在HBase上进行数据处理,Sqoop为HBase提供了高效、便捷的 RDBMS数据导入功能,Pig和Hive为HBase提供了高层语言支持。 134Spark大数据分析技术(Python版·微课版) HBase系统 架构和数据 访问流程 5.2HBase系统架构和数据访问流程 5.2.1HBase系统架构 HBase采用主从架构,由客户端、HMaster服务器、HRegionServer和ZooKeeper服 务器构成。在底层,HBase将数据存储于HDFS中。HBase系统架构如图5-2所示。 图5- 2 HBase系统架构 1.客户端 客户端包含访问HBase的接口,同时在缓存中维护着已经访问过的HRegion位置信 息,用来加快后续数据访问过程。HBase客户端使用RPC(RemoteProcedureCal,远程过程 调用)机制与HMaster服务器和HRegionServer进行通信。对于管理类操作,客户端与 HMaster服务器进行RPC;对于数据读写类操作,客户端则会与HRegionServer进行RPC 。 2.ZooKeper服务器 ZooKeper服务器用来为HBase集群提供稳定可靠的协同服务,ZooKeper服务器 存储了-ROOT-表的地址和HMaster的地址,客户端通过-ROOT-表可找到自己所需的 数据。ZooKeper服务器并非一台单一的计算机,可能是由多台计算机构成的集群。每 个HRegionServer会以短暂的方式把自己注册到ZooKeper服务器中,ZooKeper服务 器会实时监控每个HRegionServer的状态并通知给HMaster服务器,这样,HMaster服 务器就可以通过ZooKeper服务器随时感知各个HRegionServer的工作状态。 具体来说,ZooKeper服务器的作用如下: (1)保证任何时候集群中只有一个HMaster服务器作为集群的“总管”。HMaster 服务器记录了当前有哪些可用的HRegionServer,以及当前哪些HRegion分配给了哪些 第5章HBase分布式数据库135HRegionServer,哪些HRegion还没有被分配。当一个HRegion需要被分配时,HMaster 服务器从当前活着的HRegionServer中选取一个,向其发送一个装载请求,把HRegion 分配给这个HRegionServer。HRegionServer得到请求后,就开始加载这个HRegion。 加载完成后,HRegionServer会通知HMaster服务器加载的结果。如果加载成功,那么 这个HRegion就可以对外提供服务了。 (2)实时监控HRegionServer的状态。ZooKeeper服务器将HRegionServer上线和 下线信息实时通知给HMaster服务器。 (3)存储HBase目录表的寻址入口。 (4)存储HBase的模式。HBase的模式包括有哪些表、每个表有哪些列族等各种元 信息。 (5)锁定和同步服务。锁定和同步服务机制可以帮助自动故障恢复,同时连接其他 的分布式应用程序。 3.HMaster服务器 每台HRegionServer都会和HMaster服务器通信,HMaster服务器的主要任务就是 告诉每个HRegionServer它主要维护哪些HRegion。 当一台新的HRegionServer登录到HMaster服务器时,HMaster服务器会告诉它先 等待分配数据。而当一台HReionServer发生故障失效时,HMaster服务器会把它负责 的HRn标记为未分配,然后把它们分配给其他HRr。 HMaster服务器用于协调多个HRegionServer,侦测各个HRegionServer的状态,负 责分配HRegion给HRegionServer,平衡HRegionServer之间的负载。在ZooKeper服 务器的帮助下,HBase允许多个HMaster服务器共存,但只有一个HMaster服务器提供 服务,其他的HMaster服务器处于待命状态。当正在工作的HMaster服务器宕机时, ZooKeper服务器指定一个待命的HMaster服务器接管它。 HMaster服务器主要负责表和HRegion的管理工作,具体包括:管理HRegionServer, 实现其负载均衡;管理和分配HRegion,例如在HRegion拆分时分配新的HRegion,在 HRegionServer退出时迁移其上的HRegion到其他HRegionServer上;监控集群中所有 HRegionServer的状态(通过HeartBeat监听);处理模式更新请求(创建、删除、修改表的 定义)。 egiogegionServe 4.HRegionServer HRegionServer维护HMaster服务器分配给它的HRegion,处理用户对这些 HRegion的I/O请求,向HDFS文件系统中读写数据,此外,HRegionServer还负责拆分 在运行过程中变得过大的HRegion。 HRegionServer内部管理一系列HRegion对象,每个HRegion对应表中的一个分 区。HBase的表根据RowKey的范围被水平拆分成若干HRegion。每个HRegion都包 含了这个HRegion的startkey和endkey之间的所有行。HRegions被分配给集群中的 某些HRegionServer管理,由它们负责处理数据的读写请求。每个HRegionServer大约 136Spark大数据分析技术(Python版·微课版) 可以管理1000个HRegion。HRegion由多个HStore组成,每个HStore对应表中的一 个列族的存储。每个列族其实就是一个集中的存储单元,因此最好将具备共同I/O特性 的列放在一个列族中,这样最高效。 HStore是HBase存储的核心。HStore由两部分组成,一部分是MemStore,另一部 分是StoreFiles。MemStore是排序的内存缓冲区(sortedmemorybuffer),用户写入的 数据首先会放入MemStore,当MemStore满了以后会刷写(flush)成一个StoreFile(其底 层实现是HFile)。当StoreFile文件数量达到一定阈值时,会触发合并(compact)操作, 将多个StoreFiles合并成一个StoreFile,合并过程中会进行版本合并和数据删除,因此, HBase其实只增加数据,所有的更新和删除操作都是在后续的合并过程中进行的,这使 得用户的写操作只要进入内存中就可以立即返回,保证了HBaseI/O的高性能。 当StoreFile合并后,会逐步形成越来越大的StoreFile,当单个StoreFile大小达到一 定阈值后,会触发拆分(split)操作,同时把当前分区拆分成两个分区,父分区会下线,新拆 分出的两个子分区会被HMaster服务器分配到相应的HRegionServer上,使得原先一个 分区的压力得以分流到两个分区上。图5-3描述了StoreFile的合并和拆分过程。 图5- 3 StoreFile的合并和拆分过程 Hadoop数据节点负责存储所有HRegionServer管理的数据。HBase中的所有数据 都是以HDFS文件的形式存储的。出于使HReionServer管理的数据本地化的考虑, HRegionServer是根据数据节点分布的。HBaseg 的数据在写入的时候都存储在本地。但 当某一个HRegion被移除或被重新分配的时候,就可能产生数据不在本地的情况。名称 节点负责维护构成文件的所有物理数据块的元信息。 5.2 HBse数据访问流程 2.a n是按照“表名+开始主键+分区号”(区分 HRegiotablename+startkey+regionId) 的,每个HRegion对应表中的一个分区。可以用上述标识符区分不同的HRegion,这些 标识符数据就是元数据,而元数据本身也是用一个HBase表保存在HRegion里面的,称 这个表为.META.表(元数据表),其中保存的就是HReion标识符和实际HReion服务 器的映射关系。 gg .META.表也会增长,并且可能被分割为几个HRegion。为了定位这些HRegion,采 用-ROOT-表(根数据表)保存所有.META.表的位置,而-ROOT-表是不能被分割的,永远 只保存在一个HRegion里。在客户端访问具体的业务表的HRegion时,需要先通过 -ROOT-表找到.META.表,再通过.META.表找到HRegion的位置,即这两个表主要解 第5章HBase分布式数据库137 决了HRegion的快速路由问题。 1.-ROOT-表 -ROOT-表记录了.META. 表的HRegion信息。 -ROOT-表的结构如表5-1所示。 表5- 1 -ROOT-表的结构 RowKey info historian regioninfo server serverstartcode .META.,Table1,0,12345678,12657843 HRS1 .META.,Table2,30000,12348765,12348675 HRS2 下面分析-ROOT-表的结构,每行记录了一个.META. 表的HRegion信息。 1)RowKey RowKey(行键)由3部分组成:.META. 表表名、StartRowKey和创建时间戳。Row Key存储的内容又称为.META. 表对应的HRegion的名称。将组成RowKey的3部分 用逗号连接,就构成了整个RowKey。 2)info info中包含regioninfo、server和serverstartcode。其中regioninfo就是HRegion的 详细信息,包括StartRowKey、EndRowKey信息等。server存储的是管理这个HRegion 的HRegionServer的地址。所以,当HRegion被拆分、合并或者重新分配的时候,都需要 修改-ROOT-表的内容。 2..META. 表 .META. 表的结构如表5-2所示。 表5- 2 .META. 表的结构 RowKey info historian regioninfo server serverstartcode Table1,RK0,12345678 HRS1 Table1,RK10000,12345678 HRS2 Table1,RK20000,12345678 HRS3 . . Table2,RK0,12345678 HRS1 Table2,RK20000,12345678 HRS2 HBase的所有HRegion元数据被存储在.META. 表中。随着HRegion的增多, .META. 表的数据量也会增大,并拆分成多个新的HRegion。为了定位.META. 表中各个 1 38 Spark大数据分析技术(Python版·微课版) HRegion的位置,把.META.表中所有HRegion的元数据保存在-ROOT-表中,最后由 ZooKeeper服务器记录-ROOT-表的位置信息。所有客户端访问用户数据前,需要首先访 问ZooKeeper服务器获得-ROOT-表的位置,然后访问-ROOT-表获得.META.表的位 置,最后根据.META.表中的信息确定用户数据存放的位置。 下面用一个例子介绍访问具体数据的过程。先构建-ROOT-表和.META.表。 假设HBase中只有两张用户表:Table1和Table2。Table1非常大,被划分成很多 HRegion,因此在.META.表中有很多行,用来记录这些HRegion。而Table2很小,只被划分 成两个HRegion,因此在.META.表中只有两行记录。这个.META.表如表5-2所示。 假设要从Table2中查询一条RowKey是RK10000的数据,应该按以下步骤进行: (1)从.META.表中查询哪个HRegion包含这条数据。 (2)获取管理这个HRegion的HRegionServer地址。 (3)连接这个HRegionServer,查到这条数据。 对于步骤(1),.META.表也是一张普通的表,需要先知道哪个HRegionServer管理该 .META.表。因为Table1实在太大了,它的HRegion实在太多了,.META.表为了存储这些 HRegion信息,自己也需要划分成多个分区,这就意味着可能有多个HRegionServer管理这 个.META.表。HBase的做法是用-ROOT-表记录.META.表的分区信息。假设.META.表被 分成了两个分区,这个-ROOT-表如表5-1所示。客户端就需要先访问-ROOT-表。 查询Table2中Row Key是RK10000的数据的整个路由过程的主要代码在org. apache.hadoop.hbase.client.HConnectionManager.TableServers中: private HRegionLocation locateRegion(final byte[] tableName, final byte[] row, boolean useCache) throws IOException { if (tableName == null || tableName.length == 0) { throw new IllegalArgumentException("table name cannot be null or zero length"); } if (Bytes.equals(tableName, ROOT_TABLE_NAME)) { synchronized (rootRegionLock) { //防止两个线程同时查找root 区域 if (!useCache || rootRegionLocation == null) { this.rootRegionLocation = locateRootRegion(); } return this.rootRegionLocation; } } else if (Bytes.equals(tableName, META_TABLE_NAME)) { return locateRegionInMeta(ROOT_TABLE_NAME, tableName, row, useCache, metaRegionLock); } else { //缓存中无此分区,需要访问meta RS return locateRegionInMeta(META_TABLE_NAME, tableName, row, useCache, userRegionLock); } } 第5章HBase分布式数据库139 这是一个递归调用的过程。获取Table2的RowKey为RK10000的HRegionServer→ 获取.META.表的RowKey为“Table2,RK10000,…”的HRegionServer→获取-ROOT-表的 RowKey为“ .META.,Table2,RK10000,…,…”的HRegionServer→获取-ROOT-表的 HRegionServer→从ZooKeeper服务器得到-ROOT-表的HRegionServer→从-ROOT-表中查 到RowKey最接近(小于)“ .META.,Table2,RK10000,…,…”的一行,并得到.META.表的 HRegionServer→从.META.表中查到RowKey最接近(小于)“Table2,RK10000,…”的一 行,并得到Table2的HRegionServer→从Table2中查到RK10000的行。 HBase 数据表 5.3HBase数据表 HBase是基于HadoopHDFS的数据库。HBase数据表是一个稀疏的、分布式的、序 列化的、多维排序的分布式多维表,表中的数据通过行键、列族、列名(columnname )、时 间戳(timestamp)进行索引和查询定位。表中的数据都是未经解释的字符串,没有数据 类型。在HBase表中,每一行都有一个可排序的行键和任意多个列。表的水平方向由一 个或多个列族组成,一个列族中可以包含任意多个列,同一个列族的数据存储在一起。列 族支持动态扩展,可以添加列族,也可以在列族中添加列,无须预先定义列的数量,所有列 均以字符串形式存储。 5.3.1HBase数据表逻辑视图 HBase以表的形式存储数据,表由行和列组成,列可组合为若干列族,表5-3是一个 班级学生HBase数据表的逻辑视图。此表中包含两个列族:StudentBasicInfo(学生基本 信息)列族,由Name(姓名)、Addres(地址)、Phone(电话)3列组成;StudentGradeInfo (学生课程成绩信息)列族,由Chinese(语文)、Maths(数学)、English(英语)3列组成。 RowKey为ID2的学生存在两个版本的电话,时间戳较大的数据 ID3有两个版本的地址, 版本是最新的数据。 表5- 3 班级学生HBase数据表 RowKey StudentBasicInfo StudentGradeInfo Name Addres Phone Chinese Maths English ID1 LiHua Building1 135×××××××× 85 90 86 ID2 WangLi Building1 t2:136×××××××× t1:158×××××××× 78 92 88 ID3 ZhangSan t2:Building2 t1:Building1 132×××××××× 76 80 82 1.行键 任何字符串都可以作为行键,HBase表中的数据按照行键的字典序排序存储。在设 计行键时,要充分利用排序存储这个特性,将经常一起读取的行存放到一起,从而充分利 1 40 Spark大数据分析技术(Python版·微课版) 用空间局部性。如果行键是网站域名,如www.apache.org、mail.apache.org、jira.apache. org,应该将网站域名进行反转(org.apache.www,org.apache.mail,org.apache.jira)再存 储。这样,所有apache域名将会存储在一起。行键是最大长度为64KB的字节数组,实 际应用中长度一般为10~100B。 2.列族和列名 HBase表中的每个列都归属于某个列族,列族必须作为表的模式定义的一部分预先 定义,如create'StudentBasicInfo','StudentGradeInfo'。在一个列族中可以存放很多列, 而各个列族中列的数量可以不相同。 列族中的列名以列族名为前缀,例如StudentBasicInfo:Name、StudentBasicInfo: Address都是StudentBasicInfo列族中的列。可以按需要动态地为列族添加列。在具体 存储时,一张表中的不同列族是分开独立存放的。HBase把同一列族里面的数据存储在 同一目录下,由几个文件保存。HBase的访问控制、磁盘和内存的使用统计等都是在列 族层面进行的,同一列族成员最好有相同的访问模式和大小。 3.单元格 在HBase表中,通过行键、列族和列名确定一个单元格(cell)。每个单元格中可以保 存一个字段数据的多个版本,每个版本对应一个时间戳。 4.时间戳 在HBase表中,一个单元格往往保存着同一份数据的多个版本,根据唯一的时间戳 区分不同版本,不同版本的数据按照时间倒序排序,最新版本的数据排在最前面。这样, 在读取时,将先读取最新版本的数据。 时间戳可以由HBase在数据写入时自动用当前系统时间赋值,也可以由客户显式赋 值。当写入数据时,如果没有指定时间,那么默认的时间就是系统的当前时间;当读取数 据时,如果没有指定时间,那么返回的就是最新版本的数据。保留版本的数量由每个列族 的配置决定。默认的版本数量是3。为了避免数据存在过多版本造成的存储和管理(包 括索引)负担,HBase提供了两种数据版本回收方式: (1)保存数据的最后n 个版本。当版本数量过多时,HBase会将过老的版本清除。 (2)保存最近一段时间(例如最近7天)内的版本。 5.区域 HBase自动把表在纵向上分成若干区域,即HRegion,每个HRegion会保存表中的 一段连续的数据。刚开始表中只有一个HRegion。随着数据的不断插入,HRegion不断 增大,当达到某个阈值时,HRegion自动等分成两个新的HRegion。 当HBase表中的行不断增多时,就会有越来越多的HRegion,这样一张表就被保存 在多个HRegion中。HRegion是HBase中分布式存储和负载均衡的最小单位。最小单 位的含义是:不同的HRegion可以分布在不同的HRegionServer上,但是一个HRegion 不会拆分到多个HRegionServer上。 第5章HBase分布式数据库1415.3.2HBase数据表物理视图 在逻辑视图层面,HBase表是由许多行组成的;但在物理存储层面,HBase表采用基 于列的存储方式,而不是像传统关系数据库那样采用基于行的存储方式,这也是HBase 和传统关系数据库的重要区别。可简单认为每个列族对应一张存储表,表中的行键、列 族、列名和时间戳唯一确定一条记录。HBase把同一列族里面的数据存储在同一目录 下,由几个文件保存。在物理层面上,表的数据是通过StoreFile存储的,每个StoreFile 相当于一个可序列化的映射(map),映射的键和值都是可解释型字符数组。 在实际的HDFS存储中,直接存储每个字段数据所对应的完整的键值对: {行键,列族,列名,时间戳}→值 例如,表5-3中ID2行Phone字段下t2时间戳的数值136××××××××在存储 时的完整键值对是 {ID2,StudentBasicInfo,Phone,t2}→136×××××××× 也就是说,对于HBase来说,它根本不认为存在行和列这样的概念,在实现时只认为 存在键值对这样的概念。键值对的存储是排序的,行概念是通过相邻的键值对比较而构 建的,HBase在物理实现上并不存在传统数据库中的二维表概念。因此,二维表中字段 值的空值,对HBase来说在物理实现上是不存在的,而不是所谓的值为null。 HBase在4个维度(行键、列族、列名、时间戳)上以键值对的形式保存数据,其保存的 数据量会比较大,因为对于每个字段来说,需要把对应的多个键值对都保存下来,而不像 传统数据库以两个维度只需要保存一个值就可以了。 也可使用多维映射理解表5-3的班级学生HBase数据表,如图5-4所示。 图5- 4 班级学生HBase数据表多维映射