温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

HBase HFile与Prefix Compression内部实现全解–KeyValue格式

发布时间:2020-06-14 10:11:54 来源:网络 阅读:346 作者:阿里中间件 栏目:关系型数据库

1.引子

HFile(HBaseFile)是HBase使用的一种文件存储格式的抽象,

目前存在两种版本的HFile:HFileV1和HFileV2

HBase0.92之前的版本仅支持HFileV1,

HBase0.92/0.94同时支持HFileV1和HFileV2。

以下分别是HFileV1/V2的结构图:

HFileV1

HFileV2

图中的数据块(Datablock)正是实际存放应用数据的地方,

每个数据块又由一系列的KeyValue组成,并且这些KeyValue之间是按Key升序排列的,

本文将说明KeyValue到底是什么以及当KeyValue越来越多时出现大量类似的数据有哪些算法能减少重复?

首先来看一个例子:

假设需要将用户的基本信息以及正在参与的开源项目的有关信息存入HBase:

Java代码
  1. 用户基本信息参与的开源项目

  2. ————————————————-

  3. 用户Id职业性别tomcathbase

  4. ————————————————-

  5. zhh3009码农男提patch打酱油提patch打酱油

  6. 用户Id职业性别tomcatant

  7. ————————————————-

  8. jdd1999码神男创始人创始人

  9. ———————————————————

  10. 1.1

用户基本信息                   参与的开源项目
---------------------       ----------------------------
用户Id    职业   性别          tomcat           hbase
---------------------       ----------------------------
zhh3009   码农   男            提patch打酱油    提patch打酱油
用户Id    职业   性别          tomcat           ant
---------------------       ----------------------------
jdd1999   码神   男            创始人           创始人
---------------------------------------------------------
表1.1

从这个例子来看,用户的基本信息比较好确定,但是参与的开源项目不确定且在开源项目中扮演的角色也不确定,

所以用关系数据库不太好建表,因为不知道具体有多少列,也无法把相关的列归成一个组。

1.1列族

HBase是一种基于列的数据库,相关的列可以归到一个列族(ColumnFamily),

每个列族中具体有哪些列不必事先知道,可以在需要的时候添加,比如在用户基本信息中为zhh3009加入email这样的列,

上例中”用户基本信息”和”参与的开源项目”可以作为两个列族,

不同的列族在HBase内部通常对应一个目录,这样不同的列值只会放到它所属的列族目录下。

1.2rowKey

我们希望通过查询某个列就能把同一个列族或多个列族中的信息取出来,用户Id就是这样的列,

比如当我们要查询zhh3009的邮箱和参与的开源项目时,根据用户Id来查就不会查到jdd1999的信息,

在HBase中称这样的列为rowKey。

HBase是如何存放上例中的信息呢?

将用户Id这一列抽出来作为rowKey,把上面的信息按如下格式扁平化:

Java代码
<rowKey,  列族名称,       列名   => 列值>
—————————————————–
<zhh3009, 用户基本信息,   职业   => 码农>
<zhh3009, 用户基本信息,   性别   => 男>
<zhh3009, 参与的开源项目, tomcat => 提patch打酱油>
<zhh3009, 参与的开源项目, hbase  => 提patch打酱油>

<jdd1999, 用户基本信息,   职业   => 码神>
<jdd1999, 用户基本信息,   性别   => 男>
<jdd1999, 参与的开源项目, tomcat => 创始人>
<jdd1999, 参与的开源项目, ant    => 创始人>
—————————————————–
                表1.2
&lt;rowKey,  列族名称,       列名   =&gt; 列值&gt;
-----------------------------------------------------
&lt;zhh3009, 用户基本信息,   职业   =&gt; 码农&gt;
&lt;zhh3009, 用户基本信息,   性别   =&gt; 男&gt;
&lt;zhh3009, 参与的开源项目, tomcat =&gt; 提patch打酱油&gt;
&lt;zhh3009, 参与的开源项目, hbase  =&gt; 提patch打酱油&gt;
&lt;jdd1999, 用户基本信息,   职业   =&gt; 码神&gt;
&lt;jdd1999, 用户基本信息,   性别   =&gt; 男&gt;
&lt;jdd1999, 参与的开源项目, tomcat =&gt; 创始人&gt;
&lt;jdd1999, 参与的开源项目, ant    =&gt; 创始人&gt;
-----------------------------------------------------
表1.2

表1.2中的每一行在HBase中对应一个KeyValue,

“=>”左边的是KeyValue中的”Key”,”=>”右边对应KeyValue中的”Value”。

当然这只是KeyValue的一个简化格式,内部格式并非那么简单,我们接下来看看真实的KeyValue是怎样的?

2.KeyValue内部格式

KeyValue内部格式可以分成三部份:头、Key、Value,如表2.1所示

Java代码
  1. 名称   字节数说明

  2. ——————————————————————–

  3. keyLength  4表示Key所占的总字节数

  4. valueLength4表示Value所占的总字节数

  5. rowKeyLength2表示rowKey所占的字节数

  6. rowKeyrowKeyLengthrowKey

  7. columnFamilyLength1表示列族名称所占的字节数

  8. columnFamilycolumnFamilyLength列族名称

  9. columnNamecolumnNameLength列名

  10. timestamp8时间戳

  11. type1Key类型,比如是新增(Put),还是删除(Delete)

  12. valuevalueLength列值

  13. ——————————————————————–

  14. 2.1

名称             字节数                  说明
--------------------------------------------------------------------
keyLength           4                     表示Key所占的总字节数
valueLength           4                     表示Value所占的总字节数
rowKeyLength          2                     表示rowKey所占的字节数
rowKey                rowKeyLength          rowKey
columnFamilyLength    1                     表示列族名称所占的字节数
columnFamily          columnFamilyLength    列族名称
columnName            columnNameLength      列名
timestamp             8                     时间戳
type                  1                     Key类型,比如是新增(Put),还是删除(Delete)
value                 valueLength           列值
--------------------------------------------------------------------
表2.1

keyLength和valueLength组成头部,

rowKeyLength到type这7项组成Key,最后一项value代表第三部份:Value,

上面有个地方值得注意,在columnFamily前面有columnFamilyLength,

但是在columnName之前并没有columnNameLength这一项,为了节省空间,这不是必需的,

当在解析KeyValue时,通过keyLength-8(timestamp)-1(type)就可以确定columnName在此KeyValue中的结束位置。

把表1.2中的前两行按表2.1中的格式生成两个KeyValue:

KeyValueA代表:<zhh3009,用户基本信息,职业=>码农>

KeyValueB代表:<zhh3009,用户基本信息,性别=>男>

Java代码
名称             字节数                  KeyValue A        KeyValue B
—————————————————————————-
keyLength           4                     35                35
valueLength           4                     4                 2

rowKeyLength          2                     7                 7
rowKey                rowKeyLength          zhh3009           zhh3009
columnFamilyLength    1                     12                12
columnFamily          columnFamilyLength    用户基本信息      用户基本信息
columnName            columnNameLength      职业              性别
timestamp             8                     1329663787364     1329663787364
type                  1                     4(Put)            4(Put)

value                 valueLength           码农              男
—————————————————————————-
                              表2.2
名称             字节数                  KeyValue A        KeyValue B
----------------------------------------------------------------------------
keyLength           4                     35                35
valueLength           4                     4                 2
rowKeyLength377
rowKeyrowKeyLengthzhh3009zhh3009
columnFamilyLength21212
columnFamilycolumnFamilyLength用户%E
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI