[Spring Cloud] 에러없이 무중단 배포하기 (retry, graceful shutdown) - Eureka 등록해제 시간차이로 인한 익
안녕하세요~ 잭코딩입니다!
이번에는 운영환경에서 배포를 하다가 발생한 이슈에 대해 정리해보려고 합니다
Spring Cloud 환경에서 배포할 때, Eureka 등록해제 시간차이로 인한 Connection Exception이 발생했습니다
또한, 배포 시 해당 서비스를 강제 종료할 때 아직 작업중이던 테스크가 남아 있을 경우 익셉션이 발생했습니다
retry()와 graceful shutdown을 적용함으로써 이를 해결할 수 있었습니다
Exception
I/O error on POST request "서비스 URL" : nested exception is java.net.ConnectionException
서비스를 배포할 때 매번 10~20초정도 위와 같은 익셉션이 가끔 발생했습니다
처음에는 트래픽이 많은 서비스가 아니라 무시했지만, 서비스가 확장되면서 트래픽이 많아지면서 익셉션의 개수가 늘어났습니다
원인
서비스를 배포할 때, Eureka에 등록된 인스턴스가 등록 해제됩니다
하지만 이를 호출하고 있는 서비스는 Eureka 주소록에서 빠진지 모르고 계속 호출합니다
그로 인해 주소록이 갱신되기 전까지 최대 30초정도 ConnectionException이 발생했습니다
또한 배포되는 서비스에서도 간헐적으로 Exception이 발생했습니다
아직 처리중인 작업이 남았는데, 강제로 종료하면서 발생한 Exception 이었습니다
해결
1. 아직 처리중인 작업을 모두 끝내고 서비스를 종료하도록 graceful shutdown을 적용했습니다
server:
shutdown: graceful
Springboot 2.3 이상부터는 application.yml에 간단한 설정만으로 graceful shutdown을 적용할 수 있습니다
2. 현재 Eureka 주소록에서 빠진 서비스를 호출했을 경우, 다음 인스턴스를 호출하도록 retry() 기능을 적용했습니다
public Mono<SearchTemplateOutput> postByEurekaId(String uri, SearchTemplateInput body) {
return loadBalanced.build()
.post()
.uri(uri)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(body)
.retrieve()
.bodyToMono(SearchTemplateOutput.class)
.retry(2);
}
테스트
A -> B를 호출하게끔하여 부하테스트를 진행했습니다
B는 총 3개의 인스턴스가 유레카에 등록되어 있습니다
1분간 요청수만큼 부하테스트를 진행하면서 5초가 되었을 때, B 인스턴스 1개를 내렸습니다
Graceful & Retry 적용하지 않음
tpm(1분당 요청수) | Error rate (%) |
100 | 17% |
400 | 17.75% |
1000 | 17.4% |
2000 | 16.4% |
4000 | 30% |
대략 20-30초정도 Eureka 주소록에서 빠지는 시간동안 익셉션이 발생했습니다
Graceful & Retry 모두 적용
tpm(1분당 요청수) | Error rate (%) |
100 | 0% |
400 | 0% |
1000 | 0% |
2000 | 0% |
4000 | 0% |
1분당 최대 4000개의 요청까지 보냈을 때, Error rate는 0%로 안정적인 무중단 배포가 가능했습니다