처리 시간이 긴 요청 하나가 인스턴스에서 진행 중이다. 로드 밸런서가 대상을 등록 해제하는 동안 애플리케이션이 먼저 연결을 닫으면, 평소에는 성공하던 요청도 종료 구간에서 실패할 수 있다. CPU 사용률만 보면 이 요청이 실패한 순서를 설명하기 어렵다.

이 글의 질문은 인스턴스 시작·종료 중 요청 실패를 어떤 제어 구간에서 확인할까다. Elastic Beanstalk와 Application Load Balancer, EC2 Auto Scaling, Spring Boot를 사용하는 구성을 기준으로 각 시스템의 판단 시점을 나눠 본다.

Degraded가 종료 원인인지부터 구분한다

Beanstalk의 enhanced health는 HTTP 코드, 서버 로그, 시스템 지표와 배포 상태 등을 종합한다. 화면의 Degraded는 원인을 조사할 출발점이며, 그것만으로 Auto Scaling이 인스턴스를 종료했다고 결론 내리지 않는다. Enhanced health의 입력을 기준으로 상태를 해석한다.

먼저 같은 시간축에 네 기록을 놓는다.

기록확인할 사건
애플리케이션요청 시작·완료, 종료 신호, 프로세스 종료
ALB대상 health 변화, 등록 해제, 5xx 발생 구간
Beanstalk배포·설정 변경 이벤트와 health 원인
Auto Scalingscale-in 또는 비정상 대상 교체 활동과 사유

애플리케이션이 설계상 반환하는 4xx도 health 판단에 영향을 줄 수 있다. 상태 색상을 정상으로 바꾸는 설정부터 수정하면 실제 요청 실패와 표시 정책을 혼동한다. 500이 어느 요청에서 발생했고 종료 신호보다 앞인지 뒤인지 먼저 연결한다.

시작할 때 사용하는 세 시간은 역할이 다르다

새 인스턴스가 생성됐다고 바로 요청을 처리할 준비가 끝나는 것은 아니다. DB 연결, 설정 로딩, 캐시 초기화처럼 시작 중 필요한 작업이 있다면 다음 세 시간을 구분한다.

구간보호하거나 제어하는 대상
Health check grace period시작 직후 health 실패에 대한 Auto Scaling의 교체 판단
ALB health check·readiness새 요청을 보낼 수 있는 대상인지 판단
Instance warmup새 인스턴스의 지표를 동적 확장 판단에 반영하는 시점

grace period 동안에도 ALB의 health check는 진행된다. 유예 시간을 늘린다고 준비되지 않은 인스턴스가 요청을 정상 처리하는 것은 아니다. Auto Scaling의 시작 유예와 instance warmup은 목적이 다르다.

health 엔드포인트의 의존성도 선택해야 한다. 항상 200을 반환하면 필수 DB 연결이 없어도 요청을 받을 수 있다. 반대로 모든 외부 파트너의 상태까지 묶으면 일부 파트너 장애가 전체 인스턴스의 라우팅을 끊을 수 있다. 이 인스턴스가 맡은 요청을 처리하는 데 필수인 조건을 readiness로 정하고, 프로세스 생존 여부를 보는 liveness와 구분한다.

종료할 때는 요청 수락 중단이 먼저다

종료 흐름에서는 새 요청 수락을 멈추고, 이미 받은 요청이 끝날 시간을 확보하고, 마지막으로 프로세스를 종료한다. 시작과 종료의 제어 지점을 한 그림에 놓으면 서로 다른 대기 시간을 같은 설정으로 해결하려는 실수를 줄일 수 있다.

시작에서는 유예·readiness·warmup을 구분하고 종료에서는 drain 뒤 애플리케이션을 멈추는 흐름

ALB의 deregistration delay는 등록 해제 중인 대상으로 새 요청을 보내지 않고 기존 요청이 끝날 시간을 주는 장치다. 대상이 그 전에 연결을 종료하면 500 계열 응답이 발생할 수 있다. ALB 등록 해제 지연을 애플리케이션 종료 시간과 함께 확인한다.

Spring Boot에서는 graceful shutdown과 종료 단계의 제한 시간을 명시할 수 있다.

server:
  shutdown: graceful
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s
management:
  endpoint:
    health:
      probes:
        enabled: true

여기서 30초는 설명용 대기 예산이다. 이 설정은 Spring 종료 단계에서 기존 요청이 완료될 시간을 주지만, 인프라의 강제 종료 시각까지 자동 조정하지는 않는다. probe 활성화 역시 ALB의 검사 경로를 자동으로 바꾼다는 뜻은 아니다. 관리 포트가 별도라면 실제 서비스 포트의 요청 가능 상태를 충분히 대표하는지도 확인한다.

graceful shutdown의 기본값과 신규 요청 거절 방식은 Spring Boot 버전·웹 서버에 따라 확인해야 한다. 현재 공식 문서는 정상 종료 신호와 spring.lifecycle.timeout-per-shutdown-phase를 설명한다. Spring Boot graceful shutdown을 실제 사용 버전과 맞춰 읽는다.

시간 설정의 검증 단위는 진행 중인 요청이다

평상시 health 200 응답만 확인하면 종료 경합을 놓친다. 긴 요청을 보내는 동안 등록 해제와 종료를 진행하고 요청 ID별 시작·완료 시각, 마지막 신규 요청, 프로세스 종료를 모은다. 허용된 시간 안에서 이미 수락한 요청이 완료되는지 확인한다.

외부 결제가 포함된 요청이라면 연결 종료 후에도 결제가 승인됐을 수 있다. graceful shutdown은 이런 결과 불명을 모두 없애는 장치가 아니다. 요청 ID를 사용한 결과 조회와 대사 경로가 별도로 필요하다.

이 접근은 배포·스케일 인 구간에 오류가 집중되는 서비스에서 유효하다. 다음 변경을 고르기 전에 실제 종료 사유와 ALB 등록 해제 시각, 애플리케이션 종료 시각을 맞춘다. 새 요청을 끊는 지점과 기존 요청을 기다리는 시간이 확인돼야 어느 설정을 조정할지 결정할 수 있다.