Tomcatとは
Apache Tomcatは、Java ServletやJSPなどを利用したWebアプリケーションを実行するためのWebコンテナです。
TomcatはWebアプリケーションからのリクエストを受け取り、Javaで実装された処理を実行します。Webアプリケーションからデータベースへアクセスする場合は、一般的にJDBC(Java Database Connectivity)を利用します。
また、データベースへの接続を効率よく再利用するために、コネクションプールを利用できます。
Tomcatからデータベースへ接続する仕組み
Tomcat上で動作するWebアプリケーションからデータベースへアクセスする場合、JDBCを利用してデータベースへ接続します。
ただし、リクエストを処理するたびにデータベースとの接続を新しく確立すると、接続処理のオーバーヘッドが発生します。
そこで利用されるのがコネクションプールです。
コネクションプールとは
コネクションプールは、データベースへの接続を再利用するための仕組みです。
アプリケーションがデータベースへアクセスするときに毎回新しい接続を作成するのではなく、プールで管理されているコネクションを取得して利用します。
処理が終わるとコネクションをプールへ返却し、別の処理から再び利用できる状態にします。これにより、データベースへの接続を毎回確立する場合と比べて、接続処理のオーバーヘッドを抑えることができます。

コネクションプールを利用している場合、アプリケーションからConnectionのclose()を呼び出しても、通常はデータベースとの物理的な接続をその都度切断するわけではありません。コネクションはプールへ返却され、後続の処理から再利用されます。
JNDIとDataSource
Tomcatでは、JNDI(Java Naming and Directory Interface)を利用してDataSourceをWebアプリケーションから参照できます。
DataSourceは、アプリケーションがデータベース接続を取得するためのインターフェースです。Tomcat側でデータベースの接続先やユーザー名、パスワード、コネクションプールなどを設定し、アプリケーションはJNDIに登録された名前を利用してDataSourceを取得します。
大まかな関係は次のようになります。

この仕組みにより、アプリケーションのコードからデータベースの接続情報を分離し、Tomcat側で接続設定を管理できます。
Tomcatのコネクションプールを設定する
TomcatでDataSourceやコネクションプールを設定する方法はいくつかあります。ここでは一例として、WebアプリケーションのMETA-INFディレクトリにcontext.xmlを配置する方法を紹介します。
context.xmlのResource要素に、データベースの接続先、JDBCドライバ、JNDI名、コネクションプールの設定などを記載します。
以下はOracle Databaseへ接続する場合の設定例です。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource
name="jdbc/LoginTemplate"
auth="Container"
type="javax.sql.DataSource"
username="[ユーザー名]"
password="[パスワード]"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@[ホスト名]:[ポート番号]:ORCL"
maxIdle="2"
maxTotal="20"
maxWaitMillis="5000"
/>
</Context>nameに指定したjdbc/LoginTemplateがJNDI名です。Webアプリケーションは、この名前を利用してDataSourceを検索します。
なお、Oracle Databaseへ接続するためには、利用するTomcatやJava、Oracle Databaseのバージョンに対応したOracle JDBC Driverが必要です。
コネクションプールの主なパラメータ
コネクションプールでは、同時に利用できるコネクション数や待ち時間などを設定できます。ここでは、Tomcatの標準DataSourceで利用されるDBCP 2を例に説明します。
maxTotal
maxTotalは、コネクションプールから同時に払い出すことができるコネクション数の上限です。
例えばmaxTotal=”20″の場合、最大20個のコネクションを同時に利用できます。20個すべてが使用中の状態で新しいコネクション取得要求が発生すると、利用可能なコネクションが返却されるまで待機します。
maxIdle
maxIdleは、プール内でアイドル状態として保持できるコネクション数の上限です。
アイドル状態のコネクションを保持しておくことで、新しいデータベースアクセスが発生したときに既存のコネクションを再利用できます。
一方で、アイドル状態のコネクションもデータベースとの接続を維持しているため、データベース側のセッションやメモリなどのリソースを消費します。そのため、maxIdleを設定することで、再利用するコネクションを確保しつつ、不要なコネクションを大量に保持することを防ぎます。
なお、maxIdleは常に保持するコネクション数ではなく、アイドル状態として保持できるコネクション数の上限です。
maxWaitMillis
maxWaitMillisは、利用可能なコネクションを取得できない場合に待機する最大時間をミリ秒単位で指定するパラメータです。
例えばmaxWaitMillis=”5000″の場合、利用可能なコネクションが存在しなければ最大5秒間待機します。その間にコネクションを取得できなかった場合は、コネクション取得が失敗します。
チューニングパラメータまとめ

