6.1 誰發明了 HBase,為什麼

在本講中,我們將討論 Hbase 這樣一個非常棒的工具,它最近非常受歡迎:例如 Facebook 將其用作其消息系統的基礎,這已經說明了很多。

本次講座將討論Big Table的概念及其自由實現、工作特點以及與經典關係數據庫(如MySQL和Oracle)以及鍵值存儲(如Redis、Aerospike和memcached)的區別。像往常一樣,讓我們從問題的歷史開始。與許多其他大數據項目一樣,Hbase 誕生於谷歌開發的概念。Hbase 背後的原理在Bigtable:結構化數據的分佈式存儲系統一文中進行了描述。

正如我們在之前的講座中所討論的,普通文件非常適合使用 MapReduce 範例的批處理數據。另一方面,存儲在文件中的信息更新起來很不方便;文件也被剝奪了隨機訪問的可能性。為了快速方便的隨機訪問工作,有一類nosql系統如key-value存儲,如Aerospike、Redis、Couchbase、Memcached。然而,批處理在這些系統中通常非常不方便。Hbase是一種將批處理的便利性與更新和隨機訪問的便利性結合起來的嘗試。

6.2 數據模型

HBase 是一個分佈式的、面向列的、多版本的鍵值數據庫。

  • 數據被組織成由 Hbase 中稱為 RowKey 的主鍵索引的表。
  • 對於每個 RowKey 鍵,可以存儲一組無限的屬性(或列)。
  • 列被組織成稱為列族的列組。通常,具有相同用途和存儲模式的列被組合成一個列族。
  • 對於每個屬性,可以存儲幾個不同的版本。不同的版本有不同的時間戳。

記錄以 RowKey 排序的順序物理存儲。在這種情況下,不同Column Family對應的數據是分開存儲的,這樣就可以在需要的時候只從需要的Column Family中讀取數據。

當某個屬性被刪除時,並不會立即在物理上被刪除,而只是被標記上一個特殊的墓碑標誌。數據的物理刪除將在稍後執行 Major Compaction 操作時發生。

屬於同一列組且對應於同一鍵的屬性在物理上存儲為排序列表。每個鍵的任何屬性都可以不存在或存在,如果不存在該屬性,這不會導致存儲空值的開銷。

列表和列組名稱固定,佈局清晰。在列組級別,設置生存時間(TTL)和最大存儲版本數等參數。如果特定版本的時間戳與當前時間之間的差異大於 TTL,則該條目被標記為刪除。如果某個屬性的版本數超過最大版本數,則該記錄也被標記為刪除。

Hbase數據模型可以記為key-value匹配:

<table, RowKey, Column Family, Column, timestamp> -> Value

6.3 支持的操作

hbase 中支持的操作列表非常簡單。支持 4 種主要操作:

  • Put:向 hbase 添加一個新條目。該條目的時間戳可以手動設置,否則會自動設置為當前時間。
  • Get:獲取特定 RowKey 的數據。您可以指定我們將從中獲取數據的列族以及我們要讀取的版本數。
  • 掃描:一條條讀取記錄。您可以指定我們開始讀取的記錄、要讀取的記錄、要讀取的記錄數、將從中執行讀取的列族以及每條記錄的最大版本數。
  • Delete : 將特定版本標記為刪除。不會有物理刪除,它會被推遲到下一次 Major Compaction(見下文)。

6.4 架構

HBase是一個分佈式數據庫,可以運行在幾十台甚至上百台物理服務器上,即使其中一部分出現故障也能保證不間斷運行。因此,HBase的架構相對於經典的關係型數據庫來說是相當複雜的。

HBase 使用兩個主要進程來工作:

