본문 바로가기
Tech/Spring

SpringBoot를 우아하게(?) 종료시켜보자

반응형

Graceful? 이 뭐지..?

  • 말 그대로 "우아한", "그레이스하게"...
  • 뒤에 shutdown을 붙여보면 어플리케이션을 우아하게.. 셧다운 시키겠다는 뜻 같다..(네이밍 기원은 모르겟습니다)
  • 왜 필요할까..?

등장 배경

  • 일반적으로 리눅스 OS에 띄워진 어플리케이션을 종료시킬때는 kill 명령어를 이용하여 진행하게 됩니다.
  • 옵션
    • -9 (SIGKILL): 바로 죽임, OS에 즉시 프로세스를 죽이라고 요청
    • -15 (SIGTERM) : 소프트웨어 종료 시그널 프로세스에 -15를 보내는 역할, 동작 방법은 프로세스 자체에 달림
  • 서비스를 종료시킬때 SIGKILL 옵션을 이용하면 진행되고있는 요청을 끝까지 처리하지 않고 OS가 프로세스를 강제로 종료시킵니다.
    • 이러한 방식은 중요한 로직 혹은 I/O 시간이 길어 수행되고 있던 로직을 중단 시키게 되고, 경우에 따라 큰 문제가 될 수도 있습니다.
  • 따라서 SIGTERM 옵션, 즉 프로세스에 종료하라는 시그널을 보내 Graceful하게~ 진행하던 일을 처리시킨 후 종료하는 방식이 필요했습니다.

문제 상황 예시 #1

  • SpringBoot로 띄워진 어플리케이션
  • kill -9 {application pid}를 이용해 어플리케이션을 종료
@GetMapping("/sleep")
    public ResponseEntity<Void> longSleepHandler() {
        try {
            Thread.sleep(20 * 1000L); // I/O가 긴 작업
            log.info("sleep END!!!!!!!!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return ResponseEntity.ok().build();
    }
  • 위와 같은 로직이 있다고 가정할 때 동작 중 어플리케이션을 종료하게되면 바로 프로세스가 종료되는 것을 확인할 수 있습니다.


문제 상황 예시 #2

  • 이번에는 kill -15 {application pid}를 이용해 어플리케이션을 종료

  • 의도했던 내용은 중간에 kill -15 명령어를 보내더라도 이미 처리중인 요청에 대해 처리가 끝난 후 로그가 찍히길 바랬지만 그렇지 않다.
  • SpringBoot의 기본 shutdown 옵션과 연관이 있다.
    • SpringBoot 기본 shutdown 옵션은 immediate ( SpringBoot 2.3 기준 )
    • 즉 SIGTERM 명령어를 받게되면 그 즉시 생성되어있는 모든 Thread에 인터럽트 요청을 보내 종료시킨다.

해결 방안

  • SpringBoot는 2.3 버전 이후로 graceful shutdown을 지원한다!!!
  • 문제 상황 예시 #2번에서 이미 느낌이 오셨겠지만, shutdown 옵션을 graceful로 변경해주면 정해진 시간 내 까지 프로세스가 종료되길 기다려준다.
server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s # default 30초
  • 기본 timeout 시간은 30초로 설정되어있고, 상황에 따라 너무 길지 않게 설정해주면 된다.

Spring 혹은 Spring 2.3보다 낮은 버전은.. 방법이 없을까?

  • 단지 SpringBoot 2.3부터 kill -SIGTERM 신호가 왔을 때의 이벤트를 구현해놓은 것이기 때문에 직접 만들면 된다.
  • ApplicationListener<ContextClosedEvent>를 상속 받아 직접 Tomcat shutdown을 구현하면 된다.
  • 관련 내용은 정말 잘 설명해두신 포스트가 있어서 참고자료로 남겨놓겠습니다.
728x90
반응형