OpenIGのCaptureFilter利用時の注意点

OpenIG 2.1.0を利用しているシステムでCLOSE_WAITのコネクションが溜まって、応答が返らなくなるという現象があり、調査しました。

HTTPコネクションのリークの問題だろうと思い、外部システムにHTTPで通信しているClientHandlerというクラスのソースコードを見てみたところ、確かにコネクションを生成して、クローズしていません。その上、コネクションの最大数のデフォルトは64で、この値に達するとコネクションが生成できなくなり、応答が返らなくなるようでした…

/** Default maximum number of collections through HTTP client. */
private static final int DEFAULT_CONNECTIONS = 64;

ということで対策が必要です。ClientHandlerで生成してるコネクションなので、このクラスでクローズするのが適切かと思ったのですが、実際にやってみると、うまくいきません。どうもClientHandlerの後で呼ばれるFilterクラスでもコネクションを使いまわしているようで、ClientHandlerでクローズすると、Filterクラスで例外がスローされてしまいます。

さらに調べてみると、このコネクションをクローズしているのは、次の5つのFilterクラスであることが分かりました。

  • CaptureFilter
  • EntityExtractFilter
  • ExceptionFilter
  • HttpBasicAuthFilter
  • ReplaceFilter

したがって、ClientHandlerでコネクションを生成したら、これらのFilterクラスのいずれかを呼び出さないと、コネクションがリークするということになります。今回問題になっていた機能も、ClientHandlerを読んだ後に、これらのいずれも呼び出していませんでした。

この問題がなぜテスト環境では見つからなかったかというと、本番環境移行時にCaptureFilterを取り除いたことに理由があります。CaptureFilterはデバッグ目的でリクエストやレスポンスの中身を出力することができます。デバッグ時には便利なのですが、本番環境では性能面やセキュリティ面を考慮して、外すのが一般的です。このシステムでも本番環境移行時にCaptureFilterを外したところ、次の図のようにコネクションがリークしてしまったということです。

IGConnLeaks

そもそも、CaptureFilterはその名前と機能から判断すれば、ログ出力以外のことをすべきではないと考えるのが普通です(つまりCaptureFilterのバグと考えられます)。ガイドには、「Captures request and response messages for further analysis.」と書いてありますし。

ちなみにOpenIG 3.1.0から、CaptureFilterはDeprecatedになっており、代わりにCaptureDecoratorというクラスを使うことが推奨されているようです。おそらく、この問題は解決しているのではないかと思います。

広告