查看: 4064|回复: 25

[转载] HBase架构(下)

[复制链接]
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
跳转到指定楼层
1#
发表于 2013-10-10 12:15 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
出处:http://duanple.blog.163.com/blog/static/709717672011925102028874/

1 Read Path

HBase中的每个column family可能有多个文件,文件中包含实际的cells或者是KeyValue实例。当memstore中积累的更新被flush到磁盘上时这些文件就会创建出来。负责compaction的后台线程会通过将小文件合并成更大的文件来将文件数控制在一定水平上。Major compaction最终会将所有的文件集合压缩成一个,之后随着flush的进行,小文件又会出现。

因为所有的存储文件都是不可变的,所以就没法直接将一个值从它们里面删除,也没法对某个值进行覆盖。而只能通过写入一个墓碑式的标记,来代表某个cell或者某几个cell或者是整行都被删除了。

假设今天你在给定的一行里写了一个列,之后你一直不断的添加数据,那么你可能会为该行写入另一个列。问题是,假设最初的列值已经被持久化到了磁盘中,而新写入的列还在memstore中,或者已经被flush到了磁盘,那该行到底算存放到哪呢?换句话说,当你对该行执行一个get命令时,系统怎么知道该返回什么内容?作为一个客户端,你可能希望返回所有的列—看起来它们好像就是一个实体一样。但是实际的数据是存储在独立的KeyValue实例中的,而且可能跨越任意数目的存储文件。

如果你删除了最初的那个列值,然后再执行get操作,你希望该值已经不存在了,虽然实际上它还存在于某处,但是墓碑式的标记表明你已经把它删除了。但是该标记很有可能与你要删除的值是分开存储的。关于该架构更细节的内容参见the section called “Seek vs. Transfer”。


论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
2#
 楼主| 发表于 2013-10-10 12:15 | 只看该作者
该问题是通过使用QueryMatcher以及一个ColumnTracker解决的。在读取所有的存储文件以找到一个匹配的记录之前,可能会有一个快速的排除检查,可以使用时间戳或者Bloom filter来跳过那些肯定不包含该记录的存储文件。然后,对剩余的存储文件进行扫描以找到匹配该key的记录。

为何Gets即Scans

在HBase之前的版本中,Get方法的确是单独实现的。最近的版本进行了改变,目前它内部已经和Scan API使用相同的源代码。

你可能会很奇怪,按理来说一个简单的Get应该比Scan快的。把它们区分对待,更容易针对Get进行某些优化。实际上这是由HBase本身架构导致的,内部没有任何的索引文件来支持对于某个特定的行或列的直接访问。最小的访问单元就是HFile中的一个block,为了找到被请求的数据,RegionServer代码和它的底层Store实例必须load那些可能包含该数据的blocks然后进行扫描。实际上这就是Scan的操作过程。换句话说,Get本质上就是对单个行的Scan,就是一个从start row到start row+1的scan。

Scan是通过RegionScanner类实现的,它会每个Store实例(每个代表一个column family)执行StoreScanner检索,如果读操作没有包含某个column family,那么它的Store实例就会被略过。

StoreScanner会合并它所包含的存储文件和memstore。同时这也是根据Bloomfilter或者时间戳进行排除性检查的时候,然后你可以跳过那些不需要的存储文件。参见the section called “Key Design”了解排除性检查的细节,以及如何利用它。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
3#
 楼主| 发表于 2013-10-10 12:16 | 只看该作者
同时也是由StoreScanner持有QueryMatcher(这里是ScanQueryMatcher类)。它会记录下那些包含在最终结果中的KeyValue。

RegionScanner内部会使用一个KeyValueHeap类来按照时间戳顺序安排所有的Store scanners。StoreScanner也会采用相同的方式来对存储文件进行排序。这就保证了用户可以按照正确的顺序进行KeyValue的读取(比如根据时间戳的降序)。

在store scanners被打开时,它们会将自己定位到请求的row key处。准备进行数据读取。

Figure 8.10. Rows are stored and scanned across different stores, on-disk or in-memory

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
4#
 楼主| 发表于 2013-10-10 12:16 | 只看该作者
对于一个get()调用,所有的服务器需要做的就是调用RegionScanner的next()。该调用内部会读取组成结果的所有内容。包括所有请求的版本,假设某列有三个版本,同时用户请求检索它们中所有的。这三个KeyValue可能分布在磁盘或内存中的存储文件。Next()调用会从所有的存储文件中读取直到读到下一行,或者直到读到足够的版本。

与此同时,它也会记录那些删除标记。当它扫描当前行的KeyValue时,可能会碰到这些删除标记,那些时间戳小于等于该删除标记的记录都会被认为是已经清除掉了。

图中展示了一个由一系列KeyValue组成的逻辑行,某些存储在相同的存储文件中,某些在其他文件上,包含了多个column family。由于时间戳或者Bloom filter的排除过程,某些存储文件和memstore可能会被跳过。最后一个存储文件中的删除标记可能会遮蔽掉所有的记录,但是它们仍然是同一行的一部分。这些scanners—实际上可以用一系列指向存储文件的箭头表示—要么指向文件中的第一个匹配点,要么是紧挨着所请求的key的那个点(如果没有直接匹配的点的话)。

在执行next调用时,只有那些具有匹配点的scanners才会被考虑。内部循环会从第一个存储文件到最后一个存储文件,按照时间地降序一个挨一个地读取其中的KeyValue,直到超出当前请求的key。

对于scan操作,则是通过在ResultScanner上不断的调用next(),直到碰到表的结束行或者为当前的batch读取了足够多的行时。

