5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Spring Boot 2.3.0 M3のGraceful Shutdownを試してみる

Last updated at Posted at 2020-04-24

はじめに

Spring Bootの次期リリースである2.3.0ではKubernetes関連の機能追加が行われているようです。
今回はSpring Boot 2.3.0 M3で追加された Graceful Shutdown 機能を試してみました。
2.3.0の正式リリース時には挙動が変わっている可能性もあるので参考程度にどうぞ。

Graceful Shutdown とは

停止要求が行われた時点で処理中のリクエストがあった場合でも、猶予期間(Grace Period)まで完了を待機することでアプリケーションを安全に停止する仕組みです。

たとえば、下記のような処理があったとして

public void update() {

    updateSystemA();

    updateSystemB();

    updateSystemC();
}

Aの更新直後に処理が中断されてしまった場合、B・Cへの更新は行われず不整合が発生してしまいます。
Graceful Shutdownでは猶予時間の範囲内でB・Cへの更新も待って停止されるため、このような不整合を回避できます。

(ただし通常 Graceful Shutdown が働くのはあくまでも正常な停止要求が来た場合であり、Ctrl+CやOS自体の強制終了などでは処理続行できず普通に打ち切られます)

Spring Boot 2.3.0 で追加された Graceful Shutdown 機能

server.shutdown.grace-period プロパティが追加されており、このプロパティで猶予期間を設定するだけです。
下記の例では秒(s)単位で指定していますが、単位を指定しなかった場合はミリ秒での指定になるようです。
 ※ 2.3.0 の正式リリースではプロパティ名が変わっていました。
  ・server.shutdown=graceful
  ・spring.lifecycle.timeout-per-shutdown-phase=30s
  機能自体に変更はなさそうでした。

server.shutdown.grace-period=30s

たとえば、下記のような25秒後に"OK"を返すだけのAPIが Kubernetes 上で動いていたとします。

TestController.java
@RestController
public class TestController {

    @GetMapping("/")
    public ResponseEntity<String> doTest() throws Exception {

        Thread.sleep(25_000L);

        return new ResponseEntity<>("OK", HttpStatus.OK);
    }

}

猶予期間を設定しなかった場合、リクエストの処理中に Pod の停止要求を行うと Spring Boot アプリケーションは実行途中で停止してしまい 502 Bad Gateway504 Gateway Time-out が返ってきました。

>curl http://192.168.99.100/
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>openresty/1.15.8.2</center>
</body>
</html>

一方、猶予期間を適切に設定していれば、リクエスト処理中に Pod の停止要求を行っても処理中のリクエストは中断されずに結果が返るまで待機してくれることが確認できました。

>curl http://192.168.99.100/
OK

猶予期間を設定した場合でも、実行中の処理がない状態であれば待機はせずに停止してくれるようでした。

おまけ

Spring Boot アプリケーションのプロパティは application.properties (application.yaml) ファイルで設定するのが一般的ですが 環境変数でも設定できます。(詳細は Spring Boot Features#Externalized Configuration 参照)

猶予期間は Kubernetes側でも調整が必要(terminationGracePeriodSeconds:デフォルト 30秒) になるため、下記のように設定を deployment.yaml にまとめておくとやりやすいかもしれません。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shutdown
  namespace: test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: shutdown
  template:
    metadata:
      labels:
        app: shutdown
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: shutdown
        image: satrbeta/shutdown:latest
        env:
        - name: SERVER_SHUTDOWN_GRACE_PERIOD
          value: 60s
        ports:
        - containerPort: 8080

まとめ

Spring Boot 2.2.x まではこのような待機処理を自前で実装する必要があったのですが、Spring Boot 2.3.0ではほぼ自動でやってくれるようになり、だいぶ楽になっていました。

今回は組み込み tomcat 上での動作しか試していませんが、他の Webサーバでもだいたい同じ挙動になるのではないかと思います。
(2.3.0.M4時点のリファレンスによればUndertowのみリクエストを受け付けなくなるのではなく 503 Service Unavailable を返す仕様とのこと)

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?