デプロイメント、ロールバック、スケールイン、再起動の際、シャットダウン中のマイクロサービスインスタンスは、まだシャットダウンを検出できていないコンシューマーから引き続きリクエストを受信する可能性があります。これにより、リクエストエラーおよびトラフィック損失が発生します。Microservices Engine (MSE) のマイクロサービスガバナンスにおけるグレースフルシャットダウン機能は、この問題を解決するために、インスタンス停止前に進行中のリクエストを処理し終える(ドレイン)とともに、コンシューマーに対して事前に通知します。
仕組み
典型的なマイクロサービスアーキテクチャでは、プロバイダーインスタンス(Provider A)が Microservices Registry に登録され、コンシューマーインスタンス(Consumer B)がその存在を検出し、呼び出せるようになります。グレースフルシャットダウンが有効でない場合、Provider A のシャットダウン時に競合状態が発生します:
Provider A がシャットダウンを開始し、Microservices Registry にシャットダウンイベントが通知されます。
Consumer B はプロバイダーリストのキャッシュコピーを保持しており、変更を即座に検出できません。
Consumer B は引き続き Provider A へリクエストを送信します。
Provider A は既に利用不可であるため、リクエストが失敗します。
グレースフルシャットダウンは、以下の 2 段階プロセスによりこのギャップを解消します:
ドレイン段階:Provider A がシャットダウンコマンドを受信後、進行中のリクエストの処理を継続しますが、各応答に特別なタグを付与します。Consumer B がタグ付き応答を受信すると、Microservices Registry からプロバイダーリストをリフレッシュし、Provider A への新規リクエストのルーティングを停止します。
待機段階:Provider A は残りの進行中のリクエストが完了するまで待機し、その後にシャットダウンします。
グレースフルシャットダウンは、アプリケーションに対して MSE マイクロサービスガバナンスが有効化された時点で自動的に有効になります。基本機能については、手動による設定は不要です。また、MSE のグレースフル起動およびグレースフルシャットダウン機能は、アプリケーションが正常にグレースフルシャットダウンしたかどうかを確認できる可観測性も提供します。オプションの能動的通知機能を利用する場合は、「能動的通知の有効化」をご参照ください。
Kubernetes における実装詳細
Kubernetes(ACK)クラスターでは、MSE は Pod に lifecycle.preStop フックを注入することでグレースフルシャットダウンを実装します。このフックは、kubelet がアプリケーションコンテナに SIGTERM を送信する直前に実行されるため、MSE がインスタンスの登録解除およびトラフィックのドレインを行う時間を確保できます。
preStop フックの注入
注入動作は、ビジネスコンテナにカスタムの preStop フックが既に定義されているか否かによって異なります:
| シナリオ | 注入動作 |
|---|---|
カスタム preStop フックがない場合 | MSE は、ビジネスコンテナに preStop フックを直接注入します。 |
カスタム preStop フックが存在する場合 | MSE は、gracefulshutdown という名前のサイドカーコンテナを、独自の preStop フックとともに注入します。サイドカーはビジネスコンテナとネットワーク名前空間を共有するため、その preStop フックもビジネスコンテナのグレースフルシャットダウンをトリガーできます。 |
カスタムの preStop フックが Microservices Registry からのアプリケーション登録解除のみを実行する場合、そのフックは完全に削除し、代わりに MSE が注入するフックを利用してください。
サイドカーコンテナのリソース使用量
gracefulshutdown サイドカーコンテナは最小限のリソースを使用します:CPU コア 0.05 個およびメモリ 50 MiB。
terminationGracePeriodSeconds の設定
preStop フックの実行時間は、Pod の terminationGracePeriodSeconds の予算に含まれます。デフォルト値の 30 秒では、多くの場合不十分です。以下に時間予算の内訳を示します:
| 段階 | 所要時間 | 説明 |
|---|---|---|
preStop フック | 約 30 秒 | MSE がインスタンスの登録を解除し、トラフィックをドレインします |
| アプリケーションのシャットダウンフック | 可変 | アプリケーションがリソースおよび接続を解放します |
| SIGKILL(強制終了) | 0 秒 | 合計時間が terminationGracePeriodSeconds |
preStop フックおよびアプリケーションのシャットダウンフックの合計実行時間が terminationGracePeriodSeconds を超過すると、kubelet は SIGKILL を送信し、アプリケーションが強制終了します。その結果、リソースが適切に解放されない可能性があります。
Pod の仕様(spec)で terminationGracePeriodSeconds を少なくとも 90 に設定してください:
apiVersion: v1
kind: Pod
spec:
terminationGracePeriodSeconds: 90
containers:
- name: your-app
# ...ビジネスコンテナにカスタムの preStop フックが定義されており、サイドカー方式が採用されている場合、カスタム preStop フック内で少なくとも 30 秒の sleep を指定してください。これにより、サイドカーの preStop フックがグレースフルシャットダウン処理を完了するのに十分な時間が確保されます。
グレースフルシャットダウンの有効化
ACK クラスター
特に操作は必要ありません。Container Service for Kubernetes (ACK) クラスター内のアプリケーションに対して MSE マイクロサービスガバナンスが有効化された時点で、グレースフルシャットダウンは自動的に有効になります。
ECS インスタンス
アプリケーションのシャットダウンスクリプトの先頭に、以下のコマンドを追加します:
curl http://127.0.0.1:54199/offline 2>/tmp/null; sleep 30;このコマンドは、MSE に対しグレースフルシャットダウン処理の開始を通知し、進行中のリクエストがドレインされるまで 30 秒間待機します。
グレースフルシャットダウンの検証
グレースフルシャットダウンが有効化・トリガーされた後は、アプリケーションガバナンスページでトラフィックのドレインが正しく行われていることを確認します。
MSE コンソール にログインし、上部ナビゲーションバーからリージョンを選択します。
左側ナビゲーションウィンドウで、マイクロサービスガバナンス > アプリケーションガバナンス を選択します。対象アプリケーションのリソースカードをクリックします。
アプリケーション詳細ページの左側ナビゲーションウィンドウで、トラフィック管理 をクリックし、その後 グレースフル起動/シャットダウン タブをクリックします。
起動およびシャットダウンの概要 サブタブで、対象アプリケーションインスタンスを検索してクリックします。右側ペインにシャットダウンイベントのタイムラインおよび QPS グラフが表示されます。
正常なグレースフルシャットダウンでは、インスタンスが停止する前に QPS がゼロまで低下します。シャットダウン処理が完了した後は、インスタンスに一切のトラフィックが到達しません。

