Hbase Architecture[上]

【图文详解】深入理解 Hbase 架构 Deep Into HBase Architecture 这是一篇讲 HBase 架构的文章,简洁明了,图文并茂。HBase数据模型和特征HBase 数据模型(The HBase data model)HBase 中的数据存储是面向列的,采用多层次键值映射的形式。HBase 数据模型非常灵活,它的美妙之处在于动态添加或删除列数据,而不会影响性能。HBase 可用于处理半结构化数据。它没有任何特定的数据类型,因为数据以字节存储。数据模型逻辑组件HBase ... 阅读详情

Hbase Architecture

概述:

  1. 序言
  2. seek VS Transfer
    2.1 B+树
    2.2 Log-Structured Merge-Trees
  3. storage
    3.1 概览
    3.2 Write Path
    3.3 Files
    3.3.1 Root Level Files
    3.3.2 Table Level Files
    3.3.3 Region Level Files
    3.4 Region Splits
    3.5 Compactions
    3.6 HFile格
    3.7 KeyValue格式
    原文出自 Hbase Architectrue谢谢作者的整理

1.序

作为开源类BigTable实现。HBase目前已经应用在很多互联网公司中。

项目主页:http://hbase.apache.org/

无论对于高级用户还是普通使用者来说,完整地理解所选择的系统在底层是如何工作的都是非常有用的。本章我们会解释下HBase的各个组成部分以及它们相互之间是如何协作的。

2. Seek vs. Transfer

在研究架构本身之前,我们还是先看一下传统RDBMS与它的替代者之间的根本上的不同点。特别地,我们将快速地浏览下关系型存储引擎中使用的B树及B+树,以及作为Bigtable的存储架构基础的Log-Structured Merge Tree。

注:需要注意的是RDBMSs并不是只能采用B树类型的结构,而且也不是所有的NoSQL解决方案都使用了与之不同的结构。通常我们都能看到各式各样的混搭型的技术方案,它们都具有一个相同的目标:使用那些对手头上的问题来说最佳的策略。下面我们会解释下为什么Bigtable使用了类LSM-tree的方式来实现这个目标。

2.1. B+树

B+树有一些特性可以让用户根据key来对记录进行高效地插入,查找和删除。它可以利用每个segment(也称为一个page)的下界和上界以及key的数目来建立一个动态,多级索引结构。通过使用segments,达到了比二叉树更高的扇出{!很明显二叉树一个节点只有2个出度,而B+树是个多叉树,一个节点就是一个segment,因此出度大小就由segment本身存储空间决定,出度增加后,就使得树高度变低,减少了所需seek操作的数目},这就大大降低了查找某个特定的key所需的IO操作数。

此外,它也允许用户高效地进行range扫描操作。因为叶子节点相互之间根据key的顺序组成了一个链表,这就避免了昂贵的树遍历操作。这也是关系数据库系统使用B+树进行索引的原因之一。

在一个B+树索引中,可以得到page级别的locality(这里的page概念等价于其他一些系统中block的概念):比如,一个leaf pages结构如下。为了插入一个新的索引条目,比如是key1.5,它会使用一个新的key1.5 → rowid条目来更新leaf page。在page大小未超过它本身的容量之前,都比较简单。如果page大小超出限制,那么就需要将该page分割成两个新的page。参见图8.1

Figure 8.1. An example B+ tree with one full page

HBase Architecture(译):上 - 星星 - 银河里的星星

这里有个问题,新的pages相互之间不一定是相邻的。所以,现在如果你想查询从key1到key3之间的内容,就有可能需要读取两个相距甚远的leaf pages。这也是为什么大部分的基于B+-树的系统中都提供了OPTIMIZE TABLE命令的原因—该命令会顺序地对table进行重写,以删除碎片,减少文件尺寸,从而使得这种基于range的查询在磁盘上也是顺序进行的。

2.2. Log-Structured Merge-Trees

另一方面,LSM-tree,选择的是一种与之不同的策略。进入系统的数据首先会被存储到日志文件中,以完全顺序地方式。一旦日志中记录下了该变更,它就会去更新一个内存中的存储结构,该结构持有最近的那些更新以便于快速的查找。

当系统已经积累了足够的更新,以及内存中的存储结构填满的时候,它会将key → record对组成的有序链表flush到磁盘,创建出一个新的存储文件。此时,log文件中对应的更新就可以丢弃了,因为所有的更新操作已经被持久化了。

存储文件的组织方式类似于B树,但是专门为顺序性的磁盘访问进行了优化。所有的nodes都被完全填充,存储为单page或者多page的blocks。存储文件的更新是以一种rolling merge的方式进行的,比如,只有当某个block填满时系统才会将对应的内存数据和现有的多page blocks进行合并。

图8.2展示了一个多page的block如何从in-memory tree合并为一个存储磁盘上的树结构。最后,这些树结构会被用来merge成更大的树结构。

Figure 8.2. Multi-page blocks are iteratively merged across LSM trees

HBase Architecture(译):上 - 星星 - 银河里的星星

随着时间的推进将会有更多的flush操作发生,会产生很多存储文件,一个后台进程负责将这些文件聚合成更大的文件,这样磁盘seek操作就限制在一定数目的存储文件上。存储在磁盘上的树结构也可以被分割成多个存储文件。因为所有的存储数据都是按照key排序的,因此在现有节点中插入新的keys时不需要重新进行排序。

查找通过merging的方式完成,首先会搜索内存存储结构,接下来是磁盘存储文件。通过这种方式,从客户端的角度看到的就是一个关于所有已存储数据的一致性视图,而不管数据当前是否驻留在内存中。删除是一种特殊的更新操作,它会存储一个删除标记,该标记会在查找期间用来跳过那些已删除的keys。当数据通过merging被重新写回时,删除标记和被该标记所遮蔽的key都会被丢弃掉。

