Spring BootアプリケーションのTomcatハングによるFeignリクエストタイムアウトの追跡と解決

プロジェクト環境

<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
Dockerコンテナ環境で運用

問題の概要

アプリケーション内で非同期マルチスレッド処理が広く使用されています。各非同期タスク内ではデータベースクエリ、Redis参照、Feign呼び出し、RabbitMQの送受信が複雑に絡み合っています。シングルサーバー構成のため、短時間でTomcatがハング状態に陥りました。サービスは継続的に稼働していますが、すべてのHTTPリクエストが不通となり、ヘルスチェックページすら開けない状況が発生しました。コンテナ自体は正常に動作しています。

発生エラー

ネットワークリクエストすべてで以下の例外が発生しています:

feign.RetryableException: Read timed out executing POST

スタックトレースからSocketTimeoutExceptionが確認できます。Feignクライアントがターゲットサービスからの応答を長時間待機状態となっています。

調査ステップ

1. コンテナへのアクセス

docker exec -it コンテナID /bin/bash

2. ネットワークツールのインストール

apt-get update
apt-get install net-tools

3. TCP接続状態の調査

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

アプリケーションが停止していないにもかかわらず、接続数が増え続けている場合、接続の詰まりが発生している可能性があります。

4. プロセス確認

top

Javaプロセスの状態を確認します。

5. スレッドダンプの取得

# プロセスIDの確認
ps -ef | grep java

# スレッド情報の取得
jstack プロセスID

# ファイルに出力
jstack プロセスID > thread_dump.txt

6. ホスト側へのファイル転送

docker cp コンテナID:/path/to/thread_dump.txt ./

スレッド状態の分析

ダンプファイルを分析した結果、多数のCompletableFuture$Signaller.block状態スレッドが確認されました。以下はスレッド状態の解説です:

状態説明
NEW未起動のスレッド。ダンプには表示されない。
RUNNABLEVM内で実行中の状態。locksを獲得している場合あり。
BLOCKEDモニターロックを待ってブロックされている状態。
WAITING無期限に他のスレッドの操作を待機。park()、wait()、sleep()、join()などで停止。
TIMED_WATING時間制限付きの待機。wait(timeout)など。
TERMINATED終了したスレッド。

根本原因の特定

分析の結果、非同期処理で結果を取得する際にデッドロック

解決方法

非同期処理にタイムアウト設定を適用しました。具体的には、10秒間のタイムアウトを設定することで、無限待機を防止しました。

// 修正前のコード(問題あり)
CompletableFuture<Result> future = CompletableFuture.supplyAsync(() -> {
    return remoteService.call();
});
Result result = future.get(); // 無限待機

// 修正後のコード
CompletableFuture<Result> future = CompletableFuture.supplyAsync(() -> {
    return remoteService.call();
});
try {
    Result result = future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    // タイムアウト時の処理
    future.cancel(true);
    log.error("非同期処理がタイムアウトしました");
}

追加の改善ポイント

リソースプールの確認も重要です。以下のリソースが適切に設定されているか確認してください:

  • データベース接続池(HikariCPなど)
  • Redis接続池
  • スレッド池(ThreadPoolExecutor)
  • Feignクライアントのタイムアウト設定

参考資料

同様の問題遭遇時の参考URL:

  • https://blog.csdn.net/zcjluse/article/details/125974518
  • https://www.cnblogs.com/fengyege/p/16936291.html

タグ: spring-boot Tomcat OpenFeign thread-pool deadlock

6月6日 23:44 投稿