シャットダウンイベント後に QPS がゼロまで低下しない場合、Microservices Registry をバイパスするローカル呼び出し等の非マイクロサービス呼び出しが存在していないか確認してください。
シャットダウンイベントは、MSE エージェントのバージョンが 4.2.0 より新しい場合にのみ報告されます。シャットダウンイベントが表示されない場合は、エージェントをアップグレードしてください。
能動的通知の有効化
能動的通知は、デフォルトで無効化されている高度なグレースフルシャットダウン機能です。この機能は、Spring Cloud アプリケーション特有の課題に対処します:プロバイダーが登録解除された後でも、Spring Cloud コンシューマーは内部キャッシュの動作により、引き続きプロバイダーへリクエストをルーティングし続けることがあります。能動的通知が有効化されている場合、プロバイダーはシャットダウン中にコンシューマーへ明示的に通知し、コンシューマーは即座にリクエスト送信を停止します。
能動的通知を利用するタイミング
以下の条件をすべて満たす場合に、能動的通知を利用してください:
アプリケーションが Spring Cloud フレームワークを採用している かつ
基本的なグレースフルシャットダウンが有効化されているにもかかわらず、プロバイダーのシャットダウン時にコンシューマー呼び出しエラーが発生している
それ以外のほとんどのシナリオでは、デフォルトのグレースフルシャットダウン動作で十分です。
前提条件
開始する前に、以下の条件を満たしていることを確認してください:
マイクロサービスガバナンスが有効化されていること。詳細については、「マイクロサービスガバナンスの有効化」をご参照ください。
ACK クラスター内のアプリケーションに対してマイクロサービスガバナンスが有効化されていること。詳細については、「ACK クラスター内のマイクロサービスアプリケーションに対するマイクロサービスガバナンスの有効化」をご参照ください。
コンソールでの能動的通知の有効化
MSE コンソール にログインし、上部ナビゲーションバーからリージョンを選択します。
左側ナビゲーションウィンドウで、マイクロサービスガバナンス > アプリケーションガバナンス を選択します。対象アプリケーションのリソースカードをクリックします。
アプリケーション詳細ページの左側ナビゲーションウィンドウで、トラフィック管理 をクリックし、その後 グレースフル起動/シャットダウン タブをクリックします。
設定項目 セクションで、編集 をクリックします。[グレースフル起動およびシャットダウンの設定] パネルで、グレースフルシャットダウン ブロックを展開し、能動的通知 スイッチをオンにして、OK をクリックします。
制限事項
グレースフルシャットダウン
Kubernetes 環境では、グレースフルシャットダウンは preStop フックに基づいて実装されています。そのため、Pod が正常に停止する場合(以下のシナリオを含む)にのみサポートされます:
スケールイン
再起動
ローリングアップグレード
OOM kill などの異常な停止時には、グレースフルシャットダウンは適用されません。
能動的通知
マイクロサービスガバナンスは、以下のアプリケーションに対するグレースフルシャットダウンをサポートしていません:
Java 以外のアプリケーション
WebFlux および Spring MVC を使用していないアプリケーション
コンシューマーがマイクロサービスアプリケーションでないプロバイダー アプリケーション
コンシューマーまたはプロバイダーのいずれかでマイクロサービスガバナンスが無効化されているアプリケーション