有关系行数据库经验的人(比如我),在最初接触HBase这样的数据库时,对数据结构的理解容易遇到障碍。会不自觉的将HBase的行、列等概念映射成关系型数据库的行、列。为了加速理解HBase的一些概念,翻译了这篇文章《Understanding HBase and BigTable》(HBase官方文档推荐阅读文章)。
学习Hbase(Google BigTable的开源实现)最困难的是理解它的实际概念。
很不幸的是,这两个伟大的系统在其概念中包含了table和base两个词,这往往会导致一些人(比如我) 把它们跟关系型数据库的东西搞混淆。
本文旨在从概念的角度描述这些分布式数据存储系统。阅读之后,你应该能够更好地判断,什么时候要使用Hbase,什么时候该更好地使用“传统”数据库。
一切都在术语中
幸运的是,Google的BigTable论文清楚地解释了BigTable究竟是什么。这是“数据模型”部分的第一句话:
注意:请牢记上边这句话的每一个词
BigTable论文继续说明
Hadoop wiki的HbaseArchitecture页面假设:
尽管所有这些看起来都相当神秘,但是一旦你将它分解为单词,它就变得容易明确了。我喜欢按照这个顺序讨论它们:map,持久化(persistent),分布式(distributed),有序(sorted),多维(multidimensional)和稀疏(sparse)。
我没有尝试一下子描绘完整的系统,而是发现在脑海中构建一个零碎的框架更容易理解HBase……
Map
Hbase / BigTable的核心是map,根据您的编程语言背景,您可能更熟悉这些术语,array (PHP), dictionary (Python), Hash (Ruby), or Object (JavaScript).
维基百科文章显示,Map是“由一组键和一组值组成的抽象数据类型,其中每个键与一个值相关联。”
用JSON来描述一个简单Map的示例,其中所有值都只是字符串:
持久化
持久化仅仅意味着在创建或访问数据的程序完成后,您放入此特殊Map的这些数据“会持久保存”。这在概念上与任何其他类型的持久存储(例如文件系统上的文件)没有什么不同。
有序
与大多数Map实现不同,在Hbase / BigTable中,键/值对按严格的字母顺序保存。也就是说,键“aaaaa”的行应该在具有键“aaaab”的行旁边,并且与具有键“zzzzz”的行相距很远。
继续我们的JSON示例,有序版本如下所示:
由于这些系统往往非常庞大且是分布式,因此这种有序的特性非常重要。具有相似键的行在空间上的邻近性确保了当您必须扫描表时,您最感兴趣的条目彼此接近。
选择行键的约定很重要。例如,考虑一个表,其键是域名。以反向表示法列出它们是最有意义的(所以“com.jimbojw.www”比“www.jimbojw.com”更好),这样子域的行(存储上)将靠近父域行。
值得注意的是,在Hbase / BigTable中,术语“有序”并不意味着“值(values)”已排序。除了键之外,没有任何自动索引,就像在普通Map实现中一样。
多维
到目前为止,我们还没有提到任何“列(columns)”的概念,将“表(table)”视为概念中的常规哈希/映射(map)。这是有意为之。 “列(column)”这个词是另一个加载的词,如“table”和“base”,它传承了多年关系型数据库经验的情感包袱。
相反,我发现(把HBase)看成一个多维Map更容易思考这个问题 - 如果你愿意的话,可以使用嵌套Map。在之前的JSON示例中添加一个维度:
在上面的例子中,您现在会注意到每个键都指向一个有两个键的Map:“A”和“B”。从此处开始,我们将顶层键/映射(key/map)称为“行”。此外,在BigTable / Hbase命名法中,“A”和“B”映射(mappings)将被称为“列族”。
创建表时会指定表的列族,以后很难或无法修改。添加新列族代价也很大,因此好的做法是从一开始就指定您需要的所有列族。
幸运的是,列族可以具有任意数量的列,由列“限定符(qualifier)”或“标签(label)”表示。以下是我们的JSON示例的子集,内置了列限定符维度(qualifier dimension):
请注意,在显示的两行中,“A”列族有两列:“foo”和“bar”,“B”列族只有一列,其限定符为空字符串(“”)。
在向Hbase / BigTable询问数据时,必须以“<family>:<qualifier>”的形式提供完整的列名称。因此,例如,上例中的两行都有三列:“A:foo”,“A:bar”和“B:”。
请注意,虽然列族是静态的,但列本身不是。考虑这个扩展的行:
在这种情况下,“zzzzz”行只有一列,“A:catch_phrase”。由于每行可能包含任意数量的不同列,因此没有内置方法可以查询所有行中所有列的数据(list)。要获取该信息,您必须进行全表扫描。但是,您可以查询所有列族的数据,因为它们是不可变的(或多或少)。
Hbase / BigTable中最后一个维度是时间。所有数据都使用整数时间戳(seconds since the epoch)或您选择的另一个整数进行版本控制。客户端可以在插入数据时指定时间戳。
看一下使用任意整数时间戳的示例:
每个列族可能有自己的规则,确定保留的给定单元格的版本数量(单元格由其rowkey / column键值对标识)在大多数情况下,应用程序将只询问给定单元格的数据,而不指定时间戳。在这种常见情况下,Hbase / BigTable将返回最新版本(具有最高时间戳的版本),因为它以时间逆序存储这些版本数据。
如果应用程序指定时间戳,Hbase将返回时间戳小于或等于所提供时间戳的单元数据。
使用我们想象中的Hbase表,查询“aaaaa”/“A:foo”的行/列(row/column)将返回“y”,同时查询“aaaaa”/“A:foo”/ 10的 行/列/时间戳 将返回“M”。查询“aaaaa”/“A:foo”/ 2的 行/列/时间戳 将返回空结果。
稀疏
最后一个关键字是稀疏。如前所述,给定行在每个列族中可以包含任意数量的列,或者根本不包含任何列。另一种类型的稀疏性是基于行的间隙(row-based gaps),这仅仅意味着键(key)之间可能存在间隙。
如果您已经按照本文的基于映射(map-based)的术语来思考Hbase / BigTable,而不是用关系型数据库中的相似概念去思考,那么本文的目的就达到了。
就这样(And that's about it)
好吧,我希望这有助于您从概念上理解Hbase数据模型的含义。
一如既往,我期待着您的想法,意见和建议。
本文分享自微信公众号 - 普通程序员(farmerbrag)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/3185208/blog/4356298