表題の件、調べた結果をメモしておく。
環境
- Amazon Linux AMI release 2016.09
- Redash Version: 0.12.0.b2449
背景
EC2上にRedashをインストールしてみたが、Data SourceにTreasureDataを設定したところPrestoは正常に動作するが、HiveがTest Connectionでこける事象が発生した。
調査
Test Connectionが失敗したときのRedashのapi_error.logに以下のようなメッセージが出力されていた。
[2016-12-01 23:57:06 +0000] [13701] [CRITICAL] WORKER TIMEOUT (pid:13716)
[2016-12-01 23:57:06,207][PID:13716][INFO][metrics] method=POST path=/api/data_sources/3/test endpoint=datasourcetestresource status=500 content_type=? content_length=-1 duration=30242.46 query_count=5 query_duration=33.58
[2016-12-01 23:57:06 +0000] [13716] [INFO] Worker exiting (pid: 13716)
[2016-12-01 23:57:06 +0000] [7475] [INFO] Booting worker with pid: 7475
これを調べたところ、Redashが使っているGunicornというWSGI serverが出しているエラーだった。
このWGSI serverを使ってRedashのserverプロセスはマスタプロセス+workerプロセス(デフォルトで4個)という構成でリクエストを捌いている。
Gunicornの機能として、マスタプロセスとworkerプロセス間でハートビート通信をしていて、一定時間(デフォルト30秒)以上応答がないworkerプロセスを強制的にプロセス停止し、新規workerプロセス立ち上げをする機構が存在している。
上記のCRITICALエラーメッセージWORKER TIMEOUT
はこの際に発生する。
つまり、
- HiveのData Sourceに対してTest Connectionボタンを押すと、いずれかのWorkerプロセスが実際の処理を開始する
- 処理が30秒たっても終わらないため、マスタプロセスにより当該Workerプロセスが強制停止されてしまう
という事象が起きていると思われる。
PrestoはOKでHiveがダメだったのは、Hive特有の初期化処理に時間がかかるという特徴でこのタイムアウトに引っかかってしまったためだろう。
対策
Gunicornのドキュメントを参照したところ、以下のいずれかがある。
http://docs.gunicorn.org/en/stable/settings.html
- Workerプロセスのハートビート通信応答のタイムアウト値を伸ばす
- workerプロセスのタイプを変えて処理とハートビート応答を非同期にできるようにする
1つ目は対処療法なので、なるべくなら2つ目を取りたいところ。
1つ目はgunicorn起動時のパラメータオプション-t/--timeout
に秒数を渡せばよい。
2つめは、gunicorn起動時のパラメータオプション-k/--worker_class
にWorkerのタイプを指定する。
指定できるWorkerのタイプ
デフォルトで、以下のクラスが指定できるようだ。それぞれ、Pythonのパッケージが必要なのでpip
で別途インストールしないといけない。
- sync : デフォルトでの設定
- eventlet : eventlet >= 0.9.7 が必要
- gevent : gevent >= 0.13 が必要
- tornado : tornado >= 0.2 が必要
- gthread - Python 2 requires the futures package to be installed
- gaiohttp - Requires Python 3.4 and aiohttp >= 0.21.5
そのほか、自分で独自のWorkerクラスを実装することもできる。
Redash用の対策
今回は、Workerクラスにgeventを指定する方法で解決することができた。
$ sudo pip install gevent
した上で、Redashの起動スクリプトにてgunicorn起動を行なっている箇所で起動時のオプションパラメータを追加する。
[program:redash_server]
command=/opt/redash/current/bin/run /usr/local/bin/gunicorn -b 127.0.0.1:5000 --name redash -w 4 -k gevent redash.wsgi:app
これで、Workerプロセスにおいて、HiveのTest Connectionの処理とマスタプロセスとのハートビート通信応答処理が非同期に行われるようになり、HiveのData SourceもRedashから扱えるようになる。
考察
Gunicornのドキュメントにて記載されているように、以下のような場合にはWorkerクラスの設定を非同期にする検討をした方がよい。
- 長時間のブロッキング呼び出しを実行する(外部のWebサービスを利用する)
- インターネット越しのリクエスト応答を行う
- ストリーミング処理を行う
- ある程度長い時間のポーリング処理を行う
- WebSocketsを利用
- Cometを利用
今回の場合、Redashから外部のWebサービスであるTreasure DataのHiveサービスを利用しようとしていたので、まさに該当していたというわけ。
クラウドでなくてもRedashから30秒以上かかるクエリを実行することは普通にあると思われるので、Redashを使う際にはWorkerクラスの設定は非同期に変えておくのが良さそう。
以上。