- Authors

- Name
- Youngju Kim
- @fjvbn20031
目次
- Embedded Tomcatの基本構造
- 主要設定オプション
- SSL/TLS設定
- HTTPとHTTPSの同時運用
- スレッドプールのチューニング
- Undertowへの切り替え
- カスタムErrorPageとFilterRegistration
- Graceful Shutdown
- クイズ
1. Embedded Tomcatの基本構造
Spring BootはEmbedded Tomcatを標準で内蔵しており、別途WASをインストールすることなく単独で実行可能なJARファイルを作成できます。spring-boot-starter-web依存関係を追加すると、自動的にTomcatが含まれます。
spring-boot-starter-web依存関係ツリー
spring-boot-starter-web
└── spring-boot-starter-tomcat
├── tomcat-embed-core
├── tomcat-embed-el
└── tomcat-embed-websocket
組み込みサーバー比較表
| 項目 | Tomcat | Undertow | Jetty |
|---|---|---|---|
| デフォルト搭載 | あり | なし | なし |
| メモリ使用量 | 中 | 低 | 低 |
| HTTP/2サポート | あり | あり | あり |
| WebSocket | あり | あり | あり |
| スループット | 高 | 非常に高い | 高 |
| 成熟度/安定性 | 非常に高い | 高 | 高 |
| コミュニティ | 非常に大きい | 中 | 大きい |
Tomcatは最も実績のあるサーブレットコンテナであり、ほとんどのエンタープライズSpring Bootアプリケーションのデフォルト選択肢です。Undertowは低メモリ使用量と高い並行処理が必要なマイクロサービスに適しています。
2. 主要設定オプション
application.ymlでEmbedded Tomcatのほぼすべての設定を制御できます。
全体設定例
server:
port: 8080
servlet:
context-path: /api
session:
timeout: 30m
cookie:
http-only: true
secure: true
tomcat:
threads:
max: 200 # 最大ワーカースレッド数(デフォルト: 200)
min-spare: 10 # 最小アイドルスレッド数(デフォルト: 10)
max-connections: 8192 # 同時接続の最大数
accept-count: 100 # max-connections超過時の待機キューサイズ
connection-timeout: 20000 # 接続タイムアウト(ミリ秒)
max-http-form-post-size: 2MB
max-swallow-size: 2MB
uri-encoding: UTF-8
accesslog:
enabled: true
directory: logs
prefix: access_log
suffix: .txt
pattern: combined
rotate: true
shutdown: graceful
http2:
enabled: true
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
min-response-size: 1024
主要パラメータの詳細説明
threads.max(最大スレッド数)
- デフォルト: 200
- 同時に処理できるリクエストの最大数
- CPUコア数とアプリケーションのI/O特性に応じて調整が必要
max-connections
- デフォルト: 8192
- NIOコネクタが同時に維持できる最大TCP接続数
- Keep-Alive接続を効率的に管理するため、
threads.maxよりはるかに大きく設定する
accept-count
- デフォルト: 100
max-connectionsが上限に達したときのOSレベルのソケット待機キューサイズ- この値を超えるとクライアントにConnection Refusedが返される
connection-timeout
- デフォルト: 20000ms(20秒)
- クライアントがリクエストデータを送信するのに許可された最大時間
3. SSL/TLS設定
テスト用自己署名証明書の生成
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 \
-storetype PKCS12 -keystore keystore.p12 -validity 3650 \
-storepass changeit -dname "CN=localhost, OU=Dev, O=Example, L=Tokyo, S=Tokyo, C=JP"
application.yml SSL設定
server:
port: 8443
ssl:
key-store: classpath:keystore.p12
key-store-password: changeit
key-store-type: PKCS12
key-alias: tomcat
enabled: true
protocol: TLS
enabled-protocols: TLSv1.2,TLSv1.3
ciphers: TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256
Let's Encrypt証明書の連携
Let's EncryptのPEM形式の証明書をPKCS12に変換してTomcatで使用します。
# PEMをPKCS12に変換
openssl pkcs12 -export \
-in /etc/letsencrypt/live/yourdomain.com/fullchain.pem \
-inkey /etc/letsencrypt/live/yourdomain.com/privkey.pem \
-out keystore.p12 \
-name tomcat \
-passout pass:yourpassword
本番環境では、キーストアのパスワードを環境変数で注入することがセキュリティ上安全です。
server:
ssl:
key-store: file:/etc/ssl/keystore.p12
key-store-password: ${SSL_KEYSTORE_PASSWORD}
4. HTTPとHTTPSの同時運用
Spring Bootはデフォルトで1つのポートのみをサポートしますが、TomcatServletWebServerFactoryをカスタマイズしてHTTPとHTTPSの両方を同時に開くことができます。
2ポートの同時開放
@Configuration
public class TomcatConfig {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addAdditionalTomcatConnectors(createHttpConnector());
return factory;
}
private Connector createHttpConnector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}
HTTPからHTTPSへの自動リダイレクト
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.requiresChannel(channel ->
channel.anyRequest().requiresSecure()
);
return http.build();
}
}
5. スレッドプールのチューニング
サイジングの公式
I/Oバウンドアプリケーション(DB、外部API呼び出し)
適切なスレッド数 = CPUコア数 x (1 + 待機時間 / 処理時間)
CPUバウンドアプリケーション(画像処理、暗号化)
適切なスレッド数 = CPUコア数 + 1
ほとんどのWebアプリケーションはI/Oバウンドのため、CPUコア数の10〜20倍が出発点となります。JMeterやGatlingを使った負荷テストで最適値を見つけることが重要です。
Java 21 Virtual Threadの適用
Java 21のVirtual Threadを活用することで、スレッドプールサイズの手動調整が大幅に不要になります。
spring:
threads:
virtual:
enabled: true
またはコードで直接設定:
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
Actuatorでのスレッド監視
management:
endpoints:
web:
exposure:
include: metrics,health,threaddump
/actuator/metrics/tomcat.threads.busyと/actuator/metrics/tomcat.threads.config.maxでリアルタイムのスレッド使用量を確認できます。
6. Undertowへの切り替え
依存関係の変更
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
Undertow設定オプション
server:
undertow:
threads:
worker: 200 # ワーカースレッド数(デフォルト: CPUコア x 8)
io: 4 # I/Oスレッド数(デフォルト: CPUコア x 2)
buffer-size: 16384 # バッファサイズ(バイト)
direct-buffers: true
max-http-post-size: 10MB
accesslog:
enabled: true
dir: logs
pattern: combined
TomcatとUndertowのパフォーマンス比較
Undertowのノンブロッキングアーキテクチャは、高並行環境でTomcatよりも低いメモリ使用量と高いスループットを実現します。WebSocketやサーバープッシュを多用するアプリケーションでその差が顕著です。標準的なREST APIサーバーでは、2つのサーバー間のパフォーマンス差は比較的小さくなります。
7. カスタムErrorPageとFilterRegistration
TomcatServletWebServerFactoryのカスタマイズ
@Configuration
public class WebServerConfig {
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
// カスタムエラーページの登録
factory.addErrorPages(
new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"),
new ErrorPage(Exception.class, "/error/general")
);
// Tomcatコンテキストのカスタマイズ
factory.addContextCustomizers(context -> {
context.setSessionTimeout(30);
context.setUseHttpOnly(true);
});
return factory;
}
}
カスタムFilterの登録
@Bean
public FilterRegistrationBean<RequestLoggingFilter> loggingFilter() {
FilterRegistrationBean<RequestLoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new RequestLoggingFilter());
registrationBean.addUrlPatterns("/api/*");
registrationBean.setOrder(1);
return registrationBean;
}
リバースプロキシ・ロードバランサー設定
nginxやAWS ALBなどのリバースプロキシの背後で動作させる場合、クライアントIPアドレスとプロトコルを正しく解決するためにRemoteIPバルブを設定します。
server:
tomcat:
remoteip:
remote-ip-header: x-forwarded-for
protocol-header: x-forwarded-proto
8. Graceful Shutdown
設定
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
Graceful Shutdownを有効にすると、SIGTERM受信後に新しいリクエストの受け付けを停止し、処理中のリクエストが完了するまで最大30秒待ってからシャットダウンします。
Kubernetes連携
# kubernetes deployment.yaml
spec:
template:
spec:
terminationGracePeriodSeconds: 60 # Kubernetesレベルの終了待機
containers:
- name: app
lifecycle:
preStop:
exec:
command: ['/bin/sh', '-c', 'sleep 5'] # ロードバランサー除外待機
KubernetesのterminationGracePeriodSecondsは、Spring Bootのtimeout-per-shutdown-phaseより5〜10秒余裕を持って設定する必要があります。
ヘルスプローブ連携
management:
endpoint:
health:
probes:
enabled: true
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
Readiness ProbeがOUT_OF_SERVICEに切り替わってロードバランサーから除外された後に実際のシャットダウンが開始されるよう設定します。
9. クイズ
Q1. Spring Boot TomcatでTCP同時接続の最大数を制御する設定は?
答え: server.tomcat.max-connections
解説: max-connectionsはTomcat NIOコネクタが同時に維持できる最大接続数を制御します。デフォルト値は8192です。Keep-Alive接続を効率的に処理するため、この値はthreads.maxよりはるかに大きく設定します。accept-countはmax-connectionsが上限に達したときのOSレベルのソケット待機キューサイズを意味します。
Q2. Graceful Shutdownで終了シグナルを受け取った後の動作は?
答え: 新しいリクエストの受け付けを拒否し、設定されたtimeout-per-shutdown-phaseの時間内に処理中のリクエストが完了するまで待機してからシャットダウンします。
解説: server.shutdown=gracefulに設定すると、SIGTERM受信後にTomcatは新しい接続の受け付けを停止し、アクティブなリクエストの完了を待ちます。spring.lifecycle.timeout-per-shutdown-phaseで最大待機時間を設定します。Kubernetes環境ではterminationGracePeriodSecondsをSpring Bootのタイムアウトより高く設定して、完全なグレースフルシャットダウンシーケンスが完了するようにする必要があります。
Q3. Java 21のVirtual ThreadをSpring Boot Tomcatに適用する方法は?
答え: spring.threads.virtual.enabled=trueを設定するか、TomcatProtocolHandlerCustomizer BeanでExecutors.newVirtualThreadPerTaskExecutor()をexecutorとして設定します。
解説: JDK 21で安定版として導入されたVirtual Threadは、ブロッキングI/O操作中もOSスレッドを占有しない軽量スレッドで、大規模な並行リクエスト処理に適しています。Spring Boot 3.2以降では、spring.threads.virtual.enabled=trueプロパティのみで簡単に有効化できます。
Q4. TomcatをUndertowに交換する際に必ず行うべき作業は?
答え: spring-boot-starter-webからspring-boot-starter-tomcatをexclusionで除外してから、spring-boot-starter-undertowを追加する必要があります。
解説: Spring Bootのオートコンフィギュレーションはクラスパスにあるサーバー実装を自動検出します。単にUndertowを追加するだけでは、2つのサーバー実装が競合します。Tomcatを明示的にexclusionで除外してからUndertowを追加する必要があります。
Q5. server.tomcat.threads.maxとserver.tomcat.max-connectionsの違いは?
答え: threads.maxはリクエストを実際に処理するスレッドの最大数であり、max-connectionsは同時に維持できるTCP接続の最大数です。
解説: HTTP/1.1のKeep-Aliveにより、1つのTCP接続で複数のリクエストを順次処理できます。そのため、max-connectionsは通常threads.maxよりはるかに大きく設定します。例えば200スレッド・8192接続の設定では、8192のTCP接続を維持しながら、そのうち最大200を同時に処理できます。accept-countはすべての接続が使用中の場合に追加で待機できるリクエスト数です。