2009/11/29

Hadoop and HBase vs RDBMS メモ

Hadoop and HBase vs RDBMSの超適当翻訳メモ





Hadoop/HBase vs. RDBMS

December CTO Forum

Jonathan Gray
Streamy.com


-1-



プロフィール

・Streamy.comの共同創業者
・経歴(経験):コンピュータエンジニアリング、分散/耐障害性アプリケーション、リレーショナルデータベース、Linux
・2008年6月にStreamy.comのバックエンドをPostgreSQL からHadoop/Hbaseに移行に成功

-2-



なぜHadoop/Hbaseなのか

・データがペタバイトまで大きくなった
・従来のデータベースは拡張するのにお金がかかるし、本質的に分散化が難しい
・一般的なハードウェアは安くてパワフル
- 1000ドル(?)で4core/4GB/1TB
- 300GB 15k RPM SAS が500ドルぐらい
・ランダムアクセスとバッチ処理が必要
- Hadoop はbatch/streamingのみサポート

-3-



Hadoop/Hbaseの歴史

・ Googleは拡張性の問題を解決した
- “The Google File System” 2003年10月発表
 - Hadoop DFS
- “MapReduce:大規模クラスター構成での簡略化されたデータ処理” 2004年12月発表
- Hadoop Map Reduce
- “Bigtable:構造化されたデータのための分散ストレージファイルシステム” 2006年11月発表
- HBase

-4-



Hadoop の紹介

・2つのメインコンポーネント
- Hadoop DFS
  - 一般的なハードウェア上で動作する、スケーラブルで障害耐性の高い、高性能分散ファイルシステム
- Hadoop Map Reduce
- 分散コンピューティングのためのソフトウェアフレームワーク
・採用実績
 - 多くの組織で製品として使われている
 - Yahooはプライマリースポンサーとして何万ものHadoopのアクティブノードを動かしている

-5-



HDFS: Hadoop Distributed File System

・数千のノードにペタバイトのデータを複製
- データは64MBのブロックごとに分割され、それぞれのブロックが3回複製される
・マスター/スレーブアーキテクチャ
- マスター NameNode はブロックの位置情報を含む
- スレーブ DataNode はローカルのファイルシステムのブロックを管理する
・一般的なハードウェアで組み立て
- 15k RPM diskもRAIDも不要

-6-



HDFS の例

・1テラバイトのテキストファイルを10ノードのクラスター上に展開
- Java APIか、コマンドラインが使える
./hadoop dfs ?copyFromLocal ./srcFile /destFile
- ファイルは64MBのブロックに分割(合計16,384ブロック)
- それぞれのブロックは3つのノードに送られる(合計49,152ブロック、3テラバイト)
- 異なったクラスター/地理的な位置にレプリケーションが保障される

-7-



MapReduce

・ペタバイトのデータを確実にローカルファイルのように扱うための分散プログラミングモデル
- JavaとCが最初から使える
- HadoopStreamingを使ってどんな言語も使える
・ 関数型プログラミングのmap/reduce関数に触発された
 入力 -> Map() -> コピー/ソート -> Reduce() -> 出力

-8-



MapReduce の例

・ WordCount の例をHDFS上の1テラバイトのファイルで動かす
- 各ブロックファイルでMapタスク起動
- それぞれのタスクの中で、Map関数がそれぞれの行で呼ばれる:Map(LineNubmer,LineString)
- LineStringの中のれぞれの文字→Output(Word,1)
- Mapの出力はソートされ、グループ化され、reducerにコピーされる
- Reduce(Word,List)がそれぞれの文字で呼ばれる
- Output(Word,Length(List))
- 最終的に、それぞれの文字の合計数が出力される

-9-



Hadoop…

  - Hadoopは、大規模なデータを”バッチ”で保存したり、ストリーミングするように設計されている
- Hadoopは、リアルタイムでクエリーを流すのには向いていない
- Hadoopは、ランダムアクセスをサポートしない
これがHbaseがある理由。

-10-



Hbaseとは?

・分散、
・列指向、
・多次元、
・高可用性、
・高性能
・ストレージシステム
プロジェクトゴール:
数十億の列行×数百万の列×数百のバージョン
の数ペタバイトデータが数千の一般的なサーバに載る

-11-



HBase でできないor不得意なこと

・SQL データベース
- joinがない、クエリーエンジンがない、型がない、SQLがない
- トランザクション、副次索引はできるけど、未熟
・RDBMSの当座の代用品
・RDBMに対しての非スキーマ構造
- 非正規化データ
- 分散してコマ切れのテーブル

社内のDBAなら“NO”って言うでしょう

-12-



HBase のアーキテクチャ

