HBase
是一个在 HDFS
上开发的面向列的分布式数据库,如果你需要实时访问超大规模的数据集,那么使用 HBase
就对了。
HBase
自底而上地进行构建,可以简单的通过增加节点来线性扩展。其并不是关系型数据库,并且也不支持 SQL
,在特定的空间里,能够做 RDBMS
不能做的事,即在廉价的硬件构成的集群上管理超大规模的稀疏表。
应用将数据放到带有标签的表中。而表有行和列组成,表的 单元格 由行和列的交叉决定,其是有版本的。默认情况下,版本号自动分配,为 HBase
插入单元格时的时间戳,单元格的内容是未解释的字节数组。
表中的行也是字节数组,因此理论上任何东西都可以通过表示成字节数组或者将二进制形式转换为长整型或直接对数据结构进行序列化来作为键值。表中的行根据行的键值进行排序,排序根据字节序进行,所有对表的访问都需要通过表的主键。
行中的列被分为列族(column family
),同一个列族的所有成员具有相同的前缀。列族的前缀必须由 可打印的 字符组成,而修饰性的结尾字符,即列族修饰符,可以为任意字节。列族和修饰符之间始终以冒号(:
)分隔。
一个表的列族必须作为表模式定义的一部分预先给出,但是新的列族成员可以随后按需加入。
在物理上所有的列族成员都一起存放在文件系统中,因此结合前面的将 HBase
描述为一个面向列的存储器,其本质上更准确的是面向列族的存储器。
但由于调优和存储都是在列族这个维度上进行,所以所有的列族成员具有相同的访问模式和大小特征是最优解。对于存储较大字节的数据和较小字节的数据最好分别存储在不同的列族中。
简而言之,HBase
的表和 RDBMS
的表类似,只不过其单元格有版本;行是排序的;只要列族是预先存在的,客户端随时可以将列添加进去。
HBase
自动将表水平划分为区域(region
),每个区域由表中行的子集构成,每个区域由所属表、所包含的第一行及最后一行来表示。
从表建立之初,一个表只有一个区域,但随着数据增多,其区域也会增大,知道区域超过阈值的界限,就会在某行的边界上将表区分为两个大小相同的新分区。
区域是 HBase
集群上分布数据的最小单位,使用这种方式不会因为数据太大而无法放置在单个机器上的表会被放到集群中,其中集群中的每个机器负责管理表所有区域的一个子集。而表的加载也是使用这种方法将数据分布到各个节点,集群中所有的机器上的节点按次序排列也就构成了表的所有内容。
无论对行进行访问的事务牵涉到多少行,对行的更新都是 原子级别。
regionserver
。区域会自动重新进行平衡,负载均匀分布。MapReduce
集成功能使用全并行的分布式作业根据数据位置来处理它们。RDBMS
比较HBase
是一个分布式的、面向列的数据存储系统,通过在 HDFS
上提供随机读/写来解决 Hadoop
不能处理的问题。HBase
自底层设计开始即聚集于各种可伸缩性问题:表可以很高(数十亿个数据行);表可以很宽(数百万个列);水平分区并在上千个普通机器上自动复制。表的模式是物理存储的直接反映,使系统有可能提供高效的数据结构的序列化、存储和检索,因此程序的开发者就必须选择以正确的方式使用这种存储和检索方式。
严格来说 RDBMS
是一个遵循 Codd
的 12
条准则的数据库。标准的 RDBMS
是模式固定、面向行的数据库且具有 ACID
性质和复杂的 SQL
查询处理引擎。RDBMS
强调事务的强一致性、参照完整性、数据抽象和物理存储层相对独立,以及基于 SQL
语言的复杂查询支持。在 RDBMS
中,可以非常容易地建立 二级索引,执行复杂的内连接和外连接,执行计数、求和、排序、分组等操作,或对表、行和列中的数据进行分页存放。
正如 HDFS
和 YARN
是由客户端、slave
和 master
组成,HBase
也采用了相同的架构,使用一个 master
节点协调管理一个或多个 regionserver
。HBase
的 master
节点负责启动一个新的集群,将区域分配个注册的 regionserver
,恢复 regionserver
的故障。regionserver
负责零个或多个区域的管理以及相应客户端的读写请求,还负责区域的划分并通知 master
有了新的子区域,因此 master
就可以将父区域设置为离线,并用子区域替代父区域。
HBase
依赖于 ZooKeeper
,默认情况下管理着一个 ZooKeeper
实例,作为集群的 权威机构,其还负责管理 hbase:meta
目录表的位置以及当前集群主控地址等重要信息。
如果在区域的分配过程中有服务器崩溃,就可以通过 ZooKeeper
来进行分配的协调。
在启动一个客户端到 HBase
集群的连接时,客户端必须至少拿到集群所传递的 ZooKeeper
集合体的位置,这样客户端才能访问 ZooKeeper
的层次结构,从而了解集群的属性。
regionserver
从节点列表可以在 HBase
的 conf/regionservers
文件中看到,与 Hadoop
的一致。
集群的站点配置在 HBase
的 conf/hbase-site.xml
和 conf/hbase-env.sh
中,他们的格式和 Hadoop
父项目中对应的格式相同。
大部分人都是使用 HDFS
来运行 HBase
,而 HBase
通过 Hadoop
文件系统 API
来持久化存储数据。但在默认情况下,HBase
会将存储写入本地文件系统。
HBase
HBase
内部保留着名为 hbase:meta
的特殊目录表(catalog table
),他们维护着当前集群上所有区域的列表、状态和位置。hbase:meta
表中的项使用区域名作为键,区域名由 所属的表名、区域的起始行、区域的创建时间 以及对其整体进行的 MD5
哈希值(即对表名、起始行、创建的时间戳进行哈希后的结果) 组成。示例如下:
1 | # 表名、起始行、时间戳使用逗号隔开,而 MD5 哈希值则使用两个句号包围 |
如前所属,行的键都是排序的,因此想要查找一个特定行所在的区域只要在目录表中找到第一个键大于或等于给定行键的项即可。而当区域变化时,目录表也会进行对应的更新,集群上所有区域的状态信息都能保持更新。
每个行操作可能要访问三次远程节点,而为了节省代价,通常都会缓存 hbase:meta
信息,其中缓存的内容包含位置信息、用户空间区域的开始行和结束行。当使用缓存中的数据发生异常时,即区域被移动了,客户端会去查看 hbase:meta
获取区域的新位置,如果 hbase:meta
也被移动了,那客户端也会重新寻找。
当新的客户端连接到 ZooKeeper
时会首先查找 hbase:meta
的位置,然后通过寻找合适的区域来获取用户空间区域所在的节点和位置,接下来就是客户端直接与管理对应区域的 regionserver
进行交互。
到达 Regionserver
的写操作首先追加到 提交日志(commit log
) 中,然后加入内存中的 metastore
,若是 metastore
已满,则会将内容 刷入(flash
) 文件系统。
提交日志存放在 HDFS
中,当发现某个 Regionserver
崩溃时,master
节点会根据区域对崩溃的 Regionserver
的提交日志进行分割,找到还没有被持久化存储的更新,然后这部分被 重做(replay
) 以使区域恢复到崩溃之前的状态。
而在读的时候会检查区域的 metastore
,如果在其中找到了需要的版本则查询至此结束。否则就需要按照次序从新道旧检查 刷新文件(flash
),直到找到们组查询的版本,或者所有刷新文件都处理完为止。
之前说到的 刷新文件(flash
) 会有一个后台进程在其个数达到阈值时压缩他们,将多个文件重新写入一个文件,在执行压缩操作时,进程会清理掉超出模式所设最大值的版本以及删除单元格或标识单元格为过期。
而在 Regionserver
上会有另外一个进程监控着刷新文件的大小,一旦大小超过预先设定的最大值,便会对区域进行分割。
HDFS
HBase
使用 HDFS
的方式与 MapReduce
的使用方式截然不同。在 HBase
中数据文件在启动时就被打卡,并在处理过程中始终保持打开状态,这是为了节省每次访问操作打开文件所需的代价。
文件描述符用完
由于在连接的集群上始终保持文件的打开状态,因此可能会达到系统和 HDFS
设定的限制。
其中一个进程默认的文件描述符限制是 1024
,当使用的描述符个数超过文件系统的 ulimit
值,就会在日志中看到异常信息 Too many open files
,不过在出现异常信息之前,往往 HBase
就已经出现问题了。
datanode
中的线程用完
与上述的情况类似,datanode
上限制运行的线程数不能超过 256
,可以通过在 hdfs-site.xml
中配置 dfs.datanode.max.transfer.threads
来更改设置。
HBase
在 master
节点机器上运行了 Web
服务,提供了运行中集群的状态视图。默认情况下,其监听 60010
端口,主界面显示基本的属性(包含软件版本、集群负载、请求频率、集群表的列表)和加入的 Regionserver
等。
在主界面上点击选中的 Regionserver
就会展示对应的 Web
服务器,展示该服务器上所有区域的列表及其他基本的属性值。
Metric
Hadoop
有一个度量 Metric
系统,会在每隔一段时间获取系统重要组件的信息,并将其输出到上下文中。启用该系统可以将信息导出到 JMX
,从而展示集群上正在和过去的请求视图。
Htable
提供的 incrementColumnValue()
方法可以实现计数器每秒数千次的更新,解决之前计数器存储在 MySQL
中的更新频繁问题。
此博客内容均为作者学习所做笔记,侵删!
若转作其他用途,请注明来源!