用于管理数据的后台进程有一个额外的特性,它可以支持断言式的删除。也就是说删除操作可以通过在那些想丢弃的记录上设定一个TTL(time-to-live)值来触发。比如,设定TTL值为20天,那么20天后记录就变成无效的了。Merge进程会检查该断言,当断言为true时,它就会在写回的blocks中丢弃该记录。

B数和LSM-tree本质上的不同点,实际上在于它们使用现代硬件的方式,尤其是磁盘。

Seek vs. Sort and Merge in Numbers

对于大规模场景,计算瓶颈在磁盘传输上。CPU RAM和磁盘空间每18-24个月就会翻番,但是seek开销每年大概才提高5%。

如前面所讨论的,有两种不同的数据库范式,一种是Seek,另一种是Transfer。RDBMS通常都是Seek型的,主要是由用于存储数据的B树或者是B+树结构引起的,在磁盘seek的速率级别上实现各种操作,通常每个访问需要log(N)个seek操作。

另一方面,LSM-tree则属于Transfer型。在磁盘传输速率的级别上进行文件的排序和merges以及log(对应于更新操作)操作。根据如下的各项参数:

· 10 MB/second transfer bandwidth

· 10 milliseconds disk seek time

· 100 bytes per entry (10 billion entries)

· 10 KB per page (1 billion pages)

在更新100,000,000条记录的1%时,将会花费:

· 1,000 days with random B-tree updates

· 100 days with batched B-tree updates

· 1 day with sort and merge

很明显,在大规模情况下,seek明显比transfer低效。

比较B+树和LSM-tree主要是为了理解它们各自的优缺点。如果没有太多的更新操作,B+树可以工作地很好,因为它们会进行比较繁重的优化来保证较低的访问时间。越快越多地将数据添加到随机的位置上,页面就会越快地变得碎片化。最终,数据传入的速度可能会超过优化进程重写现存文件的速度。更新和删除都是以磁盘seek的速率级别进行的,这就使得用户受限于最差的那个磁盘性能指标。

LSM-tree工作在磁盘传输速率的级别上,同时可以更好地扩展到更大的数据规模上。同时也能保证一个比较一致的插入速率,因为它会使用日志文件+一个内存存储结构把随机写操作转化为顺序写。读操作与写操作是独立的,这样这两种操作之间就不会产生竞争。

存储的数据通常都具有优化过的存放格式。对于访问一个key所需的磁盘seek操作数也有一个可预测的一致的上界。同时读取该key后面的那些记录也不会再引入额外的seek操作。通常情况下,一个基于LSM-tree的系统的开销都是透明的:如果有5个存储文件,那么访问操作最多需要5次磁盘seek。然而你没有办法判断一个RDBMS的查询需要多少次磁盘seek,即使是在有索引的情况下。

3. Storage

HBase一个比较不为人知的方面是数据在底层是如何存储的。大部分的用户可能从来都不需要关注它。但是当你需要按照自己的方式对各种高级配置项进行设置时可能就得不得不去了解它。Chapter 11, Performance Tuning列出了一些例子。Appendix A, HBase Configuration Properties有一个更全的参考列表。

需要了解这些方面的另一个原因是,如果因为各种原因,灾难发生了,然后你需要恢复一个HBase安装版本。这时候,知道所有的数据都存放在哪,如何在HDFS级别上访问它们,就变得很重要了。你就可以利用这些知识来访问那些通常情况下不可访问的数据。当然,这种事情最好不发生,但是谁能保证它不会发生呢?

3.1. 概览

作为理解HBase的文件存储层的各组成部分的第一步,我们先来画张结构图。Figure 8.3, “HBase handles files in the file system, which stores them transparently in HDFS”展示了HBase和HDFS是如何协作来存储数据的。

Figure 8.3. HBase handles files in the file system, which stores them transparently in HDFS

HBase Architecture(译):上 - 星星 - 银河里的星星

上图表明,HBase处理的两种基本文件类型:一个用于write-ahead log,另一个用于实际的数据存储。文件主要是由HRegionServer处理。在某些情况下,HMaster也会执行一些底层的文件操作(与0.90.x相比,这在0.92.0中有些差别)。你可能也注意到了,当存储在HDFS中时,文件实际上会被划分为很多小blocks。这也是在你配置系统来让它可以更好地处理更大或更小的文件时,所需要了解的地方。更细节的内容,我们会在the section called “HFile Format”里描述。

通常的工作流程是,一个新的客户端为找到某个特定的行key首先需要联系Zookeeper Qurom。它会从ZooKeeper检索持有-ROOT- region的服务器名。通过这个信息,它询问拥有-ROOT- region的region server,得到持有对应行key的.META.表region的服务器名。这两个操作的结果都会被缓存下来,因此只需要查找一次。最后,它就可以查询.META.服务器然后检索到包含给定行key的region所在的服务器。

一旦它知道了给定的行所处的位置,比如,在哪个region里,它也会缓存该信息同时直接联系持有该region的HRegionServer。现在,客户端就有了去哪里获取行的完整信息而不需要再去查询.META.服务器。更多细节可以参考the section called “Region Lookups”。

注:在启动HBase时,HMaster负责把regions分配给每个HRegionServer。包括-ROOT-和.META.表。更多细节参考the section called “The Region Life Cycle”

HRegionServer打开region然后创建对应的HRegion对象。当HRegion被打开后,它就会为表中预先定义的每个HColumnFamily创建一个Store实例。每个Store实例又可能有多个StoreFile实例,StoreFile是对被称为HFile的实际存储文件的一个简单封装。一个Store实例还会有一个Memstore,以及一个由HRegionServer共享的HLog实例(见the section called “Write-Ahead Log”)。

3.2. Write Path

客户端向HRegionServer产生一个HTable.put(Put)请求。HRegionServer将该请求交给匹配的HRegion实例。现在需要确定数据是否需要通过HLog类写入write-ahead log(the WAL)。该决定基于客户端使用
方法

Put.setWriteToWAL(boolean)

