6.1 HBase を発明した人とその理由
この講義では、最近非常に人気が高まっている Hbase などの素晴らしいツールについて説明します。たとえば、Facebook はメッセージング システムの基盤として Hbase を使用していますが、これはすでに多くのことを物語っています。
この講義では、Big Table の概念とその自由な実装、作業の特徴、および従来のリレーショナル データベース (MySQL や Oracle など) や Redis、Aerospike、memcached などのキーと値のストレージの両方との違いについて説明します。いつものように、問題の経緯から始めましょう。他の多くの BigData プロジェクトと同様、Hbase は Google によって開発された概念から生まれました。Hbase の背後にある原則については、記事「Bigtable: 構造化データ用の分散ストレージ システム」で説明されています。
以前の講義で説明したように、通常のファイルは、MapReduce パラダイムを使用したバッチ データ処理に非常に適しています。一方、ファイルに保存された情報は更新するのがかなり不便です。ファイルへのランダムアクセスの可能性も奪われます。ランダム アクセスによる迅速かつ便利な作業のために、Aerospike、Redis、Couchbase、Memcached などのキーと値のストレージなどの nosql システムのクラスがあります。ただし、これらのシステムではバッチ処理は通常非常に不便です。Hbase は、バッチ処理の利便性と、更新およびランダム アクセスの利便性を組み合わせようとする試みです。
6.2 データモデル
HBase は、分散型、列指向、マルチバージョンのキー/値データベースです。
- データは、Hbase の RowKey と呼ばれる主キーによってインデックスが付けられたテーブルに編成されます。
- RowKey キーごとに、属性 (または列) の無制限のセットを保存できます。
- 列は、列ファミリーと呼ばれる列のグループに編成されます。原則として、同じ使用法と格納パターンを持つ列は 1 つの列ファミリーに結合されます。
- 属性ごとに、複数の異なるバージョンを保存できます。バージョンが異なればタイムスタンプも異なります。
レコードは、RowKey でソートされた順序で物理的に保存されます。この場合、異なる列ファミリーに対応するデータは個別に保存されるため、必要に応じて、必要な列ファミリーからのみデータを読み取ることができます。
特定の属性が削除される場合、その属性はすぐには物理的に削除されず、特別な廃棄フラグが付けられるだけです。データの物理的な削除は、後でメジャー コンパクション操作が実行されるときに行われます。
同じ列グループに属し、同じキーに対応する属性は、ソートされたリストとして物理的に格納されます。各キーには属性が存在することも存在することもありません。属性が存在しない場合でも、空の値を格納するオーバーヘッドは発生しません。
リストと列グループの名前は固定されており、明確なレイアウトになっています。列グループ レベルでは、存続期間 (TTL) や保存されるバージョンの最大数などのパラメーターが設定されます。特定のバージョンのタイムスタンプと現在時刻の差が TTL より大きい場合、エントリは削除対象としてマークされます。特定の属性のバージョン数が最大バージョン数を超えた場合、そのレコードも削除対象としてマークされます。
Hbase データ モデルは、キーと値の一致として記憶できます。
<table, RowKey, Column Family, Column, timestamp> -> Value
6.3 サポートされる操作
hbase でサポートされている操作のリストは非常に単純です。4 つの主な操作がサポートされています。
- Put : 新しいエントリを hbase に追加します。このエントリのタイムスタンプは手動で設定できます。それ以外の場合は、現在時刻に自動的に設定されます。
- Get : 特定の RowKey のデータを取得します。データを取得する列ファミリーと読み取りたいバージョンの数を指定できます。
- スキャン: レコードを 1 つずつ読み取ります。読み取りを開始するレコード、読み取り先のレコード、読み取り対象のレコード数、読み取りが実行される列ファミリー、および各レコードの最大バージョン数を指定できます。
- 削除: 特定のバージョンを削除対象としてマークします。物理的な削除は行われず、次のメジャー コンパクション (下記を参照) まで延期されます。
6.4 アーキテクチャ
HBase は、数十または数百の物理サーバー上で実行できる分散データベースであり、一部のサーバーに障害が発生した場合でも、中断のない運用が保証されます。したがって、HBase のアーキテクチャは、従来のリレーショナル データベースと比較して非常に複雑です。
HBase はその作業に 2 つの主要なプロセスを使用します。
1. リージョン サーバー- 1 つ以上のリージョンにサービスを提供します。リージョンは、連続する RowKey の特定の範囲に対応するレコードの範囲です。各リージョンには以下が含まれます。
- 永続ストレージは、HBase の主要なデータ ストレージです。データは、特別な HFile 形式で HDFS に物理的に保存されます。HFile 内のデータは RowKey のソート順に格納されます。1 つのペア (領域、列ファミリー) が少なくとも 1 つの HFIle に対応します。
- MemStore - 書き込みバッファ。データはソートされた順序で HFile d に保存されるため、レコードごとに HFile を更新すると非常にコストがかかります。代わりに、書き込み時にデータは特別な MemStore メモリ領域に入り、そこにしばらく蓄積されます。MemStore が何らかの重要な値に達すると、データは新しい HFile に書き込まれます。
- BlockCache - 読み取り用のキャッシュ。頻繁に読み取られるデータの時間を大幅に節約できます。
- 先行書き込みログ (WAL)。データは memstore に書き込まれるため、クラッシュによるデータ損失のリスクがある程度あります。これを防ぐために、操作を実際に実装する前のすべての操作は特別なログ ファイルに記録されます。これにより、障害が発生した後にデータを回復できます。
2. マスター サーバー- HBase クラスター内のメイン サーバー。マスターは、リージョン サーバー間でのリージョンの分散を管理し、リージョンのレジスタを維持し、通常のタスクの起動を管理し、その他の有用な作業を行います。
サービス間のアクションを調整するために、HBase は、構成を管理し、サービスを同期するように設計された特別なサービスである Apache ZooKeeper を使用します。
領域内のデータ量が増加し、特定のサイズに達すると、Hbase は領域を 2 で分割する操作である分割を開始します。領域の一定の分割を避けるために、領域の境界を事前に設定し、その最大値を増やすことができます。サイズ。
1 つの領域のデータは複数の HFile に保存できるため、Hbase はそれらを定期的にマージして作業を高速化します。この操作は、Hbase ではコンパクションと呼ばれます。圧縮には 2 つのタイプがあります。
- 軽度の圧縮。自動的に起動し、バックグラウンドで実行されます。他の Hbase 操作と比べて優先度が低くなります。
- 大規模な圧縮。これは手動で、または特定のトリガー (タイマーなど) の発生時に起動されます。これは優先度が高く、クラスターの速度が大幅に低下する可能性があります。メジャー コンパクションは、クラスターの負荷が小さいときに実行するのが最適です。メジャー コンパクションでは、以前に廃棄マークが付けられたデータも物理的に削除されます。
6.5 HBase を使用する方法
HBase シェル
Hbase を使い始める最も簡単な方法は、hbase シェル ユーティリティを使用することです。これは、hbase クラスター ノードに hbase をインストールした直後に使用できます。Hbase シェルは、すべての基本的な Hbase 操作のサポートが組み込まれた jruby コンソールです。以下は、2 つの列ファミリーを持つ users テーブルを作成し、それにいくつかの操作を加え、最後に hbase シェルでテーブルをドロップする例です。
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 については、公式 Web サイトで詳しく説明されています。ここから抜粋した 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 での作業のいくつかの機能
-
Hbase はすぐに使用できる MapReduce と統合されており、特別な TableInputFormat および TableOutputFormat を使用して入力および出力として使用できます。
-
適切な RowKey を選択することが非常に重要です。RowKey はリージョン全体に均一に分散する必要があります。そうでないと、いわゆる「ホット リージョン」、つまり他のリージョンよりも頻繁に使用されるリージョンが発生するリスクがあり、システム リソースの非効率な使用につながります。
-
データが個別にアップロードされるのではなく、大規模なバッチで即時にアップロードされる場合、Hbase は特別な BulkLoad メカニズムをサポートしており、単一の Put を使用するよりもはるかに高速にデータをアップロードできます。BulkLoad は基本的に 2 段階の操作です。
- 特別な MapReduce ジョブを使用した Put に参加しない HFile の形成
- これらのファイルを Hbase に直接挿入する
-
Hbase は、Ganglia 監視サーバーへのメトリクスの出力をサポートしています。これは、Hbase を管理して hbase の問題の真相を解明するときに非常に役立ちます。
行キー
RowKey はユーザー ID であり、GUUID であり、世界中で一意になるように特別に生成された文字列です。GUUID は均等に分散されるため、サーバー間でデータが適切に分散されます。
列ファミリー
私たちのストレージは 2 つの列ファミリーを使用します。
- データ。この列グループには、ユーザーが特定の URL にアクセスしたという事実など、広告目的には関係のなくなったデータが保存されます。この列ファミリーの TTL は 2 か月に設定されており、バージョン数の制限は 2000 です。
- ロングデータ。この列グループには、性別、生年月日、その他の「永遠の」ユーザー特性など、時間が経っても関連性を失わないデータが保存されます。
スピーカー
ユーザー ファクトの各タイプは別個の列に保存されます。たとえば、Data:_v 列にはユーザーがアクセスした URL が格納され、LongData:gender 列にはユーザーの性別が格納されます。
この事実のタイムスタンプがタイムスタンプとして保存されます。たとえば、Data:_v 列のタイムスタンプは、ユーザーが特定の URL にアクセスした時刻です。
このユーザー データ ストレージ構造は当社の使用パターンに非常によく適合しており、ユーザー データを迅速に更新し、ユーザーに関する必要なすべての情報を迅速に取得し、MapReduce を使用してすべてのユーザーに関するデータを一度に迅速に処理することができます。
6.7 代替案
HBase は管理と使用が非常に複雑なので、HBase を使用する前に代替手段を検討するのが合理的です。
-
リレーショナル データベース。特にデータが 1 台のマシンに収まる場合には、非常に優れた代替手段です。また、プライマリ以外のインデックスのトランザクションが重要な場合には、まずリレーショナル データベースを検討する必要があります。
-
Key-Value ストレージ。Redis や Aerospike などのストレージは、レイテンシが必要であり、バッチ処理がそれほど重要ではない場合に適しています。
-
MapReduce を使用したファイルとその処理。データが追加されるだけで、ほとんど更新/変更されない場合は、HBase を使用せず、単にデータをファイルに保存することをお勧めします。ファイルの操作を簡素化するには、Hive、Pig、Impala などのツールを使用できます。
HBase の使用は次の場合に正当化されます。
- データが大量にあり、1 台のコンピューター/サーバーに収まりきらない
- データは頻繁に更新および削除されます
- データには明示的な「キー」があり、他のすべてをバインドすると便利です
- バッチ処理が必要
- 特定のキーによるデータへのランダム アクセスが必要
GO TO FULL VERSION