・テーブルはいくつもの領域(regions)からできている
・領域は”startKey”と”endKey”によって特定される
- 空のテーブル:
(Table,NULL,NULL)
- 2つの 領域のテーブル:
(Table,NULL,”Streamy”)と(Table,”Streamy”,NULL)
・それぞれの領域はHDFS上の各ファイルやブロックとして違ったノードにあるかもしれない。
それぞれの領域はHadoopによって複製される

-13-



HBase アーキテクチャ(つづき)
・2つのタイプのHbaseのノード
・特別テーブル ? ROOT ? と META。スキーマ情報と領域の位置を保存
・マスターサーバーは領域サーバーの監視に責任を持ち、領域のロードバランシングにも責任を持つ

-14-



HBase のテーブル

・テーブルは行によってソートされる
・テーブルスキーマは”column families”によってのみ定義される
- それぞれのファミリーはいくつもの列から成る
- それぞれの列はいくつものバージョンから成る
- 列はinsertされた時のみ存在し、NULLの入力は自由(できる?)
- ファミリーの中の列はソートされ、また、お互いにソートされる
- テーブル名を除くすべてはbyte[]
(Table,Row,Family:Column,Timestamp)→値

-15-



HBase テーブルのデータ構造

SortedMap(
RowKey, List(
SortedMap(
Column, List(
Value, Timestamp
)
)
)
)
SortedMap(RowKey, List(SortedMap(Column, List(Value, Timestamp))))

-16-



Web クロールの例

・webクロールデータの保存
- “crawl”テーブルと “content” ファミリー
- 列の中にURLの行
- content:data 加工していないクロールしたデータを保存
- content:language HTTPのLanguage ヘッダーを保存
- content:type HTTPのContent-Typeヘッダーを保存
- もしハイパーリンクや画像などのために未加工データを処理するのであれば、”links”ファミリーと”images”ファミリーを加える
  - links: それぞれのハイパーリンクのための列
- images: それぞれの画像のための列

-17-




RDBMSでのWebクロールの例

・一般的なDBだとどうなるのか?
- “crawl”テーブルの中に”url”,”data”,”language”,”type”列
- “links”テーブルの中に”url”と”link”列
- “images”テーブルの中に”url”と”image”列
・どのぐらいの規模?
- 1000万ドキュメント w/avg 10リンクと10イメージ
- 合計2億1000万行に対して合計1000万
- links/imagesテーブルでインデクスが膨れ上がる

-18-



HBaseへの接続

・ネイティブ Java クライアント/API
- get(byte[] row, byte[] column, long ts, int versions)
・非ネイティブ Java クライアン
- Thrift server (※)(Ruby, C++, etc)
- REST server
- Native C/C++ client scheduled for 0.20 release
・MapReduce用TableInput/TableOutputFormat
- HBase が MapReduce の元データ
・Hbase Shell
- データ取得、追加、スキャン、管理用Jruby シェル

