Hbase底層資料結構
理解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是基於Hadoop的專案,所以一般情況下我們使用的直接就是HDFS檔案系統,這裡我們不深談HDFS如何構造其分散式的檔案系統,只需要知 道雖然Hbase中有多個RegionServer的概念,並不意味著資料是持久化在RegionServer上的,事實上,RegionServer是 排程者,管理Regions,但是資料是持久化在HDFS上的。明確這一點,在後面的討論中,我們直接把檔案系統抽象為HDFS,不再深究。
Hbase是一個分散式的資料庫,使用Zookeeper來管理叢集。在架構層面上分為Master(Zookeeper中的leader)和多個RegionServer,基本架構如圖:
在Hbase的概念中,RegionServer對應於叢集中的一個節點,而一個RegionServer負責管理多個Region。一個Region代 表一張表的一部分資料,所以在Hbase中的一張表可能會需要很多個Region來儲存其資料,但是每個Region中的資料並不是雜亂無章 的,Hbase在管理Region的時候會給每個Region定義一個Rowkey的範圍,落在特定範圍內的資料將交給特定的Region,從而將負載分 攤到多個節點上,充分利用分散式的優點。另外,Hbase會自動的調節Region處在的位置,如果一個RegionServer變得Hot(大量的請求 落在這個Server管理的Region上),Hbase就會把Region移動到相對空閒的節點,依次保證叢集環境被充分利用。
二、儲存模型
有了架構層面的保證,接下來的事情就只是關注於資料的具體儲存了。這裡就是每個Region所承擔的工作了。我們知道一個Region代表的是一張 Hbase表中特定Rowkey範圍內的資料,而Hbase是面向列儲存的資料庫,所以在一個Region中,有多個檔案來儲存這些列。Hbase中資料 列是由列簇來組織的,所以每一個列簇都會有對應的一個數據結構,Hbase將列簇的儲存資料結構抽象為Store,一個Store代表一個列簇。
所以在這裡也可以看出為什麼在我們查詢的時候要儘量減少不需要的列,而經常一起查詢的列要組織到一個列簇裡:因為要需要查詢的列簇越多,意味著要掃描越多的Store檔案,這就需要越多的時間。
我們來深入Store中儲存資料的方式。Hbase的實現是用了一種LSM 樹的結構!
LSM樹是由B+樹改進而來,所以我們首先來簡單的看看B+樹。
這是一顆簡單的B+樹,含義不言而喻,這裡不多分析,但是這種資料結構並不適合Hbase中的應用場景。這樣的資料結構在記憶體中效率是很高的,但是 Hbase中資料是儲存在檔案中的,如果按照這樣的結構來儲存,意味著我們每一次插入資料都要由一級索引找到檔案再在檔案中間作操作來保證資料的有序性, 這無疑是效率低下的。所以Hbase採用的是LSM樹的結構,這種結構的關鍵是,每一次的插入操作都會先進入MemStore(記憶體緩衝區),當 MemStore達到上限的時候,Hbase會將記憶體中的資料輸出為有序的StoreFile檔案資料(根據Rowkey、版本、列名排序,這裡已經和列 簇無關了因為Store裡都屬於同一個列簇)。這樣會在Store中形成很多個小的StoreFile,當這些小的File數量達到一個閥值的時 候,Hbase會用一個執行緒來把這些小File合併成一個大的File。這樣,Hbase就把效率低下的檔案中的插入、移動操作轉變成了單純的檔案輸出、 合併操作。
由上可知,在Hbase底層的Store資料結構中,每個StoreFile內的資料是有序的,但是StoreFile之間不一定是有序的,Store只 需要管理StoreFile的索引就可以了。這裡也可以看出為什麼指定版本和Rowkey可以加強查詢的效率,因為指定版本和Rowkey的查詢可以利用 StoreFile的索引跳過一些肯定不包含目標資料的資料。
HBase vs Cassandra
HBase | Cassandra | |
---|---|---|
語言 | Java | Java |
出發點 | BigTable | BigTable and Dynamo |
License | Apache | Apache |
Protocol | HTTP/REST (also Thrift) | Custom, binary (Thrift) |
資料分佈 | 表劃分為多個region存在不同region server上 | 改進的一致性雜湊(虛擬節點) |
儲存目標 | 大檔案 | 小檔案 |
一致性 | 強一致性 | 最終一致性,Quorum NRW策略 |
架構 | master/slave | p2p |
高可用性 | NameNode是HDFS的單點故障點 | P2P和去中心化設計,不會出現單點故障 |
伸縮性 | Region Server擴容,通過將自身釋出到Master,Master均勻分佈Region | 擴容需在Hash Ring上多個節點間調整資料分佈 |
讀寫效能 | 資料讀寫定位可能要通過最多6次的網路RPC,效能較低。 | 資料讀寫定位非常快 |
資料衝突處理 | 樂觀併發控制(optimistic concurrency control) | 向量時鐘 |
臨時故障處理 | Region Server宕機,重做HLog | 資料回傳機制:某節點宕機,hash到該節點的新資料自動路由到下一節點做 hinted handoff,源節點恢復後,推送回源節點。 |
永久故障恢復 | Region Server恢復,master重新給其分配region | Merkle 雜湊樹,通過Gossip協議同步Merkle Tree,維護叢集節點間的資料一致性 |
成員通訊及錯誤檢測 | Zookeeper | 基於Gossip |
CAP | 1,強一致性,0資料丟失。2,可用性低。3,擴容方便。 | 1,弱一致性,資料可能丟失。2,可用性高。3,擴容方便。 |