コネクションプールが上限に達するとどうなるのか
コネクションプールを利用するうえで重要なのが、すべてのコネクションが使用中になった場合の動作です。
例えばmaxTotalを20に設定している場合、20個のコネクションがすべて使用中になると、それ以上のコネクションをすぐに払い出すことはできません。

このため、maxTotalは単に大きくすればよいわけではありません。値を大きくするとTomcatからデータベースへ同時に実行される処理が増え、データベース側のCPUやメモリ、セッション数などに負荷がかかる可能性があります。
一方で、maxTotalが小さすぎるとコネクションの取得待ちが発生しやすくなり、Webアプリケーションのレスポンスが遅くなる可能性があります。
そのため、Tomcatのworkerスレッド数やアプリケーションの同時実行数だけでなく、データベース側で処理できる接続数や負荷も考慮して設定することが重要です。
コネクションプールのチューニングの考え方
maxTotal、maxIdle、maxWaitMillisは、大きくすれば性能が向上するわけではありません。Tomcatの同時実行数やデータベースの処理能力、実際のアクセス状況を確認しながら調整することが重要です。
maxTotalの考え方
maxTotalを大きくすると、同時にデータベースへアクセスできる処理を増やせます。
一方で、大きくしすぎるとデータベースへ大量のSQLが同時に実行され、CPUやメモリ、セッション数などの負荷が高くなる可能性があります。
逆に小さすぎると、コネクションプールに空きがなくなり、コネクション取得待ちが発生しやすくなります。
そのため、Tomcatのworkerスレッド数だけで決めるのではなく、ピーク時の同時DBアクセス数やデータベース側の負荷を確認しながら調整します。
maxIdleの考え方
maxIdleを大きくすると、アイドル状態のコネクションを多く保持できるため、アクセスが発生したときに既存のコネクションを再利用しやすくなります。
一方で、大きくしすぎると利用していないコネクションを多く保持し、データベース側のセッションやメモリなどのリソースを消費します。
逆に小さすぎると、アクセスが増えるたびに新しいデータベース接続を作成する機会が増え、接続確立のオーバーヘッドが発生しやすくなります。
通常時に使用されているコネクション数などを確認しながら調整することが重要です。
maxWaitMillisの考え方
maxWaitMillisを大きくすると、コネクションプールが一時的に上限へ達しても、コネクションが返却されるまで待機できます。
一方で、長くしすぎるとリクエストがTomcat上で長時間待機し、workerスレッドの滞留につながる可能性があります。
逆に短すぎると、一時的なアクセス増加でもコネクション取得に失敗しやすくなります。
アプリケーション全体のタイムアウト時間との関係を考慮し、コネクション取得だけで長時間待機しないように調整します。
チューニングでは実際の利用状況を確認する
コネクションプールの適切な値は、システムの構成やアクセス量によって異なります。
負荷試験や本番環境の監視を通して、コネクションの使用数や取得待ち、データベース側のCPU使用率やセッション数などを確認しながら調整します。
特にmaxTotalは、Tomcat側だけでなくデータベース側の処理能力も考慮することが重要です。
コネクションプールは、単に多くのコネクションを確保するための仕組みではなく、Tomcatからデータベースへの同時アクセス数を制御する役割も持っています。
コネクションプールのチューニングの考え方まとめ

コネクションを必ず返却する
コネクションプールを利用するときは、取得したコネクションを確実に返却することが重要です。
アプリケーションがコネクションを取得したまま返却しない状態が続くと、利用可能なコネクションが減少します。最終的にすべてのコネクションが使用中になると、新しい処理がコネクションを取得できなくなる可能性があります。
Javaではtry-with-resourcesを利用することで、処理終了時にConnectionのclose()を呼び出すコードを簡潔に記述できます。
try (Connection connection = dataSource.getConnection()) {
// SQLを実行
}コネクションプールを利用している場合、このclose()によって通常はコネクションがプールへ返却され、後続の処理から再利用できるようになります。
まとめ
Tomcat上のWebアプリケーションからデータベースへアクセスする場合、JDBCやDataSource、JNDI、コネクションプールなどの仕組みが利用されます。
コネクションプールを利用することで、データベース接続を毎回確立するのではなく、既存の接続を再利用できます。これにより、接続処理のオーバーヘッドを抑えることができます。
一方で、maxTotalが小さすぎるとコネクション取得待ちが発生し、大きすぎるとデータベースへの同時アクセスが増加します。Tomcatとデータベースの両方を考慮して設定することが重要です。
参考資料
TomcatのJDBCやコネクションプールについて、さらに詳しく確認したい場合はApache Tomcatの公式ドキュメントも参考にしてください。
Apache Tomcat 9 – JNDI Datasource How-To
Apache Tomcat 9 – The Tomcat JDBC Connection Pool
関連記事
Tomcatの並列処理やチューニングについては、以下の記事でも解説しています。


コメント