概念
在这小节中,我们只对HBase的核心概念进行快速、简单的介绍。掌握这些概念 至少有助于消化后续内容。
数据模型的“旋风之旅”
应用把数据存放在带标签的表中。表由行和列组成。表格“单元格”(cell)——由行 和列的坐标交叉决定一是有版本的。默认情况下,版本号自动分配,是HBase插 入单元格时的时间戳。单元格的内容是未解释的字节数组。
表中行的键也是字节数组。所以理论上,任何东西都可以表示成二进制形式,然后 转化为长整型的字符串或直接对数据结构进行序列化,来作为键值。表中的行根据 行的键值(也就是表的主键)进行排序。排序根据字节序进行。所有对表的访问都要 通过表的主键。
行中的列分成“列族”(column family)。所有的列族成员有相同的前缀。因此,像 列 temperature:air 和 temperature:dew_point 都是列族 temperature 的成员,而station identifier则属于station族。列族的前缀必须由“可打印的” (printablc)字符组成。而修饰性的结尾字符,即列族修饰符,可以为任意字节,
一个表的列族必须作为表模式定义的一部分预先给出。但是新的列族成员可以随 后按需要加入。例如,只要目标表中已经有了列族station,那么客户端就在更新时 提供新的列station:address,并存储它的值。
物理上,所有的列族成员都一起存放在文件系统中。所以,虽然我们前面把HBase描述为一个面向列的存储器,但更准确的说法实际上是它是一个面向列族的存储 器。由于调优和存储都是在列族这个层次上进行的,所以最好使所有列族成员都有 相同的“访问模式”(access pattern)和大小特征。简而言之,HBase表和RDBMS 中的表类似,单元格有版本,行是排序的,而只要列族预先存在,客户端随时可以 把列添加到列族中去。
区域
HBase自动把表水平划分成“区域”(region)。每个区域由表中行的子集构成。每 个区域由它所属于的表、它所包含的第一行及其最后一行(不包括这行)来表示。一 开始,一个表只有一个区域。但是随着区域开始变大,等到它超出设定的大小阈 值,便会在某行的边界上把表分成两个大小基本相同的新分区。在第一次划分之 前,所有加载的数据都放在原始区域所在的那台服务器上。随着表变大,区域的个 数也会增加。区域是在HBase集群分布数据的最小单位。用这种方式,一个因为 太大而无法放在单台服务器上的表会被放到服务器集群上,其中每个节点都负责管 理表所有区域的一个子集。表的加载也是使用这种方法把数据分布到各个节点去 的。在线的所有区域按次序排列就构成了表的所有内容。
加锁
无论对行进行访问的事务牵涉多少列,对行的更新都是“原子的”(atomic)。这使 得“加锁模型”(locking model )能够保持简单。
实现
正如HDFS和MapReduce由客户端、从属机(slave)和协调主控机(master)——(即HDFS 的 namenode 和 datanode,以及 MapReduce 的 jobtracker 和 tasktracker) 组成,HBase也采用相同的模型,它用一个Master节点协调管理一个或多个 Regionserver从属机(见图13-1)。HBase主控机(master)负责启动(bootstrap)和全新 的安装、把区域分配给注册的Regionserver,恢复Regionserver的故障。Master的 负载很轻。Regionserver负责零个或多个区域的管理以及响应客户端的读写请求。 Regionserver还负责区域的划分,并通知HBase Master 有了新的子区域(daughter region),这样主控机就可以把父区域设为离线,并用子区域替换父区域。
图13-1.HBase集群的成员
HBase依赖于ZooKeeper。默认情况下,它管理一个ZooKeeper实例,作为集群的 “权威”(authority)。HBase负责根目录表(root catalog table)的位置、当前集群主 控机地址类似重要信息的管理。如果区域的分配过程中有服务器崩溃,就通过 ZooKeeper来协调分配。在ZooKeeper上管理分配事务的状态有助于在恢复时可以 从崩溃服务器遗留的状态开始继续分配。在启动一个客户端到HBase集群的连接 时,客户端必须至少拿到到集群所传递的ZooKeeper整体(ensemble)的位置。这 样,客户端才能访问ZooKeeper层次,了解集群的属性,如服务器的位置。
类似于在Hadoop中可以通过conf/slaves文件查看datanode和tasktracker, Regionserver从属机节点列在HBase的conf/regionservers文件中。启动和结東服务 的脚本也使用Hadoop一样基于SSH的远程命令机制来运行。集群的站点配置 (site-specific configuration)在 HBase 的 conf/hbase-site.xml 和 conf/hbase-env.sh文件中。它们的格式和Hadoop项目中对应的格式相同(参见 第9章)。
HBase通过Hadoop文件系统API来持久化存储数据。有多种文件系统接口的实现 一种是本地文件系统接口,一种是KFS文件系统、Amazon S3以及HDFS(Hadoop Distributed Filesystem, Hadoop 分布式文件系统)的接 口 HBase 可以使用其中任何一种。我们介绍的都是针对HDFS的内容,除非另外说明,但在 默认情况下,只8&狀写的都是本地文件系统。如果是体验一下新装HBase,这是没 有问题的,但如果稍后要使用HBase集群,首要任务通常是把HBase的存储配置 为指向HDFS集群。
运行中的HBase
HBase内部保留名为-ROOT-和.META.的特殊目录表(catalog table)。它们维护着当 前集群上所有区域的列表、状态和位置。-ROOT-表包含.META.表的区域列 表。.META.表包含所有用户空间区域(user-space region)的列表。表中的项使用区 域名作为键。区域名由所属的表名、区域的起始行、区域的创建时间以及对其整体 进行的MD5哈希值(即对表名、起始行、创建的时间戳进行哈希后的结果)组成。如前所述,表的键是排序的。因此,要査找一个特定行所在的区域只要在目录表中 找到第一个键大于或等于给定行键的可。区域变化时——即分裂、禁用/启用 (disable/enable)、删除、为负载均衡重新部署区域或由于Regionserver崩溃而重新 部署区域时——目录表会进行相应的更新。这样,集群上所有区域的状态信息就能 保持是最新的。
新连接到ZooKeeper集群上的客户端首先查找-ROOT-的位置。然后客户端通 过-ROOT-获取所请求行所在范围所属.META.区域的位置。客户端接着査找.META. 区域来获取用户空间区域所在节点及其位置。接着,客户端就可以直接和管理那 个区域的尺Regionserver进行交互。
每个行操作可能要访问三次远程节点。为了节省这些代价,客户端会缓存它们遍 历-ROOT-时获取的信息和.META.位置以及用户空间区域的开始行和结束行。
这样,它们以后不需要访问.META.表也能得知区域存放的位置。客户端在碰到错 误之前会一直使用所缓存的项。当发生错误时——即区域被移动了——客户端会再 去查看.META.获取区域的新位置。如果.META.区域也被移动了,客户端会再去查 看-ROOT-。
到达Regionserver的写操作首先追加到“提交日志” (commit log),然后加入内存 中的memstore。如果memstore满,它的内容会被“刷入(flush)文件系统。.提交日志存放在HDFS中,因此即使一个Regionserver崩溃,提交日志仍然可用。如果发现一个Regionserver不能访问 通常因为服务器的znode在ZooKeeper中过期了——主控机会根据区域对死掉的Regionserver的提交日志进行分割。在重新 分配后,在打开并使用死掉的RegionSerVer上的区域之前,这些区域会找到刚分割 得到的文件,其中包括还没有持久化存储的更新。这些更新会被“重做”(replay) 使区域恢复到服务器失败前夕的状态。
在读的时候首先査看区域的memstore。如果在memstore中找到了需要的版本,直 接返回即可。否则,需要按照次序从新到旧检查“刷新文件”(flush file),直到找 到满足查询的版本,或所有刷新文件都处理完为止。
有一个后台进程负责在刷新文件个数到达一个阈值时压缩它们。它把多个文件重新 写入一个文件,因为读操作检查的文件越少,它的执行效率越高。在压缩时,超出 模式所设最大值的版本以及被删除或过期的单元格会被清理掉。在Regionserver 上,另外有一个独立的进程监控着刷新文件的大小,一旦文件大小超出预先设定的 最大值,便会对区域进行分割。