Tomcatにおける非同期処理
はじめに
Webアプリケーションでは、クライアントからのHTTP要求に対して長時間を要する処理を行うとHTTP応答がタイムアウトになり、HTTP要求を正常に受け付けられたかどうかを確認しづらくなります。また、長時間を要する処理をバックグランドで行う場合でも、非同期タスクの同時実行数を制限しなければ、スレッド数がどんどん増え運用環境の資源が枯渇すると、動作不能に陥るおそれがあります。
Tomcatコンテナ上で動作するTomcatアプリケーションで、下図のように長時間を要する処理を非同期で呼び出す方法を考えます。
図1 非同期処理の流れ
図1では、Tomcatコンテナの中にController、Service、Entityの3つがあります。クライアントからHTTP要求が来たときに、Tomcatコンテナを介してControllerからServiceを非同期で呼び出しています。非同期呼び出し後に、すぐクライアントへHTTP応答を返せるため、HTTP要求を受け付けたのかそれとも拒否したのかをクライアントへ通知できます。非同期タスクの実行状況をEntityへ反映しておけば、後から別のHTTP要求を出してその実行状況を確認できます。
非同期呼び出しの実装にあたっては、冒頭で述べたとおり非同期タスクの流動制御が必要ですが、ここで知っておきたいのは、アプリケーションが「適当に」スレッドを生成するのは推奨されていない点です。なぜなら、アプリケーションが生成したスレッドをTomcatコンテナやJava EEコンテナが認識しないため、スレッドのライフサイクルを適切に管理できなくなるためです。そこで、スレッドの個数やライフサイクルなどの管理を行う仕様である「Concurrency Utilities for Java EE(JSR 236)」が提唱され、Java EE 7に導入されました。
TomcatコンテナはJava EEコンテナのサブセットのようなものであり、JSR 236をサポートしているわけではありませんが、Spring Frameworkを導入すればスレッドのライフサイクル管理ができるようになります。ここでは、Spring Frameworkを活用した「シングルテナント対応」および「マルチテナント対応」の非同時処理の流動制御の実装方法を考えていきます。
記事構成
この記事は3つの記事で構成しています。
- 「Tomcatにおける非同期処理の実装」←この記事
サンプルソース
この記事で作成したソースコードは、GitHubにあります。
まとめ
- シングルテナントの場合
- 非同期メソッドとリクエストが1対1の対応なら、Spring Frameworkの機能で対応可能
- マルチテナントの場合
- 非同期メソッドとリクエストが1対多の対応なら、自前でスレッドプールとそのライフサイクルを用意する必要あり