HBase (2)---資料儲存結構
在本文中的HBase術語:
基於列:column-oriented
行:row
列組:column families
列:column
單元:cell
理解HBase(一個開源的Google的BigTable實際應用)最大的困難是HBase的資料結構概念究竟是什麼?首先HBase不同於一般的關係資料庫,它是一個適合於非結構化資料儲存的資料庫.另一個不同的是HBase基於列的而不是基於行的模式.
Google's BigTable論文 清楚地解釋了什麼是BigTable:
Bigtable是一個疏鬆的分散式的持久的多維排序的map,這個map被行鍵,列鍵,和時間戳索引.每一個值都是連續的byte陣列.(A
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.)
Hadoop wiki的HBase架構 頁面提到:
HBase使用和Bigtable非常相同的資料模型.使用者儲存資料行在一個表裡.一個數據行擁有一個可選擇的鍵和任意數量的列.表是疏鬆的儲存的,因此
使用者可以給行定義各種不同的列.(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.)
實質上,HBase和BigTable是個map.相同於陣列(PHP),詞典(Pyhton),Hash(Ruby)或者Object (Javascript)中的表現形式.所以每一行是一個map,這個map中還可以有多個map(基於列組).獲取一個數據就像你從map中獲取資料一 樣.給定一個行名(即從這個map中獲取資料),然後給定一個key(列組名+限定詞)來取得資料.
HBase 和BigTable都是在分散式檔案系統上構建的,所以基礎的檔案儲存能夠散佈在分散式檔案系統的機器上.
HBase使用Hadoop's Distributed File System(HDFS) 或 Amazon's Simple Storage
Service(S3),Kosmos Distributed File System(KFS), 與此一樣BigTable使用Google
File System(GFS).資料被複制到多個節點就像資料被儲存在一個RAID系統上.
不像大多數的map應用,在HBase和BigTable中,key/value 是非常嚴格地按字母次序排列的.那就是意味著鍵值為"aaaaa"的行下一個行的鍵值為"aaaab",但是和鍵值為"zzzzz"的行離的很遠.因為這 些系統都是非常龐大和分散式的, 這些特性是非常重要的. 空間接近的列保證當你確定要瀏覽表時, 你感興趣的行將會靠近這行.當你選擇行的鍵值時,這是非常重要的事情.例子:考慮你表中的列是域名.最好是倒過來的(因此 "com.jimbojw.www"比"www.jimbojw.com"更好) ,因為你的子域名將會靠近你的主域名.注意在HBase中排序僅僅是kay排序,value是不排序的.
在下面的JSON資料中,我們看到整個資料結構是一個map,並且map中每一個key對應一個包含 "A"和"B"的map.假設整個下面資料是一個table,那麼它有"1"."aaaaa","aaaab","xyz","zzzzz"這幾個行,每 一個行有一個"A"和"B"的map.在HBase的術語中, 稱"A"和"B"為列組.
{ "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" } }
在HBase中一個列組通過限定詞或叫做標籤使每一個列組能夠包含許多的列.
{ "aaaaa" : { "A" : { "foo" : "y", "bar" : "d" }, "B" : { "" : "w" } }, "aaaab" : { "A" : { "foo" : "world", "bar" : "domination" }, "B" : { "" : "ocean" } }, "zzzzz" : { "A" : { "catch_phrase" : "woot", } "B" : { "" : "1337" } } }
在上面的例子中,在"aaaaa"的行中,列組"A"包含兩個列:"foo"和"bar",列組"B"僅僅有一個限定詞為空字元竄""的列.當我們 向HBase獲取資料時,你必須提供完整的列名字"<列組>:<限定詞>".因此上面的例子中行"aaaaa"和"aaaab" 都包含三個列:"A:foo", "A:bar"和"B:".儘管在行中列組是固定的,但是同一個列中限定詞可以是不同的,就像行"zzzzz"中列組"A"中只有一個列 "catch_phrase".最後的維度是時間戳(timestamp).所有的在HBase中儲存的資料都有一個用時間戳表示的版本或者你自己通過指 定時間戳來插入或獲取資料.
{ "aaaaa" : { "A" : { "foo" : { 15 : "y", 4 : "m" }, "bar" : { 15 : "d", } }, "B" : { "" : { 6 : "w" 3 : "o" 1 : "w" } } } }
每一個列可以指定多少版本的資料被儲存在每一個單元.在上面的例子中行"aaaaa"的列"A:foo"包含兩個倒序時間戳排列的資料15和4,列 "B"包含由三個倒序時間戳排列的資料.一般的應用程式只是簡單(不通過時間戳)的請求一個單元的資料.在這種條件下,HBase只是簡單地返回最新的版 本,即時間戳最大的版本.要獲取"A:foo"返回"y",要獲取"B"返回"w".如果應用程式在一個行中請求時帶上時間戳,HBase將會返回小於或 等於請求時間戳的資料.接著上面的例子如果程式請求"A:foo"帶上時間戳10,返回"m",加上時間戳3,返回null.
每一個行可以多個列族,每一個列族可以包含無數個列,每一個列都可以有一個不同於其他列的時間戳.在通用資料庫中當表建立時我們就已經定義了列,如果修改表結構的話會非常困難(比如:新增一列).在HBase中我們可以很輕鬆地新增一個列族或列.