이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Rolling Deployment는 어떤 방식으로 실패 반경을 줄이는가?
  • 이전 버전과 새 버전이 동시에 떠 있는 동안 Spring 백엔드가 지켜야 할 호환성은 무엇인가?
  • Rolling 중 장애 신호가 보이면 어떤 순서로 멈추고 되돌려야 하는가?

개요

Rolling Deployment는 실행 중인 인스턴스를 한꺼번에 바꾸지 않고 조금씩 새 버전으로 교체하는 배포 방식이다.

서비스 전체를 멈추지 않고 새 버전을 반영할 수 있다는 장점이 있다.

하지만 배포 중에는 이전 버전과 새 버전이 동시에 사용자 요청을 처리한다.

따라서 Spring 백엔드에서는 코드뿐 아니라 DB schema, cache key, message format, 설정 값이 두 버전 모두에서 안전해야 한다.

동작 방식

Rolling은 보통 다음 순서로 진행된다.

old version 4개 실행
새 version 1개 시작
readiness 확인
트래픽 일부 수신
old version 1개 종료
다음 instance 반복

핵심은 새 인스턴스가 readiness를 통과하기 전 기존 인스턴스를 제거하지 않는 것이다.

남은 인스턴스가 트래픽을 감당할 capacity도 필요하다.

인스턴스 하나를 빼는 동안 CPU, memory, connection pool, DB connection 여유가 부족하면 rolling 자체가 latency 장애를 만들 수 있다.

Spring 준비 조건

Spring 애플리케이션은 graceful shutdown과 readiness를 구분해야 한다.

종료 중인 인스턴스가 새 요청을 받지 않고 진행 중 요청은 적당히 마무리해야 한다.

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

/actuator/health/readiness는 트래픽을 받아도 되는지 판단하는 신호다.

단순 process alive와는 다르다.

DB 연결, Redis 연결, 필수 외부 의존성 상태가 readiness에 어떻게 반영되는지 확인해야 한다.

배포 예시

VERSION=order-api:1.8.3-abc1234
./deploy.sh --strategy rolling --version "$VERSION" --batch-size 1
curl -fsS https://api.example.com/actuator/health/readiness
./smoke-test.sh --base-url https://api.example.com --suite core
./observe-window.sh --minutes 10 --watch error-rate,latency-p95

명령 자체보다 중요한 것은 batch size와 관측 창이다.

한 번에 너무 많은 인스턴스를 바꾸면 rolling의 장점인 작은 실패 반경이 사라진다.

버전 공존 문제

Rolling 중에는 old/new 버전이 같은 DB와 cache를 공유한다.

새 버전이 새 column만 읽도록 바뀌었는데 이전 버전은 그 column을 모르면 문제가 생길 수 있다.

새 버전이 message format을 바꾸면 이전 consumer가 실패할 수 있다.

cache key prefix를 바꾸면 일부 요청만 cache miss 또는 잘못된 cache hit를 겪을 수 있다.

feature flag는 이런 공존 구간을 줄이는 데 도움이 된다.

운영 체크리스트

  • 새 버전과 이전 버전이 같은 DB schema에서 동시에 동작하는가?
  • readiness가 실제 트래픽 수신 가능 상태를 반영하는가?
  • graceful shutdown이 설정되어 진행 중 요청을 끊지 않는가?
  • batch size와 관측 시간이 정해져 있는가?
  • 배포 중 남은 인스턴스가 트래픽을 감당할 여유가 있는가?
  • smoke test가 핵심 API와 인증 흐름을 포함하는가?
  • 중단 조건과 rollback target이 배포 전에 정해져 있는가?

장애 신호

  • 새 인스턴스는 시작됐지만 readiness가 계속 DOWN이다.
  • 특정 instance version에서만 5xx가 증가한다.
  • rolling batch가 진행될수록 latency p95가 천천히 상승한다.
  • 이전 버전과 새 버전이 서로 다른 cache key를 사용해 결과가 흔들린다.
  • DB migration 후 이전 버전 instance에서 SQL 오류가 난다.
  • 배포 중 active connection이 급증하고 종료 중 instance가 오래 남는다.

안전한 완화 조치

Rolling 중 이상 신호가 보이면 다음 batch 진행을 멈춘다.

이미 바뀐 인스턴스 비율을 확인하고, 새 버전만 빼도 되는지 판단한다.

DB migration이 아직 호환 범위라면 이전 artifact로 되돌리는 것이 안전할 수 있다.

DB 변경이 이미 이전 버전을 깨는 상태라면 단순 rollback보다 forward fix가 더 안전할 수 있다.

트래픽을 받는 인스턴스와 version 목록을 먼저 고정한 뒤 조치한다.

인프라 담당자와 공유할 자료

배포 전략: rolling
service: order-api
version: 1.8.3-abc1234
진행 상태: 2/6 instance new version
증상: new version instance에서 /api/orders 500 증가
readiness: new version UP, smoke test order-create 실패
DB 변경: V52 nullable column 추가, backward compatible
요청: 다음 batch 중단, new version instance를 previous version으로 교체

Rolling 장애 공유에서는 전체 서비스가 아니라 버전별 instance 상태와 배포 진행률을 같이 전달해야 한다.

실전 팁

  • Rolling은 old/new version 공존을 전제로 설계한다.
  • batch size는 장애 반경과 배포 시간을 함께 고려해 정한다.
  • readiness와 smoke test를 통과하지 못하면 다음 batch로 가지 않는다.
  • DB migration은 expand-and-contract 방식이 rolling에 잘 맞는다.
  • 배포 이벤트와 metric 그래프 시간을 맞춰 기록한다.

위험 신호!

  • 이전 버전 호환성 확인 없이 schema를 삭제한다.
  • readiness가 UP이면 핵심 API도 정상이라고 가정한다.
  • latency가 상승하는데 batch를 계속 진행한다.
  • 배포 중 어떤 instance가 어떤 version인지 모른다.
  • rollback 전에 DB migration 적용 여부를 확인하지 않는다.

확인 질문

확인 질문

  • Rolling에서 이전 버전과 새 버전의 공존이 중요한 이유는 무엇인가?
    • 배포 중 두 버전이 동시에 사용자 요청을 처리하므로 DB, cache, message, API contract가 양쪽에서 모두 안전해야 하기 때문이다.
  • Rolling 중 5xx가 늘면 첫 조치는 무엇인가?
    • 다음 batch 진행을 멈추고 version별 instance 상태, error rate, readiness, smoke test 결과를 확인하는 것이다.
  • readiness와 graceful shutdown이 필요한 이유는 무엇인가?
    • 새 인스턴스가 준비된 뒤 트래픽을 받고, 종료 중 인스턴스가 새 요청을 받지 않게 해 배포 중 요청 실패를 줄이기 위해서다.

참고 문서