nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

TomcatやJBossでHTTPリクエスト単位で並行実行数を制限するサーブレットフィルタ

WebLogicからの移行とかで、HTTPリクエスト単位で流量制御などの目的で並行実行数を制限したいという要望がたまにある。WebLogicではWork Managerというのがあって、これがHTTPリクエスト単位での設定なのだそうだ。

TomcatJBossではApache httpdのMaxClientsと同じく、リクエスト単位ではなくクライアント単位(ソケット単位)でスレッドを割り当てる。このモデルでは、例えばmaxThreads="20"とかにしたら常に同時に20個のリクエストをさばいてくれる、という仮定は成り立たない。クライアントがkeep aliveで接続している間はスレッドも待ち続けるので、21番目のリクエストは先に接続した20のクライアントがkeep aliveを終了してコネクションを切断するまで処理されない。MaxClientsは名前の通りMaxClientsなのであってMaxConcurrentRequestsではない、ということだ。

というわけでスレッド割り当てモデルに左右されずにMaxConcurrentRequestsを実現するものをサーブレットフィルタで簡単に書いてみる。

https://github.com/nekop/java-examples/blob/master/old/servlet/src/main/java/jp/programmers/examples/SemaphoreFilter.java

単なるサンプルなので安直な実装にしてる。Semaphore使っただけでロジックと呼べるようなものはほとんど無いのだけど。

あとは設定を細かくできるようにしたり、読みやすい設定ファイルにしたりするとそこそこ使えるんじゃないか。例えば以下のような設定ができるようにするとか。

実は上のユースケースはこのサンプルで書いたサーブレットフィルタそのままでも実現できるけど、web.xmlにこの設定をモリモリ書いたらたぶん読み書きしにくいので独自の設定ファイルにしたほうが良い。

あと、TomcatJBoss ASにはSemaphoreValveというこれと同じようなコンテナプラグインがあるのだけど、これを使ってしまうとポータビリティが失われるので今回紹介したようにFilterで実装するほうが良いと思う。

きちんとしたSIerさんはこういうようなセッションサイズ測ったりユーザのトラッキングしてくれたりミドルウェアに機能付加するようないろいろなサーブレットフィルタのライブラリを持っていると思うんだけど、オープンソースで公開されてたりするものはないだろうか?