(※「Threift server」:Thrift is a software framework for scalable cross-language services


-19-



HBase 拡張

・Hive, Pig, Cascading
- 次期Hbase統合のHadoop用のMapReduceツール
・Pigi
- Hbase ORM はindex、join、検索、ページング、順序付けを含む
・subRecord
- ストレージと統合されたインフラを提供。セキュリティ、ロギング、評価指標、Hbaseのモニタリング
・ Hbase-Writer
- Heritrix はHbaseテーブルを直接クロールする

-20-



HBaseの歴史

・2006年11月
- GoogleがBigTableの論文を発表
・2007年2月
- 最初のHbaseのプロトタイプがHadoop contribとして作成される
・2007年10月
- 最初の利用可能なHbase
・2008年1月
- Hadoop がトップレベルプロジェクトになり、Hbaseがサブプロジェクトになる
・2008年10月
- Hbase 0.18.1 リリース

-21-



現在のプロジェクトステータス

・最新リリース:HBase 0.18.1 on Hadoop 0.18.2
- 8番目のHBaseリリース
- スケーラブルで安定なバージョンリリース
・もうすぐリリース:HBase 0.19.0 on Hadoop 0.19.0
- マスター障害時に小さなデータの消失もない機能をHDFSに加える(最大100この編集ミスに対して3万の履歴)
- メモリ利用の効率化とリソースモニタリングについての大規模な改修
・その次のリリース: HBase 0.20.0 on Hadoop 0.20.0 (March 2009)
- 新しいHDFSファイルフォーマット「TFile」
- SPOF(Single Point of Failer)をなくす:ZooKeeper がマルチマスターを実現
-大量のランダムアクセスに対する改善
- インメモリー、キャッシュ容量の拡張

-22-



HBase の使われているところ

・Streamy
・Powerset
- Birthplace of HBase
- Home of Michael Stack, project lead
・Mahalo
・The Shopping Engine @ Tokenizer.org
・Advanced Threats Research @ Trend Micro
・Wikia
・Multilingual Archive @ WorldLing
・Also being used in some capacity at:
- Yahoo, Last.fm, Videosurf, and Rapleaf

-23-



Hadoop/HBase > PostgreSQL,MySQL,SQLServer2008,Oracle

質問ある?

-24-



比較1

・ショッピングカートを保存するシステム
- 顧客、製品、注文

-25-



シンプルなSQLスキーマ

CREATE TABLE customers (
customerid UUID PRIMARY KEY,
name TEXT, email TEXT)

CREATE TABLE products (
productid UUID PRIMARY KEY,
name TEXT, price DOUBLE)

CREATE TABLE orders (
orderid UUID PRIMARY KEY,
customerid UUID INDEXED REFERENCES(customers.customerid),
date TIMESTAMP, total DOUBLE)

CREATE TABLE orderproducts (
orderid UUID INDEXED REFERENCES(orders.orderid),
productid UUID REFERENCES(products.productid))


-26-



シンプルなHbaseのスキーマ

CREATE TABLE customers (content, orders)
CREATE TABLE products (content)
CREATE TABLE orders (content, products)

-27-



SQL、HBaseへのクエリ

・顧客用:name,emal,orders取得
・製品用:name,price取得
・注文用:customer,stamp,total取得
・注文用:productのリスト取得

-28-



SQLが得意なこと
・join
- 1つのクエリですべての注文した製品と製品情報を取得
・ 副次索引
- e-mailからのcustomerid取得
・参照整合性
- 注文を策することで’orderproducts’も削除される
- IDをupdateする際の伝搬
・リアルタイム解析
- GROUP BYやORDER BY は簡易統計解析ができる

-29-



Hbaseが得意なこと

・データスケール
- 100万顧客と100万製品
- 製品情報は大きなテキストデータシートかPDFファイルを含む
- 顧客が製品ページを見た毎回のトラッキング
・Read/Writeスケール
- テーブルはreads/writesノードに完全に分散される
- 書き込みは高速におこなわれ、インデックスのアップデート不要
・レプリケーション
- 自動的に行われる
・バッチ解析
- 大量の複雑なクエリーが連続して効果的にMapReduceの分散ジョブになり、並列して実行される

-30-



結論

・小さなインスタンスのシンプルなシステムであれば、リレーショナルデータベースは構造やデータアクセスのための方法を提供する
- トランザクションやクエリーエンジンンのほとんどの働きはアウトソースできる
- Hbaseはアプリケーションレイヤーに複雑さをもたらす
・ 拡張の必要があれば、HBaseの特性と柔軟性は、RDBMSでのスケーリングでの悩みを取り除いてくれるでしょう

-31-



比較2

・比較の鍵となる要因
- ハードウェア要件
- 拡張性
- 信頼性
- 使いやすさ
- 費用

-32-



ハードウェア要件
・RDBMSは入出力バウンド
  - 通常は高速で高価なディスクの大きな配列を必要とする -小さな本番環境は単一ノードで15-30の15k RPMドライブで、16コア、
16?64ギガバイトのRAMが必要かもしれない - 同様の仕様では、バックアップサーバが必要
・Hbaseは一般的なハードウェア用に設計されている
- 最大のパフォーマンス要因はノードの数
- 小さな本番環境では、10-20ノードでそれぞれで2500GB 7.2kRPMのでドライブで、4コアで4GB
- RAIDの1つのマースターノード、デュアルPSU(電源ユニット)、その他、最近ではSPOF

-33-



拡張性

・RDBMSのスケールは以下のもので実現される
- Memcachedによるキャッシング
- パーティショニングは多くの場合アプリケーションか外部ツールに委ねられる
- レプリケーション機能は組み込まれているか、または、有名なRDBMSではアドオンとして提供される
- スケールのメカニズムであるにもかかわらず、アーキテクチャ上効果的なマルチマスターサポートを許容しない
・Hbase はbox外でスケールする
- ランダムアクセスはMemcachedに似た気候によって高速化される(0.20からビルトイン)
- 低速から高速まで同時並行して一定のパフォーマンスを保つ
- 書き込みは分散んされ、インデックスは存在しない
- RegionServerの追加によってスケールがプラグインされる

-34-



信頼性

・RDBMS
- スレーブレプリケーション
- ワーム/ホットバックアップ
- 単一ノードの故障はたびたび致命的となる
・Hbase
- レプリケーションは組み込まれている
- バックアップはできるけど不要。

-35-



使いやすさ

・RDBMS
- 洗練された数100万のSQLとリレーショナルデータモデリング
- 正規化されたスキーマはわかりやすく、予測通りのパフォーマンスを発揮する
- しかし、スキーマはたびたび制限され、変更しにくく、拡張しにくい
・HBaseとMapReduce
- 重要な学修曲線
- 初期の苦労を緩和するため、優れたコミュニティといくつもの使い勝手を良くするツールが増えてきている
- スキーマは緩く定義されているので、データ構造は変更しやすく、パフォーマンスも一定

-36-



その他の要因

・OS/アーキテクチャ
- RDBMSはターゲットのアーキテクチャによって大きく変わる
- HbaseはLinux用に設計されて、SolarisやWindowsで成功している例もある
・費用
- HbaseはFOSS(Free and Open Source Softuare)
- たくさんの成熟したFOSSのRDBMSはあるが、企業で多く使われているものは高価
・広範な使用
- RDBMSは実証済みである
- HadoopとHbaseはまだ開発中で、まだ本番での広い利用には至っていない

-37-



結論

・2番目と1番目は同じ(?)
・RDBMSは強力な機能を提供しますが、拡張する費用はとても高いです
・Hbaseは必要最小限の機能しかありませんが、少ない費用で拡張できます

-38-

Ubuntu 8.04 LTSでhadoop環境構築

■javaインストール

$ sudo apt-get install sun-java6-*


■javaのバージョン確認

$ java -version
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)


