HBase 是一個面向列式儲存的分散式資料庫,其設計思想來源於 Google 的 BigTable 論文。HBase 底層儲存基於 HDFS 實現,叢集的管理基於 ZooKeeper 實現。HBase 良好的分散式架構設計為海量資料的快速儲存、隨機存取提供了可能,基於資料副本機制和分割區機制可以輕鬆實現線上擴容、縮容和資料容災,是巨量資料領域中 Key-Value 資料結構儲存最常用的資料庫方案。
Hbase 的擴充套件性主要體現在兩個方面,一個是基於運算能力(RegionServer) 的擴充套件,通過增加 RegionSever 節點的數量,提升 Hbase 上層的處理能力;另一個是基於儲存能力的擴充套件(HDFS),通過增加 DataNode 節點數量對儲存層的進行擴容,提升 HBase 的資料儲存能力。(拓展: 圖文詳解 HDFS 的工作機制及其原理)
HBase 作為一個開源的分散式 Key-Value 資料庫,其主要作用是面向 PB 級別資料的實時入庫和快速隨機存取。這主要源於上述易擴充套件的特點,使得 HBase 通過擴充套件來儲存海量的資料。
Hbase 是根據列族來儲存資料的。列族下面可以有非常多的列。列式儲存的最大好處就是,其資料在表中是按照某列儲存的,這樣在查詢只需要少數幾個欄位時,能大大減少讀取的資料量。
WAL 機制保證了資料寫入時不會因叢集異常而導致寫入資料丟失,Replication 機制保證了在叢集出現嚴重的問題時,資料不會發生丟失或損壞。而且 Hbase 底層使用 HDFS,HDFS 本身也有備份。
在 HBase 的列族中,可以指定任意多的列,為空的列不佔用儲存空間,表可以設計得非常稀疏。
HBase 可以將資料儲存在本地檔案系統,也可以儲存在 HDFS 檔案系統。在生產環境中,HBase 一般執行在 HDFS 上,以 HDFS 作為基礎的儲存設施。HBase 通過 HBase Client 提供的 Java API 來存取 HBase 資料庫,以完成資料的寫入和讀取。HBase 叢集主由HMaster、Region Server 和 ZooKeeper 組成。
HBase 是一個面向列式儲存的分散式資料庫。HBase 的資料模型與 BigTable 十分相似。在 HBase 表中,一條資料擁有一個全域性唯一的鍵(RowKey)和任意數量的列(Column),一列或多列組成一個列族(Column Family),同一個列族中列的資料在物理上都儲存在同一個 HFile 中,這樣基於列儲存的資料結構有利於資料快取和查詢。 HBase 中的表是疏鬆地儲存的,因此使用者可以動態地為資料定義各種不同的列。HBase中的資料按主鍵排序,同時,HBase 會將表按主鍵劃分為多個 Region 儲存在不同 Region Server 上,以完成資料的分散式儲存和讀取。
HBase 根據列成來儲存資料,一個列族對應物理儲存上的一個 HFile,列族包含多列列族在建立表的時候被指定。
Column Family 即列族,HBase 基於列劃分資料的物理儲存,一個列族可以包含包意多列。
一般同一類的列會放在一個列族中,每個列族都有一組儲存屬性:
HBase 在建立表的時候就必須指定列族。HBase的列族不是越多越好,官方薦一個表的列族數量最好小於或者等於3,過多的列族不利於 HBase 資料的管理和索引。
RowKey的概念與關係型資料庫中的主鍵相似,HBase 使用 RowKey 來唯一標識某行的資料。
存取 HBase 資料的方式有三種:
HBase 將表中的資料基於 RowKey 的不同範圍劃分到不同 Region 上,每個Region都負責一定範圍的資料儲存和存取。
每個表一開始只有一個 Region,隨著資料不斷插入表,Region 不斷增大,當增大到一個閥值的時候,Region 就會等分成兩個新的 Region。當table中的行不斷增多,就會有越來越多的 Region。
另外,Region 是 Hbase 中分散式儲存和負載均衡的最小單元,不同的 Region 可以分佈在不同的 HRegion Server上。但一個Hregion是不會拆分到多個server上的。 拓展:談一下你對 HBase 的認識?
這樣即使有一個包括上百億條資料的表,由於資料被劃分到不同的 Region上,每個 Region 都可以獨立地進行寫入和查詢,HBase 寫查詢時候可以於多 Region 分散式並行操作,因此存取速度也不會有太大的降低。
TimeStamp 是實現 HBase 多版本的關鍵。在HBase 中,使用不同 TimeStamp 來標識相同RowKey對應的不同版本的資料。相同 RowKey的資料按照 TimeStamp 倒序排列。預設查詢的是最新的版本,當然使用者也可以指定 TimeStamp 的值來讀取指定版本的資料。
不知是否有小夥伴們疑問,為什麼列式儲存會廣泛地應用在 OLAP 領域,和行式儲存相比,它的優勢在哪裡?今天我們一起來對比下這兩種儲存方式的差別。
其實,列式儲存並不是一項新技術,最早可以追溯到 1983 年的論文 Cantor。然而,受限於早期的硬體條件和應用場景,傳統的事務型資料庫(OLTP)如 Oracle、MySQL 等關係型資料庫都是以行的方式來儲存資料的。
直到近幾年分析型資料庫(OLAP)的興起,列式儲存這一概念又變得流行,如 HBase、Cassandra 等巨量資料相關的資料庫都是以列的方式來儲存資料的。
對於 OLAP 場景,大多都是對一整行記錄進行增刪改查操作的,那麼行式儲存採用以行的行式在磁碟上儲存資料就是一個不錯的選擇。
當查詢基於需求欄位查詢和返回結果時,由於這些欄位都埋藏在各行資料中,就必須讀取每一條完整的行記錄,大量磁碟轉動定址的操作使得讀取效率大大降低。
舉個例子,下圖為員工資訊emp表。
資料在磁碟上是以行的形式儲存在磁碟上,同一行的資料緊挨著存放在一起。
對於 emp 表,要查詢部門 dept 為 A 的所有員工的名字。
select name from emp where dept = A
由於 dept 的值是離散地儲存在磁碟中,在查詢過程中,需要磁碟轉動多次,才能完成資料的定位和返回結果。
對於 OLAP 場景,一個典型的查詢需要遍歷整個表,進行分組、排序、聚合等操作,這樣一來行式儲存中把一整行記錄存放在一起的優勢就不復存在了。而且,分析型 SQL 常常不會用到所有的列,而僅僅對其中某些需要的的列做運算,那一行中無關的列也不得不參與掃描。
然而在列式儲存中,由於同一列的資料被緊挨著存放在了一起,如下圖所示。
那麼基於需求欄位查詢和返回結果時,就不許對每一行資料進行掃描,按照列找到需要的資料,磁碟的轉動次數少,效能也會提高。
還是上面例子中的查詢,由於在列式儲存中 dept 的值是按照順序儲存在磁碟上的,因此磁碟只需要順序查詢和返回結果即可。
列式儲存不僅具有按需查詢來提高效率的優勢,由於同一列的資料屬於同一種型別,如數值型別,字串型別等,相似度很高,還可以選擇使用合適的編碼壓縮可減少資料的儲存空間,進而減少IO提高讀取效能。
總的來說,行式儲存和列式儲存沒有說誰比誰更優越,只能說誰更適合哪種應用場景。
HBase 作為 NoSQL 資料庫的代表,屬於三駕馬車之一 BigTable 的對應實現,HBase 的出現很好地彌補了巨量資料快速查詢能力的空缺。在前面咱們也有介紹過 HBase 的資料模型,感興趣的小夥伴可以翻看下。
HBase 的核心架構由五部分組成,分別是 HBase Client、HMaster、Region Server、ZooKeeper 以及 HDFS。它的架構組成如下圖所示。
下面我們對 HBase 架構組成的每一部分詳細介紹一下。
HBase Client 為使用者提供了存取 HBase 的介面,可以通過後設資料表來定位到目標資料的 RegionServer,另外 HBase Client 還維護了對應的 cache 來加速 Hbase 的存取,比如快取後設資料的資訊。
HMaster 是 HBase 叢集的主節點,負責整個叢集的管理工作,主要工作職責如下:
Region Server 直接對接使用者的讀寫請求,是真正的幹活的節點,主要工作職責如下。
與 HMaster 的協同:當某個 RegionServer 宕機之後,ZK 會通知 Master 進行失效備援。下線的 RegionServer 所負責的 Region 暫時停止對外提供服務,Master 會將該 RegionServer 所負責的 Region 轉移到其他 RegionServer 上,並且會對所下線的 RegionServer 上存在 MemStore 中還未持久化到磁碟中的資料由 WAL 重播進行恢復。
下面給大家詳細介紹下 Region Serve資料儲存的基本結構,如下圖所示。一個 Region Server 是包含多個 Region 的,這裡僅展示一個。
Region:每一個 Region 都有起始 RowKey 和結束 RowKey,代表了儲存的Row的範圍,儲存著表中某段連續的資料。一開始每個表都只有一個 Region,隨著資料量不斷增加,當 Region 大小達到一個閥值時,Region 就會被 Regio Server 水平切分成兩個新的 Region。當 Region 很多時,HMaster 會將 Region 儲存到其他 Region Server 上。
Store:一個 Region 由多個 Store 組成,每個 Store 都對應一個 Column Family, Store 包含 MemStore 和 StoreFile。
當一個Region 中所有 StoreFile 的大小和數量都增長到超過一個閾值時,HMaster 會把當前Region分割為兩個,並分配到其他 Region Server 上,實現負載均衡。
HFile:HFile 和 StoreFile 是同一個檔案,只不過站在 HDFS 的角度稱這個檔案為HFile,站在HBase的角度就稱這個檔案為StoreFile。
HLog:負責記錄著資料的操作紀錄檔,當HBase出現故障時可以進行紀錄檔重放、故障恢復。例如,磁碟掉電導致 MemStore中的資料沒有持久化儲存到 StoreFile,這時就可以通過HLog紀錄檔重放來恢復資料。
HBase 通過 ZooKeeper 來完成選舉 HMaster、監控 Region Server、維護後設資料叢集設定等工作,主要工作職責如下:
HDFS 為 HBase 提供底層資料儲存服務,同時為 HBase提供高可用的支援, HBase 將 HLog 儲存在 HDFS 上,當伺服器發生異常宕機時,可以重放 HLog 來恢復資料。
瞭解下 HBase 是如何寫入資料的,然後再講解一下一個比較經典的面試題。
HBase 會根據 MemStore 設定的刷盤策略定時將資料重新整理到 StoreFile 中,完成資料持久化儲存。
WAL (Write-Ahead-Log) 預寫紀錄檔是 HBase 的 RegionServer 在處理資料插入和刪除過程中用來記錄操作內容的一種紀錄檔。每次Put、Delete等一條記錄時,首先將其資料寫入到 RegionServer 對應的 HLog 檔案中去。
而WAL是儲存在HDFS上的持久化檔案,資料到達 Region 時先寫入 WAL,然後被載入到 MemStore 中。這樣就算Region宕機了,操作沒來得及執行持久化,也可以再重啟的時候從 WAL 載入操作並執行。
那麼,我們從寫入流程中可以看出,資料進入 HFile 之前就已經被持久化到 WAL了,而 WAL 就是在 HDFS 上的,MemStore 是在記憶體中的,增加 MemStore 並不能提高寫入效能,為什麼還要從 WAL 載入到 MemStore中,再刷寫成 HFile 呢?
所以 MemStore 的意義在於維持資料按照RowKey的字典序排列,而不是做一個快取提高寫入效率。
HBase Client 請求 ZooKeeper 獲取後設資料表所在的 Region Server的地址。
HBase Client 請求 RegionServer 獲取需要存取的後設資料,查詢出目標資料位於哪個 Region Server 中的哪個 Region 中。並將該 table 的 region 資訊以 及 meta 表的位置資訊快取在使用者端的 meta cache,方便下次存取。
HBase Client 請求資料所在的 Region Server,獲取所需要的資料。 Region 首先在 MemStore 中查詢,若命中則返回;如果在MemStore 中找不到,則通過 BloomFilter 判斷資料是否存在;如果存在,則在:StoreFile 中掃描並將結果返回使用者端。
HBase 的資料刪除操作並不會立即將資料從磁碟上刪除,因為 HBase 的資料通常被儲存在 HDFS 中,而 HDFS 只允許新增或者追加資料檔案,所以刪除操作主要對要被刪除的資料進行標記。
當執行刪除操作時,HBase 新插入一條相同的 Key-Value 資料,但是 keyType=Delete,這便意味著資料被刪除了,直到發生 Major_compaction 操作,資料才會真正地被從磁碟上刪除。
HBase這種基於標記刪除的方式是按順序寫磁碟的的,因此很容易實現海量資料的快速刪除,有效避免了在海量資料中查詢資料、執行刪除及重建索引等複雜的流程。