WebHDFSとHttpFsについての簡単なベンチマーク
前のエントリの続き。実用上どうなのってことで、とりあえず簡単にベンチマーク的な負荷走行をしてみた。
実行環境は以下の通り。なお HttpFs Server はNameNode上に立ててある。
- CDH4b2 + HttpFs/WebHDFS
- NameNode x1
- 2CPU 8GB Memory
- DataNode x4
- 2CPU 8GB Memory 2TB HDD
- ベンチマークスクリプト実行ノードもNameNodeと同スペック
またベンチマークに使用したコードはこちらのRubyスクリプトで、ruby 1.9.3 で動かした。簡単に処理内容をまとめると以下のような感じ。
- 特定の1ファイルに対してappendを繰り返す
- appendのサイズは1回あたり10MB
- 時間あたりでappendに成功した回数を記録
- 上記処理を行うプロセスを1〜3並列で1時間走行
- HttpFs、WebHDFS についてそれぞれ実行
- HttpFs は net/http を使って直接appendを実行 (httpfs)
- WebHDFS はwebhdfs rubygemを使いappendを実行 (webhdfs)
- WebHDFSについて、直接 net/http を使い、かつNameNodeの返す Location をキャッシュしてDataNodeにのみリクエストを投げ続ける処理も実行 (cachedwebhdfs)
- このケースではHTTP接続も可能な限り持続させる
結果
ベンチマークは以下の順で実行した(それぞれグラフの山に対応する)。
- httpfs 1セッション
- httpfs 2並列
- httpfs 3並列
- webhdfs 1セッション
- webhdfs 2並列
- webhdfs 3並列
- cached webhdfs 1セッション
- cached webhdfs 2並列
- cached webhdfs 3並列
- cached webhdfs 4並列 (最後にひとつ離れた山)
結果はグラフをごらんいただくのがよいでしょう。まずベンチマークスクリプトを実行した側。
CPU使用率を見るとこっち側がボトルネックにはまずなってないというのはわかると思う。
トラフィックは大変わかりやすい結果。まず httpfs がたいへん良い結果で、webhdfsはやはり単純なスループットでは劣る。webhdfsについてはファイル毎にDataNode URLをキャッシュすれば1.5倍弱程度の性能が出るようだ。NameNodeにいちいち問合せに行くオーバーヘッドがなくなるので、まあ当然といえば当然。
TCP Establishedを見るとwebhdfsの場合に突出している、のはNameNodeへの接続とDataNodeへの接続がひっきりなしに接続/切断を繰り返すからですね。まあこれもわかりやすい。他のケースではHTTP接続は(切れない限り)持続するようになっている。これもパフォーマンスに影響するだろう。
つぎ、NameNode。
CPU使用率はHttpFsの場合にのみ user が上がっているのは普通に納得できると思う。iowaitはファイルへの追記にともなうメタデータ更新分ですね。これはほぼ単純にトラフィック(ファイルの更新回数)に比例してると思うので、特筆すべきことは無し。ロードアベレージもそれに準ずる状況で、特に不思議なことはない。
トラフィックも HttpFs の場合は全データを中継するので上がっており、webhdfsの場合ではNameNodeはいっさい実データをやりとりしないので全く上がっていない、というわかりやすい結果。TCP Establishedも cached webhdfs では低い、わかりやすい結果ですね。
最後、DataNode。*1
CPU使用率は入ってくるトラフィックに応じて上がっている。iowaitがそれなりにあるのも普通。systemがこんなにあるのはちょっと不思議だけど(あんまり考えてない)。ロードアベレージもまあ、どのケースでも大したことはない。
トラフィックを見るとどのノードも平均的に上がっている、のはレプリケーションがあるから、のはず。今回は4ノードしかなくて3レプリカ設定なので、2並列以上の書き込みだと全ノードにI/Oが発生する。
TCP Established は各試行の違いが顕著で、特に cached webhdfs だと、書き込み対象ファイルの権威ノードかどうかでクライアントからの接続/切断の回数が全く異なる。このあたりはDataNodeが直接接続を受けるwebhdfsの特性が出ている、と同時に、DataNode URLをキャッシュすることの弊害が直接見えている。
まとめ
webhdfsは全ノードとの通信*2をHTTPで行うものだ。で、当然Java実装のネイティブプロトコルより効率が悪い、ので HttpFs よりも性能が落ちる。ある意味当然の結果になった。
なっちゃった。さて、どうしよっかなー。
なお、今回はたった4ノード(かつ2CPUずつ!)というかなり小規模な環境でのベンチマークだったので、これは実はwebhdfsには不利な状況だった。DataNodeが直接通信を受けるwebhdfsにおいてはDataNodeのノード数が増えれば当然それに応じて全体のパフォーマンスがスケールする。
また cached webhdfs 4並列の結果が3並列とほとんど変わらないことを見ても、合計8CPUは3並列の書き込み+レプリカ作成でほとんどリソースを食われており、余剰がなかったことがわかる。特にCPUリソースがあまり潤沢でない状況でwebhdfsがスケールしないのはある意味当然なので、CPUコア数の多いハードウェアを使えばまた多少違う結果が出るだろう。
とはいえ、HttpFs使っとけば、というのが比較的わかりやすい一般解になるかもしれない。webhdfsは簡単に使えるし安心感もなくはないが、パフォーマンス的につらい状況が生まれやすい未来は想像しやすい。
追記(2012/06/06)
このライブラリをWebHDFS/HttpFs両方に使えるようにしたので、それを使ってもういちど簡単なベンチマークをとってみた。
負荷サーバからのトラフィックがこのグラフ(の右の4本)。
単独セッションでほぼ倍の性能差がある。HttpFsは2セッションで性能的にはほぼ頭を打っている、のは2CPUのNameNode上にHttpFsが上がってるからかな。WebHDFSはセッション数に応じて割とスループットが上がっていっているので、DataNodeがもっと増えれば上限はまだ上がる、と思う。ノード数が20を超えるようなケースだとWebHDFSの方が性能出るんだろうなあ。
あとTCP Establishedをベンチサーバ、NameNode(HttpFsサーバ)、DataNodeのひとつ、の順で。
なんとなくHttpFsの方が見てて落ち着くなー。