Tomcatの同時接続数とスレッドを徹底解説|maxThreads・maxConnections・acceptCountのチューニング

Tomcatとは

Apache Tomcatは、JavaのServletやJSPを実行するためのOSSのWebコンテナです。WebアプリケーションへのHTTPリクエストを受け取り、アプリケーションの処理を実行してクライアントへレスポンスを返します。

Tomcatは単体でHTTPリクエストを受け付けることもできますが、システム構成によってはApache HTTP ServerなどのWebサーバやロードバランサ、リバースプロキシの後段に配置されます。

多数のアクセスを処理するシステムでは、Tomcatがどれだけの接続やリクエストを同時に処理できるかを理解しておくことが重要です。本記事では、Tomcat 10.1のHTTP Connectorを中心に、並列処理の仕組みとmaxThreadsmaxConnectionsacceptCountの関係、チューニングの考え方を解説します。

Tomcatの並列処理の仕組み

TomcatのHTTP Connectorは、クライアントからTCP接続を受け付け、HTTPリクエストをWebアプリケーションへ渡します。Tomcat 10.1では、標準のHTTP/1.1 ConnectorとしてNIO Connectorが使用されます。

Tomcatがリクエストを処理するまでには、OSのTCP/IPスタックとTomcatのConnectorがそれぞれ役割を持っています。

大まかな流れは次のとおりです。

  1. クライアントからTCP接続要求が到着すると、3-way handshake完了前の接続はOSのSYN Queueで管理されます。
  2. 3-way handshakeが完了すると、接続はOSのAccept Queue(listen backlog)でaccept()されるのを待ちます。
  3. TomcatのAcceptor Threadaccept()を実行し、接続をTomcat側へ取り込みます。
  4. Tomcatは接続をmaxConnectionsの範囲内で保持し、NIOのPoller ThreadがソケットのI/Oイベントを監視します。
  5. HTTPリクエストを処理できる状態になると、処理がWorker Threadへ渡されます。
  6. Worker ThreadがServletなどのWebアプリケーションを実行し、処理結果をHTTPレスポンスとして返します。

通常の同期リクエストでは、リクエストを処理している間、1つのWorker Threadが使用されます。同時に処理できるリクエスト数は、主にmaxThreadsによって制御されます。

一方、maxConnectionsはTomcatが同時に受け入れて保持できる接続数の上限です。そのため、Tomcatでは「接続していること」と「Worker Threadでリクエストを処理していること」は分けて考える必要があります。

例えばKeep-Alive中の接続はTomcatに保持されていても、常にWorker Threadを使用しているわけではありません。NIO ConnectorではPollerが複数の接続のI/Oイベントを監視し、処理が必要になったリクエストをWorker Threadへ渡します。

また、TomcatがmaxConnectionsに達すると、新しい接続はすぐにはTomcat側へ取り込まれず、OS側のAccept Queueで待機することがあります。この待機可能な接続数に関係するTomcatの設定がacceptCountです。

つまり、それぞれの役割は次のように整理できます。

SYN Queue / Accept Queue(OS)
→ Acceptor
→ maxConnections(Tomcatが保持する接続数)
→ Poller
→ maxThreads(同時にリクエストを処理するスレッド数)
→ Web Application

ここで重要なのは、同時接続数と同時に処理できるリクエスト数は同じではないという点です。

maxConnections、acceptCount、maxThreadsはそれぞれ異なるレイヤーを制御するため、Tomcatの並列処理や高負荷時の挙動を理解するには、これらを分けて考えることが重要です。

Tomcatのチューニングの考え方

maxThreads・maxConnections・acceptCountの関係

前述の通り、Tomcatの同時処理を理解するうえで重要なパラメータが、maxThreadsmaxConnectionsacceptCountです。

パラメータ名役割Tomcat 10.1のデフォルト値
maxThreadsリクエストを処理するスレッドの最大数。同期リクエストで同時処理数を考える際の重要な上限。200
maxConnectionsTomcatが同時に受け入れて処理対象として保持する接続数の上限。8192(NIO/NIO2)
acceptCountmaxConnections到達後にOS側で待機できる接続要求のキュー長。100

それぞれ詳細について説明します。

maxThreads

maxThreadsは、Connectorが作成するリクエスト処理スレッドの最大数です。通常の同期リクエストでは、1つのリクエストを処理している間に1つのスレッドを使用するため、maxThreadsは同時に処理できるリクエスト数を考えるうえで重要な上限になります。

Tomcat 10.1のHTTP Connectorでは、内部スレッドプールを利用する場合のmaxThreadsのデフォルト値は200です。ただし、Connectorに外部Executorを関連付けている場合、Connector側のmaxThreadsは使用されず、Executor側の設定が適用されます。

maxConnections

maxConnectionsは、Tomcatが同時に受け入れて処理対象として保持する接続数の上限です。

maxThreadsのすべての処理スレッドが使用中でも、maxConnectionsに達するまでは追加の接続を受け付けることができます。そのため、maxConnectionsがmaxThreadsより大きい構成では、接続は確立していてもリクエスト処理スレッドが空くのを待つ接続が発生することがあります。

Tomcat 10.1のNIO/NIO2 Connectorでは、maxConnectionsのデフォルト値は8192です。

acceptCount

maxConnectionsに達すると、それ以上の接続要求はOSが提供する接続キューで待機します。acceptCountは、このOS側の接続キューの最大長を指定するためのパラメータです。