■sun java使う設定

$ sudo update-alternatives --config java



■phpインストール(hadoop streamingでphpを動かす場合)

$ sudo apt-get install php5 php5-cli


■ユーザー追加

$ sudo adduser hadoop


■ssh_configが変だったので修正(なぜ?)

$ sudo vi /etc/ssh/ssh_config
PermitRootLoginをコメントアウト


■hadoopユーザ設定(パスなしユーザ設定)

$su - hadoop
$ssh-keygen -t rsa -P ""
$cat .ssh/id_rsa.pub >> .ssh/authorized_keys


■パスなしログイン確認

$ ssh localhost


■hadoopダウンロード、展開

$ wget http://www.meisei-u.ac.jp/mirror/apache/dist/hadoop/core/hadoop-0.20.1/hadoop-0.20.1.tar.gz
$ tar xvzf hadoop-0.20.1.tar.gz
$ ln -s hadoop-0.20.1 hadoop
$ vi hadoop/conf/hadoop-env.sh
export JAVA_HOME=/usr/lib/jvm/java-6-sun
$ cd hadoop


■hadoopテスト(シングルモード)

$ mkdir input
$ cp conf/*.xml input
$ bin/hadoop jar hadoop-*-examples.jar grep input output 'dfs[a-z.]+'
$ cat output/*


■hadoopテスト(疑似分散モード)

$ cd hadoop


☆以下のファイル編集

<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>


conf/hdfs-site.xml:

<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>


conf/mapred-site.xml:

<configuration>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
</property>
</configuration>


■フォーマット

$ bin/hadoop namenode -format


■起動

$ bin/start-all.sh


■動作確認

NameNode :http://localhost:50070/
JobTracker:http://localhost:50030/


■起動確認

$ jps
3815 DataNode
3964 JobTracker
4059 TaskTracker
3894 SecondaryNameNode
3736 NameNode
12858 Jps


■テストデータ作成
・サンプルデータ

$ cat /home/hadoop/sample/sample.txt
a b c d e f g
a b c d e f
a b c d e
a b c d
a b c
a b
a


・phpでmap処理:標準入力の文字列を空白で分割して、タブ区切りの行として出力

#!/usr/bin/php
while ( !feof(STDIN) ) {
$line = trim(fgets(STDIN));
foreach ( preg_split('/\s+/', $line) as $word ) {
if ( $word !== '' ) {
echo "${word}\t1\n";
}
}
}
?>


・phpでreduce処理:標準入力の文字列を数え上げる

$ cat /home/hadoop/sample/reduce.php
#!/usr/bin/php
$value ) {
echo "${key}\t${value}\n";
}
?>


■テスト
・テストデータ登録

$ cd hadoop
$ bin/hadoop fs -put /home/hadoop/sample/sample.txt input


・実行

$ bin/hadoop jar contrib/streaming/hadoop-0.20.1-streaming.jar \
-input input/sample.txt \
-output output_sample \
-mapper 'php /home/hadoop/sample/map.php' \
-reducer 'php /home/hadoop/sample/reduce.php'


・結果表示:単語ごとに出現回数表示

$ bin/hadoop fs -cat output_sample/*
a 7
b 6
c 5
d 4
e 3
f 2
g 1


■ストップ

$ bin/stop-all.sh