이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- 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이 필요한 이유는 무엇인가?
- 새 인스턴스가 준비된 뒤 트래픽을 받고, 종료 중 인스턴스가 새 요청을 받지 않게 해 배포 중 요청 실패를 줄이기 위해서다.