如何优雅的理解HBase和BigTable
云棲號資訊:【點(diǎn)擊查看更多行業(yè)資訊】
在這里您可以找到不同行業(yè)的第一手的上云資訊,還在等什么,快來!
學(xué)習(xí) HBase 最難的地方在于要讓你的腦子真正理解它是什么。
HBase:Google BigTable 的開源實(shí)現(xiàn)
我們經(jīng)常會把關(guān)系型數(shù)據(jù)庫(RDBMS,比如 MySQL)和 HBase 搞混,因?yàn)樵谶@兩個(gè)系統(tǒng)中都包含 table 和 base(HBase,Database)。
這篇文章的目標(biāo)是從概念上來說清楚 HBase 這個(gè)分布式的數(shù)據(jù)存儲系統(tǒng)。讀完后,你應(yīng)該可以很清楚的知道什么情況下 HBase 更好,什么情況下傳統(tǒng)的關(guān)系型數(shù)據(jù)庫更好。
關(guān)于一些術(shù)語
幸運(yùn)的是,Google 的 BigTable論文清楚的解釋了 BigTable 到底是什么。下面是論文中數(shù)據(jù)模型章節(jié)的第一句話:
BigTable 是一個(gè)稀疏的、分布式的、可持久化的多維有序 map。
在這個(gè)節(jié)骨眼上,我想給讀者一個(gè)機(jī)會,讓他們在讀到最后一行字時(shí),能夠收集到他們腦殼里的活動信息(這可能是個(gè)笑話,但我沒懂^v^)。
論文中,繼續(xù)解釋如下:
map 通過 rowKey,columnKey 和時(shí)間戳進(jìn)行索引,map 中的每個(gè)值都是一個(gè)連續(xù)的字節(jié)數(shù)組。
注:rowKey 是記錄的主鍵,唯一標(biāo)識一行記錄
在 Hadoop 的官方文檔中,也對 HBase 的架構(gòu)做了說明:
HBase 使用了與 BigTable 非常類似的數(shù)據(jù)模型。用戶存儲數(shù)據(jù)行到特定的表中。一個(gè)數(shù)據(jù)行有一個(gè)可排序的 rowKey 和數(shù)量不定的列。這個(gè)表是稀疏的,只要用戶愿意,這個(gè)表不同行可以有完全不同的列。
這些話看起來相當(dāng)費(fèi)解,讓人摸不著頭腦,但如果你把這些話拆成一個(gè)個(gè)詞,意思就慢慢變的清晰了。我將按照以下的順序來討論這些詞:map,持久化,分布式,有序的,多維的,稀疏。
我發(fā)現(xiàn)循序漸進(jìn)地建立一個(gè)思維框架要比一次性勾畫一個(gè)完整的系統(tǒng)更加容易。
map
從根本來上來,HBase/BigTable 是一個(gè) map。map 在不同的編程語言中有不同的叫法,比如 PHP 中的 array,Python 的 dictionary,Ruby 中的 Hash,或者 JavaScript 中的 Object。
維基百科上對于 map 的定義是:map 是一個(gè)抽象的數(shù)據(jù)類型,包含了一組 key 和一組 value,每個(gè) key 關(guān)聯(lián)一個(gè) value。
如果用 JavaScript 的對象來表示 map,這里有一個(gè)簡單的例子,其中所有的 value 都是字符串:
{"zzzzz" : "woot","xyz" : "hello","aaaab" : "world","1" : "x","aaaaa" : "y" }持久化的
持久化的意思僅僅是指你放進(jìn)這個(gè)特殊 map 的數(shù)據(jù)會在你的程序執(zhí)行完成之后被保存下來。它和其他的持久化存儲系統(tǒng)中持久化的概念沒有任何區(qū)別,比如存一個(gè)文件到一個(gè)文件系統(tǒng)。我們繼續(xù)...
分布式的
HBase 和 BigTable 都建立在分布式文件系統(tǒng)上,所以底層文件可以被分散存儲到不同的機(jī)器上。
HBase 可以存儲到 HDFS(Hadoop's Distributed File System)上,也可以存儲到 亞馬遜的 S3(Simple Storage Service)上,而 BigTable 使用的是 GFS(Google File System)。
同一份數(shù)據(jù)會被復(fù)制存儲到多個(gè)節(jié)點(diǎn)上,類似于 RAID(獨(dú)立冗余磁盤陣列,利用冗余存儲的數(shù)據(jù)使損壞數(shù)據(jù)得以恢復(fù),從而保護(hù)數(shù)據(jù)不丟失)系統(tǒng)中數(shù)據(jù)在磁盤上的復(fù)制存儲到多塊磁盤的方式。
在這篇文章中,我們不關(guān)心具體使用哪種分布式文件系統(tǒng)。重要的是,要理解這個(gè)文件系統(tǒng)是分布式的,即使集群中某個(gè)節(jié)點(diǎn)出現(xiàn)故障,也可以保證數(shù)據(jù)的完整性和安全性。
有序的
和其他大多數(shù) map 的實(shí)現(xiàn)不同,HBase 和 BigTable 的鍵值對的順序嚴(yán)格按照字母順序來排列。所以 rowKey 為 "aaaaa" 的下一條記錄的 rowKey 就是 "aaaab",并且會離 “zzzz” 非常遠(yuǎn)。
繼續(xù)看上面的那個(gè) JSON 例子,排行序之后是下面這樣的:
{"1" : "x","aaaaa" : "y","aaaab" : "world","xyz" : "hello","zzzzz" : "woot" }因?yàn)檫@個(gè)系統(tǒng)是分布式的,而且會越來越大,因此排序這個(gè)特性非常重要。這樣就會把 rowKey 相近的記錄放在一起,在某些情況下,如果你必須要掃描表(通常不推薦),那就能保證你需要獲取的記錄都在一塊。
那么如何選擇 rowKey 就非常重要。比如說,一個(gè)表的 rowKey 就是域名。一個(gè)比較好的方式就是將域名進(jìn)行反轉(zhuǎn)來作為 rowKey(使用 “com.jimbojw.www”,而不要使用 “www.jimbojw.com”),這樣,同一個(gè)域名下的記錄就可以存儲在相鄰的位置。
繼續(xù)上面的域名例子,rowKey 為 “mail.jimbojw.com” 行應(yīng)該與 “www.jimbojw.com” 行更近,而不是 “mail.xyz.com”,如果不把域名反轉(zhuǎn)存儲,就會發(fā)生這種情況。
需要注意的是,在 HBase / BigTable 中,有序并不意味著值是有序的。除了 rowKey 以外,沒有任內(nèi)容會被排序,在這點(diǎn)上和普通 map 的實(shí)現(xiàn)一致。
多維的
到目前為止,我們還沒有提過任何關(guān)于列的概念,而是將表在概念上當(dāng)做常規(guī)的 map。我是故意這么做的。列和表、base 等詞一樣,都帶有傳統(tǒng)關(guān)系型數(shù)據(jù)庫多年的情感包袱。
然而,我發(fā)現(xiàn)把 HBase 理解為一個(gè)多維的 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"} }在上面的例子中你可以看到每個(gè) key 都指向了另一個(gè) map,其中包含著 A 和 B 兩個(gè) key。在這里,我們將最上面那層鍵值對稱為行。并且在 HBase / BigTable 的術(shù)語表中,A 和 B 的映射稱之為列族。
一個(gè)表的列族在表創(chuàng)建的時(shí)候就會被創(chuàng)建好,而且后續(xù)修改很困難,添加一個(gè)新列族的開銷同樣也很大,所以在創(chuàng)建表的時(shí)候應(yīng)當(dāng)將后續(xù)會用到的所有列族創(chuàng)建好。
好在一個(gè)列族可以有任意數(shù)量的列。稱之為為列限定符(qualifier)或者標(biāo)簽(label)。
下面是我們上面 JSON 例子的子集,這次加入了 qualifier 的維度:
{// ..."aaaaa" : {"A" : {"foo" : "y","bar" : "d"},"B" : {"" : "w"}},"aaaab" : {"A" : {"foo" : "world","bar" : "domination"},"B" : {"" : "ocean"}},// ... }注意在上面的兩行數(shù)據(jù)中,A 列族有兩列:foo 和 bar,B 列族只有一列,而且 qualifier 是一個(gè)空字符串。
當(dāng)訪問 HBase / BigTable 中的數(shù)據(jù)時(shí),你需要提供完整的列名::。舉個(gè)例子,上面總共有三列,分別是:A:foo,A:bar 和 B:。
列族雖然基本固定不變,但是列不是,來看下面的例子:
{// ..."zzzzz" : {"A" : {"catch_phrase" : "woot",}} }在這個(gè)例子中,zzzzz 行有一個(gè)列 A:catch_phrase。因?yàn)槊恳恍锌梢杂腥我鈹?shù)量的列,所以沒有內(nèi)置方法可以從所有行中的所有列中查詢出一個(gè)列表。為了獲取到那些信息,你需要做全表掃描。但是你可以查詢所有的列族,因?yàn)樗鼈兪遣蛔兊?#xff08;基本不變)。
HBase / BigTable 中最后的一個(gè)維度是時(shí)間。所有數(shù)據(jù)默認(rèn)通過時(shí)間戳(1970年以來的秒數(shù))來表示版本,或者你也可以指定一個(gè)其他的整數(shù)??蛻舳嗽诓迦霐?shù)據(jù)的時(shí)候可以指定這個(gè)時(shí)間戳。
在最新的例子中,我們使用任意的整數(shù)來作為版本標(biāo)識:
{// ..."aaaaa" : {"A" : {"foo" : {15 : "y",4 : "m"},"bar" : {15 : "d",}},"B" : {"" : {6 : "w"3 : "o"1 : "w"}}},// ... }每個(gè)列族可以自己指定一個(gè) cell 中的數(shù)據(jù)可以保留多少個(gè)版本(cell 由 rowKey 和列進(jìn)行標(biāo)識)。在大多數(shù)情況下,應(yīng)用會直接訪問一個(gè) cell 中的數(shù)據(jù),而不會指定一個(gè)時(shí)間戳(版本),HBase / BigTable 會直接返回最近版本(時(shí)間戳最大的那個(gè))的數(shù)據(jù),因?yàn)樗前凑諘r(shí)間倒序來存儲數(shù)據(jù)的。
如果應(yīng)用在請求數(shù)據(jù)的時(shí)候指定了一個(gè)時(shí)間戳,那么 HBase 就會返回時(shí)間戳小于或者等于指定時(shí)間戳的一個(gè) cell 中的數(shù)據(jù)。
如果查詢上面例子中的 HBase 表,查詢 aaaaa A:foo,就會返回 y,如果帶時(shí)間戳查詢 aaaaa A:foo 10,就會返回 m,如果查詢 aaaaa A:foo 2,就會返回 null。
稀疏的
最后的一個(gè)關(guān)鍵詞是稀疏的。就如上面所說的,一個(gè)給定的行在每個(gè)列族中可以有任意數(shù)量的列,0 或者任意大。行之間可以存在間隙,這也是另一種稀疏。
如果你一直跟著本文在 map 的基礎(chǔ)上來理解 HBase / BigTable,而沒有與關(guān)系型數(shù)據(jù)庫(RDBMS)的概念混淆,這樣就很好了。
【云棲號在線課堂】每天都有產(chǎn)品技術(shù)專家分享!
課程地址:https://yqh.aliyun.com/live
立即加入社群,與專家面對面,及時(shí)了解課程最新動態(tài)!
【云棲號在線課堂 社群】https://c.tb.cn/F3.Z8gvnK
原文發(fā)布時(shí)間:2020-06-14
本文作者:Rayjun
本文來自:“掘金”,了解相關(guān)信息可以關(guān)注“掘金”
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的如何优雅的理解HBase和BigTable的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对话阿里云MVP裔隽跨界半生,不改赤子心
- 下一篇: 技术运维的经营大法——对话阿里云MVP熊