1. 區域服務器——服務於一個或多個區域。區域是與特定範圍的連續 RowKeys 相對應的一系列記錄。每個區域包含:

  • Persistent Storage是 HBase 中主要的數據存儲。數據以特殊的 HFile 格式物理存儲在 HDFS 上。HFile 中的數據按 RowKey 排序順序存儲。一對(區域、列族)對應至少一個 HFIle。
  • MemStore - 寫入緩衝區。由於數據按排序順序存儲在 HFile d 中,因此每條記錄更新 HFile 的成本非常高。相反,在寫入時,數據會進入一個特殊的 MemStore 內存區域,並在那裡累積一段時間。當 MemStore 被填充到某個臨界值時,數據被寫入一個新的 HFile。
  • BlockCache - 讀取緩存。允許您在頻繁讀取的數據上顯著節省時間。
  • 預寫日誌 (WAL)。由於數據寫入到 memstore 中,因此存在因崩潰導致數據丟失的風險。為了防止這種情況發生,在實際執行操作之前的所有操作都屬於一個特殊的日誌文件。這允許您在發生任何故障後恢復數據。

2. Master Server ——HBase集群中的主服務器。Master 管理區域在 Region Server 之間的分佈,維護區域註冊,管理定期任務的啟動,以及做其他有用的工作。

為了協調服務之間的操作,HBase 使用 Apache ZooKeeper,這是一種旨在管理配置和同步服務的特殊服務。

當region的數據量增加,達到一定大小時,Hbase開始split,將region一分為二的操作。為了避免region的不斷劃分,可以預先設置region的邊界,增加region的最大值尺寸。

由於一個區域的數據可以存儲在多個 HFile 中,Hbase 會定期將它們合併在一起以加快工作速度。這種操作在 Hbase 中稱為壓縮。壓實有兩種類型:

  • 輕微壓實。自動啟動,在後台運行。與其他 Hbase 操作相比具有較低的優先級。
  • 主要壓實。它是手動啟動的,或者是在某些觸發器發生時啟動的(例如,通過計時器)。它具有高優先級,可以顯著降低集群速度。Major Compaction 最好在集群負載較小的時候進行。Major Compaction 還會物理刪除以前標記為墓碑的數據。

6.5 使用 HBase 的方法

HBase 外殼

開始使用 Hbase 的最簡單方法是使用 hbase shell 實用程序。它在任何 hbase 集群節點上安裝 hbase 後立即可用。

Hbase shell 是一個 jruby 控制台,內置支持所有基本的 Hbase 操作。下面是創建一個包含兩個列族的 users 表,對其進行一些操作,並在 hbase shell 中刪除該表的示例:

create 'users', {NAME => 'user_profile', VERSIONS => 5}, {NAME => 'user_posts', VERSIONS => 1231231231} 
put 'users', 'id1', 'user_profile:name', 'alexander' 
put 'users', 'id1', 'user_profile:second_name', 'alexander' 
get 'users', 'id1' 
put 'users', 'id1', 'user_profile:second_name', 'kuznetsov' 
get 'users', 'id1' 
get 'users', 'id1', {COLUMN => 'user_profile:second_name', VERSIONS => 5} 
put 'users', 'id2', 'user_profile:name', 'vasiliy' 
put 'users', 'id2', 'user_profile:second_name', 'ivanov' 
scan 'users', {COLUMN => 'user_profile:second_name', VERSIONS => 5} 
delete 'users', 'id1', 'user_profile:second_name' 
get 'users', 'id1' 
disable 'users' 
drop 'users'

原生API

和其他大部分hadoop相關的項目一樣,hbase是用java實現的,所以原生的api是用Java實現的。本機 API 在官方網站上有很好的記錄。這是使用從那裡獲取的 Hbase API 的示例:

import java.io.IOException;

import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