所设置的flag。WAL是一个标准的Hadoop SequenceFile,里面存储了HLogKey实例。这些keys包含一个序列号和实际的数据,用来replay那些在服务器crash之后尚未持久化的数据。

一旦数据写入(or not)了WAL,它也会被放入Memstore。与此同时,还会检查Memstore是否满了,如果满了需要产生一个flush请求。该请求由HRegionServer的单独的线程进行处理,该线程会把数据写入到位于HDFS上的新HFile里。同时它也会保存最后写入的序列号,这样系统就知道目前为止持久化到哪了。

3.3. Files

HBase在HDFS上有一个可配置的根目录,默认设置为”/hbase”。 the section called “Co-Existing Clusters”说明了在共享HDFS集群时如何换用另一个根目录。可以使用hadoop dfs -lsr命令来查看HBase存储的各种文件。在此之前,我们先创建并填写一个具有几个regions的table:

hbase(main):001:0>create ‘testtable’, ‘colfam1’, \
{ SPLITS => [‘row-300’, ‘row-500’, ‘row-700’ , ‘row-900’] }

0 row(s) in 0.1910 seconds

hbase(main):002:0>
for i in ‘0’..’9’ do for j in ‘0’..’9’ do \
for k in ‘0’..’9’ do put ‘testtable’, “row-#{i}#{j}#{k}”, \

“colfam1:#{j}#{k}”, “#{j}#{k}” end end end

0 row(s) in 1.0710 seconds

0 row(s) in 0.0280 seconds

0 row(s) in 0.0260 seconds

…

hbase(main):003:0>
flush ‘testtable’

0 row(s) in 0.3310 seconds

hbase(main):004:0>
for i in ‘0’..’9’ do for j in ‘0’..’9’ do \

for k in ‘0’..’9’ do put ‘testtable’, “row-#{i}#{j}#{k}”, \

“colfam1:#{j}#{k}”, “#{j}#{k}” end end end

0 row(s) in 1.0710 seconds

0 row(s) in 0.0280 seconds

0 row(s) in 0.0260 seconds

…

Flush命令会将内存数据写入存储文件,否则我们必须等着它直到超过配置的flush大小才会将数据插入到存储文件中。最后一轮的put命令循环是为了再次填充write-ahead log。

下面是上述操作完成之后,HBase根目录下的内容:

HADOOP_HOME/bin/hadoop dfs -lsr /hbase

   ...

   0 /hbase/.logs

   0 /hbase/.logs/foo.internal,60020,1309812147645

   0 /hbase/.logs/foo.internal,60020,1309812147645/ \

foo.internal%2C60020%2C1309812147645.1309812151180

   0 /hbase/.oldlogs

  38 /hbase/hbase.id

   3 /hbase/hbase.version

   0 /hbase/testtable

 487 /hbase/testtable/.tableinfo

   0 /hbase/testtable/.tmp

   0 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855

   0 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855/.oldlogs

 124 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855/.oldlogs/ \

hlog.1309812163957

 282 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855/.regioninfo

   0 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855/.tmp

   0 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855/colfam1

11773 /hbase/testtable/1d562c9c4d3b8810b3dbeb21f5746855/colfam1/ \

646297264540129145

   0 /hbase/testtable/66b4d2adcc25f1643da5e6260c7f7b26

 311 /hbase/testtable/66b4d2adcc25f1643da5e6260c7f7b26/.regioninfo

   0 /hbase/testtable/66b4d2adcc25f1643da5e6260c7f7b26/.tmp

   0 /hbase/testtable/66b4d2adcc25f1643da5e6260c7f7b26/colfam1

7973 /hbase/testtable/66b4d2adcc25f1643da5e6260c7f7b26/colfam1/ \

3673316899703710654

   0 /hbase/testtable/99c0716d66e536d927b479af4502bc91

 297 /hbase/testtable/99c0716d66e536d927b479af4502bc91/.regioninfo

   0 /hbase/testtable/99c0716d66e536d927b479af4502bc91/.tmp

   0 /hbase/testtable/99c0716d66e536d927b479af4502bc91/colfam1

4173 /hbase/testtable/99c0716d66e536d927b479af4502bc91/colfam1/ \

1337830525545548148

   0 /hbase/testtable/d240e0e57dcf4a7e11f4c0b106a33827

 311 /hbase/testtable/d240e0e57dcf4a7e11f4c0b106a33827/.regioninfo

   0 /hbase/testtable/d240e0e57dcf4a7e11f4c0b106a33827/.tmp

   0 /hbase/testtable/d240e0e57dcf4a7e11f4c0b106a33827/colfam1

7973 /hbase/testtable/d240e0e57dcf4a7e11f4c0b106a33827/colfam1/ \

316417188262456922

   0 /hbase/testtable/d9ffc3a5cd016ae58e23d7a6cb937949

 311 /hbase/testtable/d9ffc3a5cd016ae58e23d7a6cb937949/.regioninfo

   0 /hbase/testtable/d9ffc3a5cd016ae58e23d7a6cb937949/.tmp

   0 /hbase/testtable/d9ffc3a5cd016ae58e23d7a6cb937949/colfam1

7973 /hbase/testtable/d9ffc3a5cd016ae58e23d7a6cb937949/colfam1/ \

4238940159225512178

注:由于空间的限制,我们对输出内容进行了删减,只留下了文件大小和名称部分。你自己在集群上运行命令时可以看到更多的细节信息。

文件可以分成两类:一是直接位于HBase根目录下面的那些,还有就是位于table目录下面的那些。

3.3.1. Root Level Files

第一类文件是由HLog实例处理的write-ahead log文件,这些文件创建在HBase根目录下一个称为.logs的目录。Logs目录下包含针对每个HRegionServer的子目录。在每个子目录下,通常有几个HLog文件(因为log的切换而产生)。来自相同region server的regions共享同一系列的HLog文件。