acceptCountのデフォルト値は100です。ただし、実際のキューサイズはOSの実装や設定の影響を受けるため、Tomcatに設定した値がそのまま使われるとは限りません。OS側のキューも満杯になると、新しい接続が拒否されたり、タイムアウトしたりする可能性があります。

処理が詰まった際の挙動

Tomcatへのリクエストが増加すると、まず影響を受けるのがmaxThreadsです。

すべてのWorker Threadが処理中になると、新しいリクエストをすぐに処理できなくなります。ただし、TomcatはmaxConnectionsの範囲内で接続を保持できるため、すぐに接続が拒否されるわけではありません。

さらに接続が増えてmaxConnectionsに達すると、Tomcatはそれ以上の接続を受け入れられなくなり、新しい接続はOS側のAccept Queueで待つようになります。

このAccept Queueの大きさに関係するのがacceptCountです。

さらに接続が増えてAccept Queueもいっぱいになると、新しい接続を待機させる余裕がなくなり、接続拒否やタイムアウトが発生する可能性があります。

つまり、高負荷時には次のように後段から前段へ影響が波及します。

maxThreadsが上限に達する

リクエストをすぐ処理できない

Tomcatが保持する接続が増える

maxConnectionsに達する

新しい接続がOSのAccept Queueで待つ

acceptCountに関係するキューもいっぱいになる

接続拒否・タイムアウトの可能性

このように、maxThreads、maxConnections、acceptCountは独立したパラメータですが、高負荷時には後ろから前へ詰まりが波及するバックプレッシャーとして捉えると理解しやすくなります。

maxThreadsを増やせば性能が上がるわけではない

アクセス数が増えたときに、maxThreadsを大きくすれば性能が上がると考えがちですが、単純に値を増やせばよいわけではありません。

スレッド数を増やすと、より多くのリクエストを並列に処理できる可能性があります。一方で、アプリケーションの処理内容によってはCPU使用率やメモリ使用量が増加し、スレッド間の切り替えによるオーバーヘッドも増えます。

さらに、Tomcatの後段にあるデータベースや外部APIがボトルネックになっている場合、maxThreadsだけを増やしても処理性能は向上しません。むしろ待機する処理が増え、レスポンスタイムが悪化する可能性があります。

DBコネクションプールとのバランスも重要

Webアプリケーションからデータベースへアクセスするシステムでは、Tomcatのスレッド数だけでなく、DBコネクションプールとのバランスを考える必要があります。

例えばmaxThreadsを500に設定していても、DBコネクションプールの最大接続数が50で、多くのリクエストがDBアクセスを必要とする場合、同時にDBを利用できる処理数はDBコネクションプールによって制限されます。

この状態でTomcatのスレッド数だけを増やすと、DBコネクションの取得待ちとなるスレッドが増える可能性があります。そのため、TomcatのチューニングではTomcatだけではなく、アプリケーション、DBコネクションプール、データベース、外部サービスまで含めてボトルネックを確認することが重要です。

コネクション関連の詳細は以下でまとめているので、合わせて参照ください。
Tomcatのデータベース接続を徹底解説|JDBC・JNDI・DataSource・コネクションプール

チューニング手順

maxThreadsなどの値を決めるときは、推測だけで設定するのではなく、性能試験や本番環境の監視結果を基に調整します。

  1. 想定する同時アクセス数を整理する
    通常時とピーク時のリクエスト数、レスポンスタイム、接続数を確認します。
  2. 現在のTomcatの状態を確認する
    処理中スレッド数、最大スレッド数、接続数、レスポンスタイムなどをJMXや監視ツールで確認します。
  3. 後段のリソースも確認する
    CPU、メモリ、DBコネクションプール、データベース、外部APIなどにボトルネックがないか確認します。
  4. 性能試験で設定値を変更する
    maxThreadsなどを段階的に変更し、スループットとレスポンスタイムがどのように変化するか確認します。
  5. エラーや待ち時間も確認する
    平均レスポンスタイムだけでなく、タイムアウト、接続拒否、DB接続待ち、CPU使用率なども合わせて確認します。

重要なのは、最大スループットだけを追求するのではなく、ピーク時でも許容できるレスポンスタイムを維持し、後段システムを過負荷にしない値を探すことです。

まとめ

Tomcatでは、maxThreads、maxConnections、acceptCountがそれぞれ異なる役割を持っています。

  • maxThreads:リクエスト処理スレッドの最大数
  • maxConnections:Tomcatが同時に受け入れて処理対象として保持する接続数の上限
  • acceptCount:maxConnections到達後にOS側で待機できる接続要求のキュー長

特に重要なのは、同時接続数と同時処理数は同じではないという点です。maxThreadsを増やせば必ず性能が向上するわけでもありません。

Tomcatをチューニングするときは、CPUやメモリだけでなく、DBコネクションプール、データベース、外部サービスなどを含めてボトルネックを確認し、性能試験の結果を基に設定値を決めることが重要です。

ほかにもチューニング関連のコンテンツを配信していますので、ぜひ目を通してもらえると嬉しいです。
【Apache】並列処理の仕組みとチューニング方法をまとめてみた。

参考資料

Tomcatのパラメータはバージョンによってデフォルト値や仕様が異なる場合があります。実際に設定する際は、利用しているTomcatの公式ドキュメントを確認してください。

コメント