add by zhj: 這篇文章寫的通俗易懂,介紹了HBase最重要的幾點特性。
英文原文:https://dzone.com/articles/understanding-hbase-and-bigtab
譯文:https://lunatictwo.github.io/2017/09/25/Hbase&&BigTable/
學習HBase(Google BigTable 的具體實現)最困難的地方在於,HBase的概念很難讓人理解。
不幸的是,在HBase和BigTable的介紹中,都包含了table這個單詞,很容易讓學過關系型數據庫的人們(包括我自己)產生困惑。
這篇文章致力於從概念的角度介紹這個分布式數據存儲系統。閱讀之后,當你遇到想使用HBase或者是想使用傳統數據庫的時候,你就可以有一個清晰的認識。
一切都在術語中
Google的BigTable論文 清晰的指出了什么是BigTable。這里是其中Data Model一節的第一句話:
Bigtable is a sparse, distributed, persistent multidimensional sorted map.
接下來,論文繼續解釋道:
The map is indexed by a row key, column key, and a timestamp; each value in the map is an uninterpreted array of bytes.
在HBase的Wiki介紹中,有如下描述:
HBase uses a data model very similar to that of Bigtable. Users store data rows in labelled tables. A data row has a sortable key and an arbitrary number of columns. The table is stored sparsely, so that rows in the same table can have crazily-varying columns, if the user likes.
盡管看起來讓人難以理解,但是一次理解一個單詞,也是有意義的。下面我將按照以下順序解釋這些單詞:map, persistent, distributed, sorted, multidimensional, 和sparse。
1. 字典
HBase和BigTable的核心是一個map。依靠你的編程語言背景,你可以很容易理解,這就像PHP中的關聯數組,Python中的字典,Ruby中的哈希,或者是JavaScript中的對象。
從Wiki中的解釋來看,map就是”由key和value組成的數據結構,其中每一個key和一個value相關聯”。
使用JavaScript的對象語法,這是一個簡單的map實例:
{
"zzzzz" : "woot",
"xyz" : "hello",
"aaaab" : "world",
"1" : "x",
"aaaaa" : "y"
}
2. 持久化
Persistence(持久性)只是表示當你的程序結束或數據入口關閉后,你保存在map中的數據會被持久化,這個和其他的持久化存儲方式沒區別。
3. 分布式
Hbase和BigTable構建在分布式文件系統上,以便底層文件存儲可以在獨立機器陣列之間傳播。
HBase可以運行在HDFS上,也可以運行在Amazon的Simple Storage Service上,同時BigTable可以運行在Google File System上。
數據以類似的方式在多個參與節點中復制,以便數據在基於獨立冗余磁盤陣列的系統中的光盤之間進行條帶化。
在本文中,我們並不關心使用哪個分布式文件系統實現。要了解的事情是它是分布式的,它提供了一個保護機制,例如,集群內的某個節點發生故障,可以做到容災即可。
4. 有序
與大多數Map實現不同,在Hbase/BigTable中,鍵值對以嚴格的字母順序保存。 也就是說,鍵“aaaaa”的存儲行應該在鍵“aaaab”的旁邊,並且距離具有鍵“zzzzz”的存儲行非常遠。
回到我們的map示例,排序后的版本如下:
{
"1" : "x",
"aaaaa" : "y",
"aaaab" : "world",
"xyz" : "hello",
"zzzzz" : "woot"
}
因為這些系統往往是特別龐大的,並且數據是分布式存儲,所以這種排序功能其實非常重要。具有類似鍵的行的空間優勢確保了當一個操作必須掃描表格時,查詢最感興趣的內容將彼此靠近。
這在選擇行key時很重要。 例如,假如一個表的關鍵字是域名,最有意義的是以反向符號(即“com.jimbojw.www”而不是“www.jimbojw.com”)列出它們,以便關於子域名的行將在父域名行附近。
繼續解釋域名的例子,如果是以反向符號存儲的話,假如有一行數據是“mail.jimbojw.com”,那么它應該被存儲在“www.jimbojw.com”行的旁邊,而不是在“mail.xyz.com”旁邊。
需要注意的是,在HBase和BigTable中的value是不被排序的,只有key被排序。除了這個,其他的和普通的map實現是一樣的。
5. 多維度
到目前為止,我們沒有提到任何“列(columns)”的概念,而是將“表”視為概念中的常規Hash/Map。 這是完全有意為之的。單詞“列”是另一個人為引入的單詞,如“table”和“base”,它是多年關系型數據庫從業人員的命名習慣。
相反,我更喜歡把它想象為一個map的嵌套結構。比如如下結構:
{
"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"
}
}
在上述例子中,你會發現每一個內層的map都有兩個key,A和B。從現在開始,每一個外層的map視為一行,每一個內層的map中的A、B視為A、B列。
創建表的時候,需要首先指定好表的列,后續難以修改,或不可修改。同時,添加新的列的代價也是非常昂貴的。
不過幸運的是,在每一個列中,同樣可以添加無數的列,就像JSON中一樣,舉例如下:
{
// ...
"aaaaa" : {
"A" : {
"foo" : "y",
"bar" : "d"
},
"B" : {
"" : "w"
}
},
"aaaab" : {
"A" : {
"foo" : "world",
"bar" : "domination"
},
"B" : {
"" : "ocean"
}
},
// ...
}
上面的示例中,A列有兩個子列:foo和bar,B列有一個子列,用空字符串標識。
在查詢HBase和BigTable的時候,必須提供數據的全限定名,比如”A:foo”, “A:bar”和”B:”。
請注意,盡管列是靜態的,但列的子列不是。比如以下結構:
{
// ...
"zzzzz" : {
"A" : {
"catch_phrase" : "woot",
}
}
}
在這種情況下,“zzzzz”行只有一列“A:catch_phrase”。 因為每一行可能有不同的列數,所以沒有內置的方法來查詢所有列中所有子列的列表。要獲取該信息,必須進行全表掃描。然而,可以查詢所有列的內容,因為這些列是不可變的。
Hbase/BigTable表示的最終維度是時間。所有數據使用整數時間戳或用戶選擇的其他整數進行統一時間控制。客戶端可以在插入數據時指定時間戳。
假設有如下采用某一時間序列存儲的數據:
{
// ...
"aaaaa" : {
"A" : {
"foo" : {
15 : "y",
4 : "m"
},
"bar" : {
15 : "d",
}
},
"B" : {
"" : {
6 : "w"
3 : "o"
1 : "w"
}
}
},
// ...
}
每個列的子列可能有自己的規則來設置要保留的版本數量(單元格由其行鍵/列對標識)。在大多數情況下,應用程序將簡單地詢問給定單元格的數據,而不指定時間戳。 在這種常見情況下,Hbase/BigTable將返回最新的版本(具有最高時間戳的版本),因為它們以倒序的時間順序存儲。
如果應用程序在給定的時間戳中請求給定行,則Hbase將返回單元格數據,其中時間戳小於或等於提供的時間戳。
使用上述示例的Hbase表,查詢“aaaaa”/“A:foo”的行/列將返回“y”,同時查詢“aaaaa”/“A:foo”/ 10的行/列/時間戳將返回“M”。 查詢“aaaaa”/“A:foo”/ 2的行/列/時間戳將返回空結果。
6. 稀疏
最后一個關鍵字是sparse(稀疏的)。 如上文已經提到的,給定行可以在每個列族中具有任意數量的列,或者根本沒有列。 另一種類型的稀疏性是基於行的間隙,這僅僅意味着鍵之間可能存在間隙。
當然,如果您在本文的基於map的術語中考慮過Hbase/BigTable,而不是在RDBMS中看到類似的概念,那么這是非常有道理的。(言外之意就是說,在HBase/BigTable中的數據是稀疏的,而在RDBMS中不經常是。)
綜述
以上就是HBase/BigTable的概念介紹。