一个有趣的现象是log file大小被报告为0。对于最近创建的文件通常都是这样的,因为HDFS正使用一个内建的append支持来对文件进行写入,同时只有那些完整的blocks对于读取者来说才是可用的—包括hadoop dfs -lsr命令。尽管put操作的数据被安全地持久化,但是当前被写入的log文件大小信息有些轻微的脱节。

等一个小时log文件切换后,这个时间是由配置项:hbase.regionserver.logroll.period控制的(默认设置是60分钟),你就能看到现有的log文件的正确大小了,因为它已经被关闭了,而且HDFS可以拿到正确的状态了。而在它之后的那个新log文件大小又变成0了:

249962 /hbase/.logs/foo.internal,60020,1309812147645/ \

foo.internal%2C60020%2C1309812147645.1309812151180

   0 /hbase/.logs/foo.internal,60020,1309812147645/ \

foo.internal%2C60020%2C1309812147645.1309815751223

当日志文件不再需要时,因为现有的变更已经持久化到存储文件中了,它们就会被移到HBase根目录下的.oldlogs目录下。这是在log文件达到上面的切换阈值时触发的。老的日志文件默认会在十分钟后被master删除,通过hbase.master.logcleaner.ttl设定。Master默认每分钟会对这些文件进行检查,可以通过hbase.master.cleaner.interval设定。

hbase.id和hbase.version文件包含集群的唯一ID和文件格式版本号:
hadoopdfs−cat/hbase/hbase.ide627e130-0ae2-448d-8bb5-117a8af06e97

$
hadoop dfs -cat /hbase/hbase.version

7

它们通常是在内部使用因此通常不用关心这两个值。此外,随着时间的推进还会产生一些root级的目录。splitlog和.corrupt目录分别是log split进程用来存储中间split文件的和损坏的日志文件的。比如:

0 /hbase/.corrupt

  0 /hbase/splitlog/foo.internal,60020,1309851880898_hdfs%3A%2F%2F \

localhost%2Fhbase%2F.logs%2Ffoo.internal%2C60020%2C1309850971208%2F \

foo.internal%252C60020%252C1309850971208.1309851641956/testtable/ \

d9ffc3a5cd016ae58e23d7a6cb937949/recovered.edits/0000000000000002352

上面的例子中没有损坏的日志文件,只有一个分阶段的split文件。关于log splitting过程参见the section called “Replay”。

3.3.2. Table Level Files

HBase中的每个table都有它自己的目录,位于HBase根目录之下。每个table目录包含一个名为.tableinfo的顶层文件,该文件保存了针对该table的HTableDescriptor(具体细节参见the section called “Tables”)的序列化后的内容。包含了table和column family schema信息,同时可以被读取,比如通过使用工具可以查看表的定义。.tmp目录包含一些中间数据,比如当.tableinfo被更新时该目录就会被用到。

3.3.3. Region Level Files

在每个table目录内,针对表的schema中的每个column family会有一个单独的目录。目录名称还包含region name的MD5 hash部分。比如通过master的web UI,点击testtable链接后,其中User Tables片段的内容如下:

testtable,row-500,1309812163930.d9ffc3a5cd016ae58e23d7a6cb937949.

MD5 hash部分是”d9ffc3a5cd016ae58e23d7a6cb937949”,它是通过对region name的剩余部分进行编码生成的。比如”testtable,row-500,1309812163930”。尾部的点是整个region name的一部分:它表示这是一种包含hash的新风格的名称。在HBase之前的版本中,region name中并不包含hash。

注:需要注意的是-ROOT-和.META.元数据表仍然采用老风格的格式,比如它们的region name不包含hash,因此结尾就没有那个点。

.META.,,1.1028785192

对于存储在磁盘上的目录中的region names编码方式也是不同的:它们使用Jenkins hash来对region name编码。

Hash是用来保证region name总是合法的,根据文件系统的规则:它们不能包含任何特殊字符,比如”/”,它是用来分隔路径的。这样整个的region文件路径就是如下形式:

/////

在每个column-family下可以看到实际的数据文件。文件的名字是基于Java内建的随机数生成器产生的任意数字。代码会保证不会产生碰撞,比如当发现新生成的数字已经存在时,它会继续寻找一个未被使用的数字。

Region目录也包含一个.regioninfo文件,包含了对应的region的HRegionInfo的序列化信息。类似于.tableinfo,它也可以通过外部工具来查看关于region的相关信息。hbase hbck工具可以用它来生成丢失的table条目元数据。

可选的.tmp目录是按需创建地,用来存放临时文件,比如某个compaction产生的重新写回的文件。一旦该过程结束,它们会被立即移入region目录。在极端情况下,你可能能看到一些残留文件,在region重新打开时它们会被清除。

在write-ahead log replay期间,任何尚未提交的修改会写入到每个region各自对应的文件中。这是阶段1(看下the section called “Root Level Files”中的splitlog目录),之后假设log splitting过程成功完成-然后会将这些文件原子性地move到recovered.edits目录下。当该region被打开时,region server能够看到这些recovery文件然后replay相应的记录。

Split vs. Split

在write-ahead log的splitting和regions的splitting之间有明显的区别。有时候,在文件系统中很难区分文件和目录的不同,因为它们两个都涉及到了splits这个名词。为避免错误和混淆,确保你已经理解了二者的不同。

一旦一个region因为大小原因而需要split,一个与之对应的splits目录就会创建出来,用来筹划产生两个子regions。如果这个过程成功了—通常只需要几秒钟或更少—之后它们会被移入table目录下用来形成两个新的regions,每个代表原始region的一半。

换句话说,当你发现一个region目录下没有.tmp目录,那么说明目前它上面没有compaction在执行。如果也没有recovered.edits目录,那么说明目前没有针对它的write-ahead log replay。

注:在HBase 0.90.x版本之前,还有一些额外的文件,目前已被废弃了。其中一个是oldlogfile.log,该文件包含了对于相应的region已经replay过的write-ahead log edits。oldlogfile.log.old(加上一个.old扩展名)表明在将新的log文件放到该位置时,已经存在一个oldlogfile.log。另一个值得注意的是在老版HBase中的compaction.dir,现在已经被.tmp目录替换。