最终的结果是一个匹配了给定的get或者scan操作的KeyValue的列表。它会被发送给客户端,客户端就可以使用API函数来访问里面的列。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
5#
 楼主| 发表于 2013-10-10 12:16 | 只看该作者
2 Region查找

为了让客户端能够找到持有特定的row key range的region server,HBase提供了两个特殊的元数据表:-ROOT-和.META.。

-ROOT-表用于保存.META.表的所有regions的信息。HBase认为只有一个root region,同时它永不会被split,这样就可以保证一个三层的类B+树查找模式:第一层是存储在ZooKeeper上的一个保存了root 表的region信息的节点,换句话说就是保存了root region的那个region server的名称。第二层需要到-ROOT-表中查找匹配的meta region,然后第三层就是到.META.表中检索用户表的region信息。

元数据表中的row key由每个region的表名,起始行,及一个ID(通常使用当前时间,单位是毫秒)。从HBase 0.90.0开始,这些key可能会有一个额外的与之关联的hash值。目前只是用于用户表中。

注:Bigtable论文指出,在.META.表的region大小限制在128MB的情况下,它可以寻址2^34个regions,如果按每个region 128MB大小算,就是2^61字节大小。因为region大小可以增加而不会影响到定位模式,因此根据需要这个值还可以增大。

尽管客户端会缓存region位置信息,但是客户端在首次查询时都需要发送请求来查找特定row key或者一个region也可能会被split,merge或者移动,这样cache可能会无效。客户端库采用一种递归的方式逐层向上地找到当前的信息。它会询问与给定的row key匹配的.META.表region所属的region server地址。如果信息是无效的,它就退回到上层询问root表对应的.META. region的位置。最后,如果也失败了,它就需要读取Zookeeper节点以找到root表region的位置。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
6#
 楼主| 发表于 2013-10-11 12:28 | 只看该作者
最坏情况下,将会需要6次网络传输才能找到用户region,因为无效记录只有当查找失败时才能发现出来,当然系统假设这种情况并不经常发生。在缓冲为空的情况下,客户端需要三次网络传输来完成缓存更新。一种降低这种网络传输次数的方法是对位置信息进行预取,提前更新客户端缓存。具体细节见the section called “Miscellaneous Features”。

Figure 8.11. Starting with an empty cache, the client has to do three lookups.



一旦用户表region已知之后,客户端就可以直接访问而不需要进一步的查找。图中对查找进行了标号,同时假设缓存是空的。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
7#
 楼主| 发表于 2013-10-11 12:29 | 只看该作者
2.1 Region生命周期

Region的状态会被master追踪,通过使用AssignmentManager类。它会记下region从offline状态开始的整个生命周期。表8.1列出了一个region的所有可能状态。

Table 8.1. Possible states of a region

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
8#
 楼主| 发表于 2013-10-11 12:30 | 只看该作者
状态间的转换可能是由master引起,也可能是由持有它的那个region server引起。比如master可能将region分配给某个server,之后它会由该server打开。另一方面,region server可能会启动split过程,这会触发region打开和关闭事件。

由于这些事件本身的分布式属性,服务器使用ZooKeeper在一个专门的znode中记录各种状态。

3 ZooKeeper

从0.20.x开始,HBase使用ZooKeeper作为它的分布式协调服务。包括region servers的追踪,root region的位置及其他一些方面。0.90.x版引入了新的master实现,与ZooKeeper有了更紧密的集成。它使得HBase可以去除掉master和region servers之间发送的心跳信息。这些现在都通过ZooKeeper完成了,当其中的某一部分发生变化时就会进行通知,而之前是通过固定的周期性检查完成。

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
9#
 楼主| 发表于 2013-10-11 12:30 | 只看该作者
HBase会在它的根节点下创建一系列的znodes。根节点默认是”/hbase”,可以通过zookeeper.znode.parent进行配置。下面是所包含的znodes节点列表及其功用:

注:下面的例子使用了ZooKeeper命令行接口(简称CLI)来运行这些命令。可以通过如下命令启动CLI:
  1. $
  2. $ZK_HOME/bin/zkCli.sh -server <quorum-server>

  3. /hbase/hbaseid
复制代码
包含了集群ID,跟存储在HDFS上的hbase.id文件中的一致. 如下:
  1. [zk: localhost(CONNECTED) 1]
  2. get /hbase/hbaseid
  3.         
  4. e627e130-0ae2-448d-8bb5-117a8af06e97


  5. /hbase/master
复制代码

使用道具 举报

回复
论坛徽章:
277
马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11版主9段
日期:2012-11-25 02:21:03ITPUB年度最佳版主
日期:2014-02-19 10:05:27现任管理团队成员
日期:2011-05-07 01:45:08
10#
 楼主| 发表于 2013-10-13 17:04 | 只看该作者
包含了服务器名称, (具体参见the section called “Cluster Status Information” ). 如下:
  1. [zk: localhost(CONNECTED) 2]
  2. get /hbase/master

  3. foo.internal,60000,1309859972983


  4. /hbase/replication
复制代码
包含了replication的细节信息。相关细节参见 the section called “Internals”。
  1. /hbase/root-region-server
复制代码
包含了持有
-ROOT-
regions 的region server的服务器名称。在region查找过程中会用到它 (见 the section called “Region Lookups”). 如下:
  1. [zk: localhost(CONNECTED) 3]
  2. get /hbase/root-region-server

  3. rs1.internal,60000,1309859972983


  4. /hbase/rs
复制代码

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表