如何优雅的理解HBase和BigTable
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
学习 HBase 最难的地方在于要让你的脑子真正理解它是什么。
HBase:Google BigTable 的开源实现
我们经常会把关系型数据库(RDBMS,比如 MySQL)和 HBase 搞混,因为在这两个系统中都包含 table 和 base(HBase,Database)。
这篇文章的目标是从概念上来说清楚 HBase 这个分布式的数据存储系统。读完后,你应该可以很清楚的知道什么情况下 HBase 更好,什么情况下传统的关系型数据库更好。
关于一些术语
幸运的是,Google 的 BigTable论文清楚的解释了 BigTable 到底是什么。下面是论文中数据模型章节的第一句话:
BigTable 是一个稀疏的、分布式的、可持久化的多维有序 map。
在这个节骨眼上,我想给读者一个机会,让他们在读到最后一行字时,能够收集到他们脑壳里的活动信息(这可能是个笑话,但我没懂^v^)。
论文中,继续解释如下:
map 通过 rowKey,columnKey 和时间戳进行索引,map 中的每个值都是一个连续的字节数组。
注:rowKey 是记录的主键,唯一标识一行记录
在 Hadoop 的官方文档中,也对 HBase 的架构做了说明:
HBase 使用了与 BigTable 非常类似的数据模型。用户存储数据行到特定的表中。一个数据行有一个可排序的 rowKey 和数量不定的列。这个表是稀疏的,只要用户愿意,这个表不同行可以有完全不同的列。
这些话看起来相当费解,让人摸不着头脑,但如果你把这些话拆成一个个词,意思就慢慢变的清晰了。我将按照以下的顺序来讨论这些词:map,持久化,分布式,有序的,多维的,稀疏。
我发现循序渐进地建立一个思维框架要比一次性勾画一个完整的系统更加容易。
map
从根本来上来,HBase/BigTable 是一个 map。map 在不同的编程语言中有不同的叫法,比如 PHP 中的 array,Python 的 dictionary,Ruby 中的 Hash,或者 JavaScript 中的 Object。
维基百科上对于 map 的定义是:map 是一个抽象的数据类型,包含了一组 key 和一组 value,每个 key 关联一个 value。
如果用 JavaScript 的对象来表示 map,这里有一个简单的例子,其中所有的 value 都是字符串:
{ "zzzzz" : "woot", "xyz" : "hello", "aaaab" : "world", "1" : "x", "aaaaa" : "y" }
持久化的
持久化的意思仅仅是指你放进这个特殊 map 的数据会在你的程序执行完成之后被保存下来。它和其他的持久化存储系统中持久化的概念没有任何区别,比如存一个文件到一个文件系统。我们继续...
分布式的
HBase 和 BigTable 都建立在分布式文件系统上,所以底层文件可以被分散存储到不同的机器上。
HBase 可以存储到 HDFS(Hadoop's Distributed File System)上,也可以存储到 亚马逊的 S3(Simple Storage Service)上,而 BigTable 使用的是 GFS(Google File System)。
同一份数据会被复制存储到多个节点上,类似于 RAID(独立冗余磁盘阵列,利用冗余存储的数据使损坏数据得以恢复,从而保护数据不丢失)系统中数据在磁盘上的复制存储到多块磁盘的方式。
在这篇文章中,我们不关心具体使用哪种分布式文件系统。重要的是,要理解这个文件系统是分布式的,即使集群中某个节点出现故障,也可以保证数据的完整性和安全性。
有序的
和其他大多数 map 的实现不同,HBase 和 BigTable 的键值对的顺序严格按照字母顺序来排列。所以 rowKey 为 "aaaaa" 的下一条记录的 rowKey 就是 "aaaab",并且会离 “zzzz” 非常远。
继续看上面的那个 JSON 例子,排行序之后是下面这样的:
{ "1" : "x", "aaaaa" : "y", "aaaab" : "world", "xyz" : "hello", "zzzzz" : "woot" }
因为这个系统是分布式的,而且会越来越大,因此排序这个特性非常重要。这样就会把 rowKey 相近的记录放在一起,在某些情况下,如果你必须要扫描表(通常不推荐),那就能保证你需要获取的记录都在一块。
那么如何选择 rowKey 就非常重要。比如说,一个表的 rowKey 就是域名。一个比较好的方式就是将域名进行反转来作为 rowKey(使用 “com.jimbojw.www”,而不要使用 “www.jimbojw.com”),这样,同一个域名下的记录就可以存储在相邻的位置。
继续上面的域名例子,rowKey 为 “mail.jimbojw.com” 行应该与 “www.jimbojw.com” 行更近,而不是 “mail.xyz.com”,如果不把域名反转存储,就会发生这种情况。
需要注意的是,在 HBase / BigTable 中,有序并不意味着值是有序的。除了 rowKey 以外,没有任内容会被排序,在这点上和普通 map 的实现一致。
多维的
到目前为止,我们还没有提过任何关于列的概念,而是将表在概念上当做常规的 map。我是故意这么做的。列和表、base 等词一样,都带有传统关系型数据库多年的情感包袱。
然而,我发现把 HBase 理解为一个多维的 map 会容易很多,map 的 map。给上面的 JSON 再加上一列:
{ "1" : { "A" : "x", "B" : "z" }, "aaaaa" : { "A" : "y", "B" : "w" }, "aaaab" : { "A" : "world", "B" : "ocean" }, "xyz" : { "A" : "hello", "B" : "there" }, "zzzzz" : { "A" : "woot", "B" : "1337" } }
在上面的例子中你可以看到每个 key 都指向了另一个 map,其中包含着 A 和 B 两个 key。在这里,我们将最上面那层键值对称为行。并且在 HBase / BigTable 的术语表中,A 和 B 的映射称之为列族。
一个表的列族在表创建的时候就会被创建好,而且后续修改很困难,添加一个新列族的开销同样也很大,所以在创建表的时候应当将后续会用到的所有列族创建好。
好在一个列族可以有任意数量的列。称之为为列限定符(qualifier)或者标签(label)。
下面是我们上面 JSON 例子的子集,这次加入了 qualifier 的维度:
{ // ... "aaaaa" : { "A" : { "foo" : "y", "bar" : "d" }, "B" : { "" : "w" } }, "aaaab" : { "A" : { "foo" : "world", "bar" : "domination" }, "B" : { "" : "ocean" } }, // ... }
注意在上面的两行数据中,A 列族有两列:foo 和 bar,B 列族只有一列,而且 qualifier 是一个空字符串。
当访问 HBase / BigTable 中的数据时,你需要提供完整的列名::。举个例子,上面总共有三列,分别是:A:foo,A:bar 和 B:。
列族虽然基本固定不变,但是列不是,来看下面的例子:
{ // ... "zzzzz" : { "A" : { "catch_phrase" : "woot", } } }
在这个例子中,zzzzz 行有一个列 A:catch_phrase。因为每一行可以有任意数量的列,所以没有内置方法可以从所有行中的所有列中查询出一个列表。为了获取到那些信息,你需要做全表扫描。但是你可以查询所有的列族,因为它们是不变的(基本不变)。
HBase / BigTable 中最后的一个维度是时间。所有数据默认通过时间戳(1970年以来的秒数)来表示版本,或者你也可以指定一个其他的整数。客户端在插入数据的时候可以指定这个时间戳。
在最新的例子中,我们使用任意的整数来作为版本标识:
{ // ... "aaaaa" : { "A" : { "foo" : { 15 : "y", 4 : "m" }, "bar" : { 15 : "d", } }, "B" : { "" : { 6 : "w" 3 : "o" 1 : "w" } } }, // ... }
每个列族可以自己指定一个 cell 中的数据可以保留多少个版本(cell 由 rowKey 和列进行标识)。在大多数情况下,应用会直接访问一个 cell 中的数据,而不会指定一个时间戳(版本),HBase / BigTable 会直接返回最近版本(时间戳最大的那个)的数据,因为它是按照时间倒序来存储数据的。
如果应用在请求数据的时候指定了一个时间戳,那么 HBase 就会返回时间戳小于或者等于指定时间戳的一个 cell 中的数据。
如果查询上面例子中的 HBase 表,查询 aaaaa A:foo,就会返回 y,如果带时间戳查询 aaaaa A:foo 10,就会返回 m,如果查询 aaaaa A:foo 2,就会返回 null。
稀疏的
最后的一个关键词是稀疏的。就如上面所说的,一个给定的行在每个列族中可以有任意数量的列,0 或者任意大。行之间可以存在间隙,这也是另一种稀疏。
如果你一直跟着本文在 map 的基础上来理解 HBase / BigTable,而没有与关系型数据库(RDBMS)的概念混淆,这样就很好了。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-06-14
本文作者:Rayjun
本文来自:“掘金”,了解相关信息可以关注“掘金”
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
完美避坑!记一次 Elasticsearch 集群迁移架构实战
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 前言 Elastic 自身设计了集群分片的负载平衡机制,当有新数据节点加入集群或者离开集群,集群会自动平衡分片的负载分布。 需求背景 公司原有大数据平台基于公有云构建,由于种种原因,现在需要迁移到自建机房,Elasticsearch 集群承担了大数据平台主要的对外查询需求,也有部分实时计算需求基于 Elasticsearch 实现,所以需要在不影响应用系统体验的情况下做到平滑的迁移。本次分享讲述我们如何进行平滑迁移以及如何避坑。 需要迁移的主要有两部分: 对外提供的服务 API,这些 API 是与 Elastic 集群绑定的,属于业务场景定制化开发; Elasticsearch 集群迁移,数据需要迁移,节点也需要全部迁移。 图示:公有云集群 + 自建机房集群示意图,业务系统查询图 迁移策略 大数据平台的 Elastic 集群直接对外提供实时查询服务,任何影响 Elastic 集群平稳的操作都应该避免,那我们的集群迁移策略也侧重平稳,时间上可以宽松一些,迁移主要的工作有以下几个: 关闭集群...
- 下一篇
【云栖号直播】阿里云618大促必看:揭秘阿里云建站的“硬”标准!
云栖号在线课堂,及时了解行业动态!阿里云推出疫情专题方案,为企业业务护航,让你足不出户了解行业动态。 在这里可以走近阿里云基础产品,了解更多应用方案,还能遇见大咖分享洞见及故事!也可以通过视频的形式让你高效、生动的了解场景化的上云最佳实践。 本周重磅推荐 标题:云上数仓怎么建?云原生数据仓库AnalyticDB MySQL最佳实践 简介:随着业务系统迁移上云,在云上构建企业级数据仓库成为刚需。选择什么样的技术架构?云上数据仓库设计有哪些关键点?基于云原生数据库仓库AnalyticDB MySQL版的云上数仓解决方案解决了业务数据与数据仓库数据同步、实时更新的难题,降低了ETL开发成本,提高了数据时效性,帮助云上企业快速实现数据价值。 观看直播 标题:阿里云新品发布会第97期:专属钉钉解决方案全新上线 简介:钉钉的用户数量已经突破3亿,客户对钉钉提供企业版的诉求越来越强。针对企业级共性需求,客户可按需选择专属设计、专属存储、专属安全和最高级别的专属App,定制出千人千面的钉钉,助力企业打造自己的钉钉。 观看直播 标题:阿里云数据中台重磅升级深度解读专场 简介:阿里巴巴集团副总裁、数据技术...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS6,CentOS7官方镜像安装Oracle11G
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS6,7,8上安装Nginx,支持https2.0的开启