本节总结了下HBase根目录下的各种目录所包含的一系列内容。有很多是由region split过程产生的中间文件。在下一节里我们会分别讨论。

3.4. Region Splits

当一个region内的存储文件大于hbase.hregion.max.filesize(也可能是在column family级别上配置的)的大小时,该region就需要split为两个。起始过程很快就完成了,因为系统只是简单地为新regions(也称为daughters)创建两个引用文件,每个只持有原始region的一半内容。

Region server通过在parent region内创建splits目录来完成。之后,它会关闭该region这样它就不再接受任何请求。

Region server然后开始准备生成新的子regions(使用多线程),通过在splits目录内设置必要的文件结构。里面包括新的region目录及引用文件。如果该过程成功完成,它就会把两个新的region目录移到table目录下。.META.table会进行更新,指明该region已经被split,以及子regions分别是谁。这就避免了它被意外的重新打开。实例如下:

ow: testtable,row-500,1309812163930.d9ffc3a5cd016ae58e23d7a6cb937949.

column=info:regioninfo, timestamp=1309872211559, value=REGION => {NAME => \

'testtable,row-500,1309812163930.d9ffc3a5cd016ae58e23d7a6cb937949. \

 TableName => 'testtable', STARTKEY => 'row-500', ENDKEY => 'row-700', \

 ENCODED => d9ffc3a5cd016ae58e23d7a6cb937949, OFFLINE => true, 

 SPLIT => true,}

column=info:splitA, timestamp=1309872211559, value=REGION => {NAME => \

'testtable,row-500,1309872211320.d5a127167c6e2dc5106f066cc84506f8. \

TableName => 'testtable', STARTKEY => 'row-500', ENDKEY => 'row-550', \

ENCODED => d5a127167c6e2dc5106f066cc84506f8,}                                                                                                                       

