Apache⇔Tomcat mod_proxy_ajp連携で「ThreadPool logFull 〜」エラー発生

現象

Tomcatで以下のログを吐き、接続が非常に遅くなる現象が発生した。

org.apache.tomcat.util.threads.ThreadPool logFull
致命的: すべてのスレッド (200) が現在稼働中で待機しています。maxThreads (200) を増やすか、そのサーブレットのステータスを
チェックしてください

調査

ひとまずThreadDumpを取る。
結果、以下のようなThreadが大量発生していた。

"TP-Processor176" daemon prio=1 tid=0x09a994b8 nid=0x13ee runnable [0x57a53000..0x57a53db0]
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
        - locked <0xb043e0f8> (a java.io.BufferedInputStream)
        at org.apache.jk.common.ChannelSocket.read(ChannelSocket.java:620)
        at org.apache.jk.common.ChannelSocket.receive(ChannelSocket.java:558)
        at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:685)
        at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:889)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:686)
        at java.lang.Thread.run(Thread.java:595)

同様の現象を説明しているページを発見。

しかし本現象が発生した環境では、Apache側ではmaxClientsを150に設定しているので超えることは無いはずなのだが。
Apacheの再起動を連発すると、Tomcat側にコネクションが残り続ける?
とにかく何とかする必要がある。

対策

TomcatAJPコネクタの設定を調査
http://www.oki.com/jp/oss/document/tomcat/tomcat-6.0.14/build/tomcat-docs/config/ajp.html
http://tomcat.apache.org/connectors-doc/generic_howto/timeouts.html

これによるとAJPコネクタのconnectionTimeoutのデフォルト値が無限大に設定されているみたいだ。。。
HTTPコネクタのconnectionTimeoutのデフォルトは60秒。混同しないように注意。


どうやらこいつを設定してやれば、不要なコネクションが破棄される模様。
server.xmlでデフォルトで設定されているAJPコネクタ設定を

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

こう修正

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" connectionTimeout="20000" redirectPort="8443" />

これで不必要なコネクションが解放されるはず。

他のパラメータも調整。
最終的にはこのように設定した。

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3"
               maxThreads="200" minSpareThreads="25" maxSpareThreads="200"
               backlog="100" connectionTimeout="20000"
               enableLookups="false" redirectPort="8443" />

補足

同様の現象はコネクタにmod_jkを使っている類似プロジェクトでは発生していなかった。
よく見るとmod_jkではworkers.propertiesのパラメータでconnect_timeout設定を書いている。
今回採用しているmod_proxy_ajpは追加でファイルを用意する必要がないため、server.xml側に各種設定を書かなければならなかった。

結論

ApacheTomcatの連携でmod_proxy_ajpを使用する場合は、必ずserver.xmlのデフォルト以外のパラメータ(特にconnectionTimeout)を設定!