티스토리 뷰
최근에 클라이언트 요청이 처리되는 와중에 어플리케이션이 종료될 경우, 그 요청은 어떻게 되는지에 대한 문의가 와서 겸사겸사 graceful shutdown
에 대해서 포스팅을 해보려고 한다.
0. graceful shutdown이란?
서론에서 graceful shutdown
이라는 표현을 했는데, 이에 대해서 간략히 설명하자면 다음과 같다.
graceful shutdown
이란 질서정연한 방식으로 어플리케이션을 종료하는 절차를 뜻한다.- 다시 말해 어플리케이션이 완전히 종료되기 전에 진행 중인 모든 작업을 완료하고, 리소스는 적절하게 해제하고, 데이터 무결성이 유지되도록 필요한 조치를 취하는 행위를 뜻한다.
즉, “클라이언트의 요청을 처리하는 와중에 어플리케이션을 종료시켰을 때 요청을 잘 처리하고 종료하는가?”를 다른 말로 표현하자면 “어플리케이션이 graceful shutdown을 지원하는가?”가 되는 것이다.
1. graceful shutdown 활성화
Spring Boot 2.3
부터 graceful shutdown
을 지원하고, 이를 활성화하기 위해서는 아래에 해당하는 프로퍼티를 설정한다.
참고로 해당 프로퍼티를 설정하지 않을 경우 기본 값으로 immediate
가 세팅되는데, 이는 요청 여부와 상관 없이 서버를 즉시 종료한다는 뜻이다.
server:
shutdown: graceful
2. 샘플 프로젝트 준비
요청에 대한 처리 시간을 조정하며 테스트를 진행할 예정이기 때문에 Controller
와 graceful shutdown
와 관련된 프로퍼티를 위해 application.yml
파일을 추가하였다.
Controller
Controller
는 아래와 같이 작성했는데, graceful shutdown
이 잘 되는지 확인하기 위해 요청을 처리하는데 드는 시간을 일부러 늘렸다.
@Slf4j
@RestController
public class SampleController {
@GetMapping("/foo")
public String foo() throws InterruptedException {
log.info("get request");
bar();
return "success";
}
private void bar() throws InterruptedException {
Thread.sleep(60000);
log.info("end bar method");
}
}
3. graceful shutdown 활성화 전
graceful shutdown
을 활성화 하기 전에 테스트를 수행한 결과는 다음과 같다.
정상 테스트
요청 처리에 드는 시간을 10초로 변경하여 테스트를 수행했고 어플리케이션 프로세스를 죽이지 않았으므로, 요청을 보내고 10초 뒤에 응답을 받았다는걸 알 수 있다.
요청 처리 중 process kill
요청을 처리하는 와중에 프로세스를 죽였을 경우, 응답을 받기 전에 어플리케이션이 종료되어버린다. bar 메소드와 관련된 로그도 남지 않았다.
4. graceful shutdown 활성화 후
정상 테스트
프로세스를 죽이지 않을 경우에는 graceful shutdown
을 활성화하기 전과 동일하게 요청/응답이 잘 이뤄짐을 알 수 있다.
요청 처리 중 process kill
요청을 보낸 뒤에 프로세스를 죽일 경우, graceful shutdown
이 시작되었다는 로그와 함께 요청이 정상처리 되고 graceful shutdown
이 완료되었다는 로그를 남긴다.
graceful shutdown 중 요청
graceful shutdown
이 되고 있을 때 요청이 들어오면 어떻게 될까? 정답은 서버에서 요청을 받아주지 않는다.
5. shutdown timeout
timeout
graceful shutdown
을 활성화했다고 요청을 처리하기 위해 무한히 기다리는 것은 아니다.
아래의 예시는 요청을 처리하는데 60초의 시간이 들 경우에 graceful shutdown
이 어떻게 되는지를 살펴본 결과인데, 하나 이상의 요청이 남아있는 와중에 graceful shutdown
이 중단되었다는 로그와 함께 프로세스가 종료되고 정상적으로 응답이 나가지 않았다는 걸 알 수 있다.
timeout 시간 조정
graceful shutdown
에 대한 타임아웃은 아래의 프로퍼티로 조절할 수 있는데 기본값은 30초이다.
즉 해당 프로퍼티를 따로 설정하지 않았을 때, 요청이 들어오고 30초 내에 처리가 되지 않을 경우 제대로 요청이 처리가 되지 않은채로 프로세스가 종료된다. → 바로 위의 에러 로그를 보면 타임아웃에 대한 로그도 볼 수 있다
spring:
lifecycle:
timeout-per-shutdown-phase: 2m
타임아웃 시간을 2분으로 늘릴 경우, 요청이 정상적으로 처리되는 것을 확인할 수 있다.
물론 클라이언트 요청이 없을 경우, 요청에 대한 대기 시간은 제외하고 어플리케이션이 종료 처리된다.
참고) 프로세스 종료 방식
프로세스를 종료하는 방식에는 여러가지가 있는데, graceful shutdown
과 관련된 내용만 간단히 정리하자면 다음과 같다.
SIGKILL(kill -9)
SIGKILL
은 프로세스를 즉시 종료시킨다. 그래서 graceful shutdown
이 동작하지 않는다.
SIGTERM(kill -15)
SIGKILL
과 달리 SIGTERM
은 graceful하게 프로세스를 죽이는 방법이다. graceful shutdown
이 동작하게 하려면 SIGTERM
방식으로 프로세스를 죽여야 한다. 위의 예시에서는 모두 SIGTERM
으로 프로세스를 종료했다.
샘플 코드 🤓
참고 🙇♂️
'스프링' 카테고리의 다른 글
[Spring] 어플리케이션을 종료할 때 특정 작업 수행하기(feat. ApplicationListener) (0) | 2023.11.05 |
---|---|
[Spring] @SpringBootApplication가 없는 상황에서 @SpringBootTest 수행하기 (0) | 2023.08.05 |
[Spring] 초기 데이터 로딩(data.sql, schema.sql) (0) | 2023.06.02 |
[Spring] 주기적인 작업 구현하기(feat. Scheduling Tasks) (0) | 2023.04.01 |
[Spring Integration] 소개 및 튜토리얼 (0) | 2023.03.18 |