pandazx's blog

Hadoop, データ分析など雑多な技術ブログ

EricssonのHBaseチューニング1

以下の記事の意訳。けど、未検証。
HBase: Performance Tuners | Ericsson Labs

5000 row/secの処理性能だったところをチューニングにより、750,000 row/secを達成した。
本ブログでは集計プログラムについてのみ説明しているが、次回ブログではランダムアクセスにも対応できる説明があるらしい。

チューニング環境

  • 対象レコードは91個の属性を持つ
  • 少なくとも1億行をスキャンできる
  • すべての属性に対して、ランダムアクセスするパターンのクエリを評価する

今回のクエリパターンは属性をカラムファミリーにまとめるのは難しい。そのため、いくつか対策を行った。

一つ目の対策はすべての属性を一つのカラムファミリーの別々のカラムとして格納するよう定義した。二つ目の対策は次回のブログで説明する。

クラスタ構成

  • master x1
  • slave x7
  • サーバはすべてx86で、SETA(SATA?)ディスク装備
  • クラスタに接続するのにプライベートIPは使わない
  • 集計プログラムはmasterのHMasterが稼働するサーバ上で実行する

プログラムはテーブル全体をスキャンして集計するものだが、SQLで説明すると以下のようになる。

SELECT sum(A), WHERE B = C GROUP BY(D).

5,000 row/secから500,000 row/secにするチューニング

まず、パラメータを何も変更しない状態で、普通のHBase APIを使ってテストした。
その結果、5,000 row/secになった。
しかし、あるブログによると、この状態でも、もっと高いパフォーマンス、10,000 row/sec程度の結果になるはずだ。

原因を探るべく、ボトルネックの調査を行った結果、次の教訓を得た。

教訓1:デフォルト設定では、HBaseはランダムアクセスにチューニングされている。

今回の目的はフルテーブルスキャンをすることであるため、異なるシチュエーションで使うためのチューニング方法を調べた。

ブロックキャッシュ

ブロックキャッシュはデータをメモリ上に保持するものだ。キャッシュが空の状態からプログラムを二回実行してテストしたが、実行時間は同じだった。キャッシュは満タンになり、ガベージコレクションが発生した。

ブロックサイズを1MBから64MBに変更した。(ブロックキャッシュの間違い?)

その結果、新しいデータがディスクから読まれるとブロックキャッシュが増えることを確認したが、結局はガベージコレクションがボトルネックになった。

CPU使用率が高い時にガベージコレクションが起きるリソースが足りなくなり、問題になる。リージョンサーバがシャットダウンする場合もある。パフォーマンス的には最悪の状態。

考えた結果、ブロックキャッシュを無効にすることにした。しかし、データをディスクから常に読むことになるので、パフォーマンスを向上させるには、他の対策が必要になる。

パラメータチューニング

setCaching

リージョンサーバからクライアントに何行のrowを同時に送るか。500-10,000を設定する。

setBatch

ネットワーク帯域を上手く制御するためのパラメータ。これだと何のことかわからないが、setCachingは一度に取得する行数で、setBatchは一度に取得する列数らしい。これはHBaseクライアントを作る際のページング処理について - wyukawa’s blog に書いてある。

rpchandler

hbase.regionserver.handler.count のことだと思われる。このパラメータについて以下、2.3. Configuration Files より引用

Count of RPC Listener instances spun up on RegionServers. Same property is used by the Master for count of master handlers. Default is 10.


これら3つのパラメータをチューニングすることで、20,000 row/secを達成した。

パラレルスキャン

HBaseのスキャンがどのように動くのかを調べた結果、次の教訓得た。

教訓2:スキャンは各リージョンサーバでシリアルに実行される

この教訓を得たことから、スキャンではなく、パラレルにリージョンデータを読むようにプログラムを設計した。
(もう少し、ここの実装方法を詳しく書いて欲しかった。HBaseのデータを入力にしてMapReduceしたということだろうか。)

これにより、大幅なパフォーマンス向上を果たしたが、ネットワークボトルネックという新たな問題に直面した。複数サーバから同時にデータがクライアント送られてくることが原因。この問題にはHBaseのある機能で対応した。

コプロセッサ

不要なデータ含めてすべてのデータを送っていたことが原因。slave上で前処理を行うことで、必要な情報だけを送るようにした。これを実現するためにはHBaseのコプロセッサ機能を使う。コプロセッサにより、ユーザが定義した処理を各リージョンサーバ上でパラレルに行える。

コプロセッサは大量のrowを集計するのに、MapReduceなしで行える。

まとめ

以上のチューニングにより、500,000 row/secを達成した。
冒頭に述べた750,000 row/secを達成する方法は次回のブログで述べる(らしい)