column=info:splitB, timestamp=1309872211559, value=REGION => {NAME => \

'testtable,row-550,1309872211320.de27e14ffc1f3fff65ce424fcf14ae42. \

TableName => [B@62892cc5', STARTKEY => 'row-550', ENDKEY => 'row-700', \ 

ENCODED => de27e14ffc1f3fff65ce424fcf14ae42,}

可以看到原始的region在”row-550”处被分成了两个regions。在info:regioninfo中的”SPLIT=>true”表面该region目前已经分成了两个regions:splitA和splitB。

引用文件的名称是另一个随机数,但是会使用它所引用的region的hash作为后缀,比如:

/hbase/testtable/d5a127167c6e2dc5106f066cc84506f8/colfam1/ \

6630747383202842155.d9ffc3a5cd016ae58e23d7a6cb937949

该引用文件代表了hash值为” d9ffc3a5cd016ae58e23d7a6cb937949”的原始region的一半内容。引用文件仅仅有很少量的信息:原始region split点的key,引用的是前半还是后半部分。这些引用文件会通过HalfHFileReader类来读取原始region的数据文件。

现在两个子regions已经就绪,同时将会被同一个服务器并行打开。现在需要更新.META.table,将这两个regions作为可用region对待—看起来就像是完全独立的一样。同时会启动对这两个regions的compaction—此时会异步地将存储文件从原始region真正地写成两半,来取代引用文件。这些都发生在子regions的.tmp目录下。一旦文件生成完毕,它们就会原子性地替换掉之前的引用文件。

原始region最终会被清除,意味着它会从.META.table中删除,它的所有磁盘上的文件也会被删除。最后,master会收到关于该split的通知,它可以因负载平衡等原因将这些新的regions移动到其他服务器上。

ZooKeeper支持

Split中的所有相关步骤都会通过Zookeeper进行追踪。这就允许在服务器出错时,其他进程可以知晓该region的状态。

3.5. Compactions

存储文件处于严密的监控之下,这样后台进程就可以保证它们完全处于控制之中。Memstores的flush操作会逐步的增加磁盘上的文件数目。当数目足够多的时候,compaction进程会将它们合并成更少但是更大的一些文件。当这些文件中的最大的那个超过设置的最大存储文件大小时会触发一个region split过程。(see the section called “Region Splits”).

有两种类型的Compactions:minor和major。Minor compaction负责将一些小文件合并成更大的一个文件。合并的文件数通过hbase.hstore.compaction.min属性进行设置(以前该参数叫做hbase.hstore.compactionThreshold,尽管被弃用了但是目前还支持该参数)。默认该参数设为3,同时该参数必须>=2。如果设得更大点,会延迟minor compaction的发生,但是一旦它启动也会需要更多的资源和更长的时间。一个minor compaction所包含的最大的文件数被设定为10,可以通过hbase.hstore.compaction.max进行配置。

可以通过设置hbase.hstore.compaction.min.size(设定为该region的对应的memstore的flush size)和hbase.hstore.compaction.max.size(默认是Long.MAX_VALUE)来减少需要进行minor compaction的文件列表。任何大于最大的compaction size的文件都会被排除在外。最小的compaction size是作为一个阈值而不是一个限制,也就是说在达到单次compaction允许的文件数上限之前,那些小于该阈值的文件都会被包含在内。

图8.4展示了一个存储文件集合的实例。所有那些小于最小的compaction阈值的文件都被包含进了compaction中。

Figure 8.4. A set of store files showing the minimum compaction threshold

HBase Architecture(译):上 - 星星 - 银河里的星星

该算法会使用hbase.hstore.compaction.ratio (defaults to 1.2, or 120%)来确保总是能够选出足够的文件来进行compaction。根据该ratio,那些大小大于所有新于它的文件大小之和的文件也能够被选入。计算时,总是根据文件年龄从老到新进行选择,以保证老文件会先被compacted。通过上述一系列compaction相关的参数可以用来控制一次minor compaction到底选入多少个文件。

HBase支持的另外一种compaction是major compaction:它会将所有的文件compact成一个。该过程的运行是通过执行compaction检查自动确定的。当memstore被flush到磁盘,执行了compact或者major_compact命令或者产生了相关API调用时,或者后台线程的运行,就会触发该检查。Region server会通过CompactionChecker类实现来运行该线程。

如果用户调用了major_compact命令或者majorCompact()API调用,都会强制major compaction运行。否则,服务端会首先检查是否该进行major compaction,通过查看距离上次运行是否满足一定时间,比如是否达到24小时。

3.6. HFile格式

实际的文件存储是通过HFile类实现的,它的产生只有一个目的:高效存储HBase数据。它基于Hadoop的TFile类,模仿了Google的Bigtable架构中使用的SSTable格式。之前HBase采用的是Hadoop MapFile类,实践证明性能不够高。图8展示了具体的文件格式:

Figure 8.5. The HFile structure

HBase Architecture(译):上 - 星星 - 银河里的星星

文件是变长的,定长的块只有file info和trailer这两部分。如图所示,trailer中包含指向其他blocks的指针。Trailer会被写入到文件的末尾。Index blocks记录了data和meta blocks的偏移。data和meta blocks实际上都是可选部分。但是考虑到HBase使用数据文件的方式,通常至少可以在文件中找到data blocks。

Block 大小是通过HColumnDescriptor配置的,而它是在table创建时由用户指定的,或者是采用了默认的标准值。实例如下:

{NAME => ‘testtable’, FAMILIES => [{NAME => ‘colfam1’,

BLOOMFILTER => ‘NONE’, REPLICATION_SCOPE => ‘0’, VERSIONS => ‘3’,

COMPRESSION \=> ‘NONE’, TTL => ‘2147483647’, BLOCKSIZE => ‘65536’,

IN_MEMORY => ‘false’, BLOCKCACHE => ‘true’}]}

Block大小默认是64KB(or 65535 bytes)。下面是HFile JavaDoc中的注释:

“Minimum block size。通常的使用情况下,我们推荐将最小的block大小设为8KB到1MB。如果文件主要用于顺序访问,应该用大一点的block大小。但是,这会导致低效的随机访问(因为有更多的数据需要进行解压)。对于随机访问来说,小一点的block大小会好些,但是这可能需要更多的内存来保存block index,同时可能在创建文件时会变慢(因为我们必须针对每个data block进行压缩器的flush)。另外,由于压缩编码器的内部缓存机制的影响,最小可能的block大小大概是20KB-30KB”。

每个block包含一个magic头,一系列序列化的KeyValue实例(具体格式参见 the section called “KeyValue Format” )。在没有使用压缩算法的情况下,每个block的大小大概就等于配置的block size。并不是严格等于,因为writer需要放下用户给的任何大小数据{!如配置的block size可能是64KB,但是用户给了一条1MB的记录,writer也得接受它}。即使是对于比较小的值,对于block size大小的检查也是在最后一个value写入后才进行的{!不是写入前检查,而是写入后检查},所以实际上大部分blocks大小都会比配置的大一些。另一方面,这样做也没什么坏处。

在使用压缩算法的时候,对block大小就更没法控制了。如果压缩编码器可以自行选择压缩的数据大小,它可能能获取更好的压缩率。比如将block size设为256KB,使用LZO压缩,为了适应于LZO内部buffer大小,它仍然可能写出比较小的blocks。

Writer并不知道用户是否选择了一个压缩算法:它只是对原始数据按照设定的block大小限制控制写出。如果使用了压缩,那么实际存储的数据会更小。这意味着对于最终的存储文件来说与不进行压缩时的block数量是相同的,但是总大小要小,因为每个block都变小了。

你可能还注意到一个问题:默认的HDFS block大小是64MB,是HFile默认的block大小的1000倍。这样,HBase存储文件块与Hadoop的块并不匹配。实际上,两者之间根本没有关系。HBase是将它的文件透明地存储到文件系统中的,只是HDFS也恰巧有一个blocks。HDFS本身并不知道HBase存储了什么,它看到的只是二进制文件。图8.6展示了HFile内容如何散布在HDFS blocks上。

Figure 8.6. The many smaller HFile blocks are transparently stored in two much larger HDFS blocks

HBase Architecture(译):上 - 星星 - 银河里的星星

有时候需要绕过HBase直接访问HFile,比如健康检查,dump文件内容。HFile.main()提供了一些工具来完成这些事情:

$
./bin/hbase org.apache.hadoop.hbase.io.hfile.HFile

usage: HFile [-a] [-b] [-e] [-f ] [-k] [-m] [-p] [-r ] [-v]

-a,–checkfamily Enable family check

-b,–printblocks Print block index meta data

-e,–printkey Print keys

-f,–file File to scan. Pass full-path; e.g.

                 hdfs://a:9000/hbase/.META./12/34

-k,–checkrow Enable row order check; looks for out-of-order keys

-m,–printmeta Print meta data of file

-p,–printkv Print key/value pairs

-r,–region Region to scan. Pass region name; e.g. ‘.META.,,1’

-v,–verbose Verbose output; emits file and meta data delimiters

Here is an example of what the output will look like (shortened):

$
./bin/hbase org.apache.hadoop.hbase.io.hfile.HFile -f \
/hbase/testtable/de27e14ffc1f3fff65ce424fcf14ae42/colfam1/2518469459313898451 \

-v -m -p

Scanning -> /hbase/testtable/de27e14ffc1f3fff65ce424fcf14ae42/colfam1/2518469459313898451

K: row-550/colfam1:50/1309813948188/Put/vlen=2 V: 50

K: row-550/colfam1:50/1309812287166/Put/vlen=2 V: 50

K: row-551/colfam1:51/1309813948222/Put/vlen=2 V: 51

K: row-551/colfam1:51/1309812287200/Put/vlen=2 V: 51

K: row-552/colfam1:52/1309813948256/Put/vlen=2 V: 52

…

K: row-698/colfam1:98/1309813953680/Put/vlen=2 V: 98

K: row-698/colfam1:98/1309812292594/Put/vlen=2 V: 98

K: row-699/colfam1:99/1309813953720/Put/vlen=2 V: 99

K: row-699/colfam1:99/1309812292635/Put/vlen=2 V: 99

Scanned kv count -> 300

Block index size as per heapsize: 208

reader=/hbase/testtable/de27e14ffc1f3fff65ce424fcf14ae42/colfam1/ \

2518469459313898451, compression=none, inMemory=false, \

firstKey=row-550/colfam1:50/1309813948188/Put, \

lastKey=row-699/colfam1:99/1309812292635/Put, avgKeyLen=28, avgValueLen=2, \

entries=300, length=11773

fileinfoOffset=11408, dataIndexOffset=11664, dataIndexCount=1, \

metaIndexOffset=0, metaIndexCount=0, totalBytes=11408, entryCount=300, \

version=1

Fileinfo:

MAJOR_COMPACTION_KEY = \xFF

MAX_SEQ_ID_KEY = 2020

TIMERANGE = 1309812287166….1309813953720

hfile.AVG_KEY_LEN = 28

hfile.AVG_VALUE_LEN = 2

hfile.COMPARATOR = org.apache.hadoop.hbase.KeyValue$KeyComparator

hfile.LASTKEY = \x00\x07row-699\x07colfam199\x00\x00\x010\xF6\xE5|\x1B\x04

Could not get bloom data from meta block

第一部分是序列化的KeyValue实例的实际数据。第二部分除了trailer block的细节信息外,还dump出了内部的HFile.Reader属性。最后一部分,以”FileInfo”开头的,是file info block的值。

提供的这些信息是很有价值的,比如可以确定一个文件是否进行了压缩,采用的压缩方式。它也能告诉用户存储了多少个cell,key和value的平均大小是多少。在上面的例子中,key的长度比value的长度大很多。这是由于KeyValue类存储了很多额外数据,下面会进行解释。

3.7. KeyValue格式

实际上HFile中的每个KeyValue就是一个简单的允许对内部数据进行zero-copy访问的底层字节数组,包含部分必要的解析。图8.7展示了内部的数据格式。

Figure 8.7. The KeyValue format

HBase Architecture(译):上 - 星星 - 银河里的星星

该结构以两个标识了key和value部分的大小的定长整数开始。通过该信息就可以在数组内进行一些操作,比如忽略key而直接访问value。如果要访问key部分就需要进一步的信息。一旦解析成一个KeyValue Java实例,用户就可以对内部细节信息进行访问,参见the section called “The KeyValue Class”。

在上面的例子中key之所以比value长,就是由于key所包含的这些fields造成的:它包含一个cell的完整的各个维度上的信息:row key,column family name,column qualifier等等。在处理小的value值时,要尽量让key很小。选择一个短的row和column key(1字节family name,同时qualifier也要短)来控制二者的大小比例。

另一方面,压缩也有助于缓解这种问题。因为在有限的数据窗口内,如果包含的都是很多重复性的数据那么压缩率会比较高。同时因为存储文件中的KeyValue都是排好序的,这样就可以让类似的key靠在一起(在使用多版本的情况下,value也是这样的,多个版本的value也会是比较类似的)。

HBase summit document 比较全面的关于HBase的详细介绍,不错的东西 立即下载

相关推荐

宽带阻抗匹配的工程实现-第一步,端口驻波仿真

其实阻抗匹配我工作以来经常说,也经常做,但是基本上都是直接在印制板上进行调试。现在想先用仿真软件直接设计出来,才发现很多东西嘴上说容易,想做出来太难了。所以准备写一些文章,记录一下碰到的问题。

pp_0604的博客 2375

hbck源码系列(一)--hbck基本介绍

本文主要针对CDH5.13.3对应hbase1.2版本来分析hbck,帮助大家在运维中正确使用该修复工具 一.hbck基本介绍 Hbck主要有两个作用:检查异常和修复异常 注意:该图参考范欣欣的一个ppt图. 一致性修复 一致性检查主要检查是检查Region在meta中的Region、在线Regionserver的Region和hdfs的Regioninfo的Region信息...

峰的记忆 1244

脑机接口最新发展动态报告 (2024-2025)

脑机接口动态

高山 4106

HBase Architecture(译):上

转自:http://hi.baidu.com/rebeccacao/blog/item/059aee1ce51b5d014134179e.html HBase Architecture(译):上 2012-01-04 14:01 译者: 2011-10-1 出处:http://duanple.blog.163.com/blog/static/70971767

hua840812的专栏 801

Codex辅助小说创作:零成本AI写作指南与实战技巧

自然语言处理技术通过深度学习模型理解语义上下文,其核心原理是基于大规模文本训练的语言模型预测能力。在创意写作领域,这项技术的价值在于突破传统写作工具的功能局限,实现从内容生成到风格模仿的智能化辅助。特别是提示词工程的应用,让创作者能够精准控制AI输出的内容和风格。在实际应用场景中,AI写作工具显著降低了小说创作门槛,适用于网络小说、奇幻科幻等多种文学类型。本文以OpenAI Codex为例,详细解析如何利用AI技术完成从故事大纲设计、章节生成到平台发布的全流程创作,其中提示词优化和内容质量把控是提升生成效果

weixin_32678995的博客 561

[基于STM32底盘控制与ROS上层导航小车制作] 第一节 stm32电机驱动与编码器读取反馈

系列文章目录 第一节stm32电机驱动与编码器读取反馈 第二节 stm32电机pid控制 第三节 stm32线速度标定 第四节 stm32添加mpu6050得到angle角度 第五节 实现STM32与ubuntu系统下的ROS串口DMA通信,传输底盘速度等信息 第六节 ROS计算和发布里程计 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 系列文章目录 前言 1.pwm与电机正反转 2.编码器初始化 二、pwm控制与编码器使用 1.pwm使电机 .

LanLanLan1927的博客 1万+

HBase1.2官方文档——Architecture

架构 Architecture 63. 概述 Overview 63.1. NoSQL? HBase是一种 "NoSQL" 数据库。"NoSQL"是一个通用词表示数据库不是RDBMS ,后者支持 SQL 作为主要访问语言。有许多种 NoSQL 数据库: BerkeleyDB 是本地 NoSQL 数据库例子, 而 HBase 是大型分布式数据库。技术上来说, HBase 更像是...

weixin_30782331的博客 694

电力系统设计实战:如何用ETAP绘制一次接线图并优化供电方案

本文详细介绍了如何使用ETAP软件进行电力系统一次接线图的绘制与供电方案优化。从基础环境配置到主接线拓扑构建,再到典型接线方式的对比分析与智能优化,为工业与民用电力系统设计提供实用指南。通过ETAP的可靠性分析和动态仿真功能,帮助工程师选择最优供电方案,提升系统可靠性和运维效率。

weixin_29250573的博客 205

HBase HMaster Architecture

http://blog.zahoor.in/2012/08/hbase-hmaster-architecture/   HBase architecture follows the traditional master slave model where you have a master which takes decisions and one or more slaves which ...

llystar的专栏 364

Python爬虫:爬取健身平台运动数据(跑步、骑行轨迹)

通过分析这些运动数据,用户能够了解自己的运动趋势、运动成绩,并作出相应的调整。通过使用Strava的API,我们成功地获取了用户的运动活动信息和运动轨迹数据,并进行了存储与可视化。Strava的API提供了丰富的数据接口,能够通过OAuth2认证获取用户的运动数据,包括历史数据、运动轨迹等信息。Strava的API还提供了获取活动轨迹数据的接口,返回的数据格式通常是GeoJSON格式,适用于地图可视化。随着大数据技术的发展,运动数据的分析和可视化为个人健康管理、运动训练计划的优化等提供了强大的支持。

2201_76125261的博客 1075

19. SAP UI5 应用开发教程之十九 - SAP UI5 数据类型和复杂的数据绑定

通过本教程前面的步骤SAP UI5 初学者教程之十七 - 聚合绑定在 UI5 复合控件中的使用的介绍,我们已经学会了如何在 SAP UI5 里显示列表,如下图所示: 本步骤我们给该列表添加更多的业务数据,比如每张发票的金额。 按照本文的步骤完成的 SAP UI5 应用,列表如下图所示: 可以看到,同前一个步骤相比,现在 Invoices 表格里,每张发票的金额和货币单位已经显示出来了。 为了实现这个效果,本步骤的源代码位于我的 Github 这个文件夹下面: https://github.com/wan

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 3692

Hbase Architecture

http://hbase.apache.org/book.html#architecture

soledede 194

常用元器件使用方法3:电平转换芯片74LVC1T45的使用方法

介绍: 74LVC1T45是一个单位双向可控电平转换芯片。   芯片特性: 1、宽供给电压范围:1.65V到5.5V; 2、3.3V时,可输出24mA电流; 3、最大16uA电能损耗; 4、高噪音抑制;   型号:   引脚: VCC(A) 1 A端和DIR电源 GND 2 地 A 3 数据输入/输出 B 4 ...

snmplink的博客 1万+

hbase architecture

hbase's architecture overview: note: * why hbase use zookeeper but hadoop? hbase use zk to implements the heartbeat mechanism ,and hadoop use build-in heartbeat to detect node states ...

莱布尼兹 235

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Hbase Architecture 译文

原文链接:http://wiki.apache.org/lucene-hadoop/Hbase/HbaseArchitecture引言本文介绍了HBase,它是Hadoop的一个简单数据库。它和Google的Bigtable非常相似,也有一些区别。如果你知道Bigtable,很好;如果你不知道,也不影响你理解本文。数据模型HBase使用了和Bigtable非常相似的数据模型。用户在

daidodo的专栏 5114

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

HBase HMaster Architecture - HBase Master架构

HBase architecture follows the traditional master slave model where you have a master which takes decisions and one or more slaves which does the real task. In HBase, the master is called HMaster  and

技术笔记本 3813

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Hbase Architecture[下]

概述: Read Path Region查找 2.1 Region生命周期 ZooKeeper Replication 4.1 Life of a Log Edit 4.1.1 正常处理流程 4.1.2 Non-responding Slave Clusters 4.2 Internals 4.2.1 选择复制到目标Region Servers

yjq_java的专栏 483

HBase Architecture 101 - Storage

One of the more hidden aspects of HBase is how data is actually stored. While the majority of users may never have to bother about it you may have to get up to speed when you want to learn what the

韩王-信 1208

hbase-architecture

https://www.mapr.com/blog/in-depth-look-hbase-architecture http://stackoverflow.com/questions/40067933/hbase-whats-the-difference-between-wal-and-memstore https://www.mapr.com/blog/in-depth-look-hba...

weixin_34220963的博客 163

HBase之体系结构(Architecture)

HBase在分布式部署上采用master/slave的方式,主要包含3大功能组件,分别是:RegionServer、MasterServer和ClientLibrary 在分布式存储上使用的是Hadoop的HDFS子框架 分布式计算功能基于Hadoop的MapReduce实现 1.Region Region作为HBase的分布式存储单元包含了一组Row,这些Row的key值在索引排序上是连

JavaMan_chen的专栏 4173

HBase Architecture(译):下

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34123613的博客 206

HBase Architecture(译):中

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34128501的博客 145

HBase Architecture 101 - Write-ahead-Log

文章来源:http://www.larsgeorge.com/2010/01/hbase-architecture-101-write-ahead-log.html<br />What is the Write-ahead-Log you ask? In my previous post we had a look at the general storage architecture of HBase. One thing that was mentioned is the Write-ahead

Mac Track 1442
上一篇: 并行计算之实验三
下一篇: Hbase Architecture[下]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值