public class MyLittleHBaseClient {
  public static void main(String[] args) throws IOException {
	Configuration config = HBaseConfiguration.create();
	Connection connection = ConnectionFactory.createConnection(config);
	try {
  	Table table = connection.getTable(TableName.valueOf("myLittleHBaseTable"));
  	try {
    	Put p = new Put(Bytes.toBytes("myLittleRow"));
    	p.add(Bytes.toBytes("myLittleFamily"), Bytes.toBytes("someQualifier"),
    	Bytes.toBytes("Some Value"));
    	table.put(p);

    	Get g = new Get(Bytes.toBytes("myLittleRow"));
    	Result r = table.get(g);
    	byte [] value = r.getValue(Bytes.toBytes("myLittleFamily"),
      	Bytes.toBytes("someQualifier"));

    	String valueStr = Bytes.toString(value);
    	System.out.println("GET: " + valueStr);

    	Scan s = new Scan();
    	s.addColumn(Bytes.toBytes("myLittleFamily"), Bytes.toBytes("someQualifier"));
    	ResultScanner scanner = table.getScanner(s);
    	try {
       	for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {
         	System.out.println("Found row: " + rr);
       	}
     	} finally {
       	scanner.close();
     	}
   	} finally {
     	if (table != null) table.close();
   	}
 	} finally {
   	connection.close();
 	}
  }
}

Thrift、REST 和對其他編程語言的支持

為了使用其他編程語言,Hbase 提供了 Thrift API 和 Rest API。基於它們,為所有主要編程語言構建了客戶端:python、PHP、Java Script 等。

6.6 使用 HBase 的一些特性

  1. Hbase 與 MapReduce 集成開箱即用,可以使用特殊的 TableInputFormat 和 TableOutputFormat 作為輸入和輸出。

  2. 選擇正確的 RowKey 非常重要。RowKey 必須提供良好的跨區域均勻分佈,否則存在所謂的“熱點區域”的風險 - 比其他區域使用頻率高得多的區域,這會導致系統資源使用效率低下。

  3. 如果數據不是單個上傳,而是立即大批量上傳,Hbase 支持一種特殊的 BulkLoad 機制,可以讓你上傳數據的速度比使用單個 Puts 快得多。BulkLoad 本質上是一個兩步操作:

    • 使用特殊的 MapReduce 作業在沒有 puts 參與的情況下形成 HFile
    • 將這些文件直接插入到 Hbase 中
  4. Hbase 支持將其指標輸出到 Ganglia 監控服務器。這在管理 Hbase 以深入了解 HBase 問題時非常有幫助。

行鍵

RowKey是用戶ID,是一個GUUID,一個專門生成的字符串,全球唯一。GUUID 分佈均勻,可以在服務器之間很好地分佈數據。

列族

我們的存儲使用兩個列族:

  • 數據。這組列存儲不再與廣告目的相關的數據,例如用戶訪問過某些 URL 的事實。此 Column Family 的 TTL 設置為 2 個月,版本數限制為 2000。
  • 長數據。這組列存儲的數據不會隨著時間的推移而失去相關性,例如性別、出生日期和其他“永恆”的用戶特徵。

喇叭

每種類型的用戶事實都存儲在單獨的列中。例如,Data:_v 列存儲用戶訪問過的 URL,LongData:gender 列存儲用戶的性別。

這個事實的時間戳被存儲為時間戳。例如,在 Data:_v 列中,時間戳是用戶訪問特定 URL 的時間。

這種用戶數據存儲結構非常符合我們的使用模式,可以讓你快速更新用戶數據,快速獲取用戶的所有必要信息,並使用MapReduce一次性快速處理所有用戶的數據。

6.7 備選方案

HBase 的管理和使用非常複雜,因此在使用 HBase 之前,查看替代方案是有意義的:

  • 關係數據庫。一個很好的選擇,尤其是在數據適合一台機器的情況下。另外,首先,在主索引以外的索引事務很重要的情況下,您應該考慮關係數據庫。

  • 鍵值存儲。Redis 和 Aerospike 等存儲更適合需要延遲且批處理不太重要的情況。

  • 文件及其使用 MapReduce 的處理。如果數據只是增加,很少更新/改變,那麼最好不要使用HBase,而只是將數據存儲在文件中。為了簡化文件工作,您可以使用 Hive、Pig 和 Impala 等工具。

在以下情況下使用 HBase 是合理的:

  • 有很多數據,它們不適合放在一台計算機/服務器上
  • 數據經常更新和刪除
  • 數據中有一個明確的“鍵”,可以方便地綁定其他所有內容
  • 需要批量處理
  • 需要通過特定密鑰隨機訪問數據