というか、えー、問題にハマりましたので。問題が炸裂した夜はわたくし渋谷で飲んでおりまして、対応と原因のアタリをとっていただきました同僚の方々にはお礼の言葉しかございません。
ThriftHiveプロトコルにおけるcleanメソッド
まず第一に、HiveServerに対してThrift経由で接続(ThriftHiveを使用)する場合、以下の点に注意する必要がある、というのが大前提です。
- クライアントはクエリ結果の読み出しを含む全処理が終わったあとに clean() を呼んでから通信を切断すること
- これが行われないとHiveServerはクエリの処理に使用したファイルディスクリプタや一時ファイルの類をすべて保持したままにする
- cleanを自動的にやってくれるような機構は存在しない
- cleanメソッドは比較的最近のバージョンのHiveにしか存在しない
- 少なくとも自分が最初にshibを作ったとき(CDH3b2がターゲット)は存在しなかった
- CDH3u2では存在したので、その間のどこか(に対応するHiveのどれかのバージョン)で取り込まれた
cleanを呼ばないとHiveServerが開いているファイルディスクリプタは増え続け、ulimitで設定した値を超えたところで一切の接続要求に応答しなくなってスタックします。こうなったら再起動するしか手がありませんから注意しましょう。
しかしクライアントの作り方を間違えるとサーバが死亡するってだいぶひどいですね。というか、そもそもcleanメソッドなかった期間がだいぶ長かったはずだけどその間どうしてたんだ。
まあHiveServer2とやらがそのうち出てくるらしいのでそれに期待すればいいんじゃないでしょうか。
HiveServerにおけるファイルディスクリプタの扱い
上記の点に注意してクライアントのコードを書き換えても、Hiveクエリ実行後にやっぱりファイルディスクリプタがふたつ開かれたままの状態になってしまい、あれーやっぱりリークしてねー? と思ってtwitterでぎゃーと騒いでたら親切なタムタムさんが調べてくれた。*1
で、結論としてはGCがきちんと走れば結果的にはリークしないで済む、ようですね! GCにfdのcloseを頼るのは個人的にはどうかと思うけど、問題ないんならまあ使う分にはいいや。
ちなみに、結論が出る前にHiveServerのopenしているファイルディスクリプタ数でも監視するかーと仕掛けておいたグラフがこちらになります。GrowthForecastまじべんり。
大丈夫そうですね!
*1:というか、自分でもだいたいコードは読んだんだけどまとめる気力がなかった……。