Skip to content
Published on

배포 전략 완전 가이드: 되돌릴 수 있는 것과 없는 것

공유하기
Authors

들어가며

배포 전략을 다루는 글은 대개 도구 카탈로그로 끝납니다. 이 블로그에도 이미 그런 글이 있습니다. Feature Flag와 Progressive Delivery 완전 해부는 다크 런치, 카나리 롤아웃, 플래그 관리 도구를 기법별로 정리했고, CI/CD와 GitOps를 다룬 글들은 파이프라인을 어떻게 구성하는지 설명합니다. 그 글들을 다시 쓸 생각은 없습니다.

이 글은 같은 재료를 오직 하나의 축으로 다시 정렬합니다: 지금 이 변경은 아직 되돌릴 수 있는가, 아니면 이미 되돌릴 수 없는 지점을 지났는가. 이 질문에 답할 수 있으면 전략 선택은 대체로 자동으로 정해집니다. 답할 수 없으면 어떤 도구를 써도 사고는 같은 방식으로 납니다.

그래서 이 글의 무게중심은 도구가 아니라 데이터입니다. 무중단 배포를 자랑하던 팀이 실제로 무너지는 지점은 거의 언제나 스키마 변경과 데이터 마이그레이션이고, 그 부분은 롤아웃 도구가 전혀 도와주지 않기 때문입니다.


1. 배포와 릴리스를 분리하기

두 단어를 같은 뜻으로 쓰는 조직이 아직 많습니다. 하지만 이 둘을 분리하지 못하면 되돌릴 수 있는 선택지가 하나밖에 남지 않습니다.

  • 배포(deployment): 새 코드가 프로덕션 환경에 존재하게 되는 사건입니다. 프로세스가 떠 있고 헬스 체크를 통과하지만, 아직 아무도 그 경로를 지나가지 않을 수 있습니다.
  • 릴리스(release): 실제 사용자 트래픽이 그 코드 경로를 타기 시작하는 사건입니다. 트래픽 비율, 플래그 스위치, 라우팅 규칙이 결정합니다.

두 사건을 한 덩어리로 묶으면 되돌리는 단위도 하나뿐입니다. 바로 배포 아티팩트입니다. 문제가 생기면 파이프라인을 다시 돌려 이전 이미지를 배포해야 하고, 그 시간은 대개 분 단위입니다. 반대로 분리해 두면 되돌리는 단위가 트래픽 비율이나 플래그 값이 되고, 이것은 초 단위입니다.

1-1. 분리의 비용

분리는 공짜가 아닙니다. 릴리스를 뒤로 미룬다는 말은 새 경로와 옛 경로가 한 바이너리 안에 공존한다는 뜻입니다. 코드가 늘고, 테스트해야 할 조합이 늘고, 어느 경로가 실제로 실행 중인지 헷갈리기 시작합니다. 6절에서 이 비용을 따로 다룹니다.

1-2. 가장 흔한 실패

코드는 분리했는데 스키마는 분리하지 않는 경우입니다. 애플리케이션은 플래그 하나로 되돌릴 수 있지만, 이미 실행된 ALTER TABLE은 플래그가 없습니다. 배포 파이프라인이 아무리 정교해도 이 지점에서 가역성이 끊깁니다.


2. 되돌릴 수 있는 변경과 없는 변경 — 판별 체크리스트

배포 계획을 세우기 전에 다음 다섯 질문에 먼저 답합니다. 답이 애매하면 그 변경은 비가역 쪽으로 분류하는 편이 안전합니다.

Q1. 이 변경의 부수효과가 프로세스 밖에 남는가?
    (DB 쓰기, 외부 API 호출, 메시지 발행, 메일/푸시 발송, 결제 승인)
Q2. 이전 버전 코드가 새 버전이 쓴 데이터를 그대로 읽을 수 있는가?
Q3. 되돌리는 데 걸리는 시간이 문제를 감지하는 데 걸리는 시간보다 짧은가?
Q4. 되돌리는 행위 자체가 새로운 상태 변화를 만드는가?
Q5. 외부에 계약을 공개했는가? (공개 API, 웹훅 페이로드, 이벤트 스키마)
    소비자 수를 모른다면 그 변경은 이미 비가역이다.

2-1. 세 단계 분류

등급정의롤백 수단
즉시 가역프로세스 밖에 남는 흔적이 없다UI 문구, 정렬 순서, 읽기 전용 화면, 캐시 TTL 조정플래그 또는 트래픽
조건부 가역흔적이 남지만 이전 버전이 읽을 수 있다새 컬럼에 쓰기 시작, 새 이벤트 필드 추가, 인덱스 추가배포 되돌리기
비가역되돌려도 이미 발생한 결과가 남는다컬럼 삭제, 외부 결제/메일 발송, 공개 API 필드 제거보상 절차만 존재

2-2. 실무에서 오분류가 잦은 것들

  • 인덱스 생성은 대개 조건부 가역입니다. 삭제로 되돌릴 수 있지만, 생성 도중 발생한 잠금과 I/O 급증은 되돌릴 수 없습니다. 되돌릴 수 있는 것은 결과이지 그 과정에서 이미 발생한 장애가 아닙니다.
  • 메시지 발행은 거의 언제나 비가역입니다. 컨슈머가 이미 받았다면 발행 취소라는 개념은 존재하지 않습니다.
  • 읽기 전용으로 보이는 변경도 캐시를 오염시키면 비가역에 가깝습니다. 잘못된 값이 긴 TTL로 들어가면 코드를 되돌려도 사용자는 한동안 옛 결과를 봅니다.

가역성은 코드의 속성이 아니라 코드와 데이터와 시간의 조합입니다. 같은 코드 변경이라도 아직 아무도 쓰지 않았으면 가역이고, 백만 건을 쓴 뒤에는 비가역입니다.


3. 전략 카탈로그와 각각이 요구하는 전제

각 전략은 "좋다/나쁘다"가 아니라 각자 다른 전제를 요구합니다. 전제를 만족하지 못한 채 쓰면 이름만 그럴듯한 위험한 배포가 됩니다.

재생성    [v1 v1 v1] → (전면 중단) → [v2 v2 v2]    롤백 = 재배포, 중단이 다시 발생
롤링      [v1 v1 v1] → [v2 v1 v1] → [v2 v2 v1] …  롤백 = 역방향 롤링, 같은 시간 소요
블루그린  [blue v1] 과 [green v2] 병존 → 라우터 전환  롤백 = 라우터 되돌리기, 초 단위
카나리    [v1 95%] + [v2 5%] → 비율 상향           롤백 = 비율 0으로, 초 단위
섀도      [v1 100%] + [v2 사본 트래픽, 응답 폐기]   롤백 = 미러링 중단, 사용자 영향 없음
  • 재생성(recreate): 전제는 계획된 중단 시간이 허용된다는 것입니다. 두 버전이 절대 공존할 수 없는 경우, 예를 들어 배타적 잠금이 필요한 일괄 마이그레이션에는 이 방식이 오히려 정직합니다. 단점은 롤백도 중단을 동반한다는 점입니다.
  • 롤링: 전제는 두 버전이 동시에 살아 있어도 안전하다는 것입니다. 여기에는 스키마 양방향 호환, 세션 비의존성, 메시지 포맷 호환이 모두 포함됩니다. 이 전제를 검증하지 않고 롤링을 쓰는 것이 가장 흔한 사고 원인입니다.
  • 블루그린: 전제는 프로덕션 규모의 환경을 두 벌 유지할 자원과, 상태를 두 환경이 공유해도 문제가 없다는 확인입니다. 컴퓨트는 복제하기 쉽지만 데이터베이스는 대개 공유합니다. 그래서 블루그린은 애플리케이션 롤백을 초 단위로 만들어 주지만 스키마 문제는 전혀 해결하지 않습니다.
  • 카나리: 전제는 관측입니다. 트래픽을 쪼갤 수 있고, 쪼갠 두 집단의 지표를 따로 볼 수 있어야 합니다. 4절에서 자세히 다룹니다.
  • 섀도(트래픽 미러링): 전제는 새 버전이 부수효과를 만들지 않도록 격리할 수 있다는 것입니다. 사본 트래픽이 실제로 결제를 일으키거나 메일을 보내면 섀도가 아니라 이중 처리입니다. 성능과 오류율 검증에는 훌륭하지만, 응답을 버리므로 정확성 검증에는 별도 비교 장치가 필요합니다.

3-1. 여기서 의견이 갈립니다

블루그린의 자원 비용과 카나리의 운영 복잡도 중 무엇이 더 비싼지는 팀마다 다르게 결론이 납니다. 블루그린을 지지하는 쪽은 전환이 원자적이고 롤백 절차가 단순하다는 점을 듭니다. 카나리를 지지하는 쪽은 블루그린이 전환 순간에 100%를 한꺼번에 노출하므로 실제로는 위험을 줄이지 않는다고 봅니다. 축은 세 개입니다. 인프라 비용, 관측 성숙도, 트래픽 규모입니다. 하루 요청이 수천 건인 서비스에서 5% 카나리는 통계적으로 의미가 없고, 이 경우 블루그린이 합리적입니다.

브랜치 전략에서도 같은 대립이 있습니다. 트렁크 기반 개발은 통합 간격을 줄여 배포 단위를 작게 만들지만 플래그 부채를 늘립니다. 장기 브랜치는 코드베이스를 깨끗하게 유지하지만 병합 시점에 큰 덩어리를 한 번에 릴리스하게 만듭니다. 어느 쪽이 낫다기보다 배포 단위 크기와 플래그 관리 비용을 맞바꾸는 선택입니다.


4. 카나리가 의미를 가지려면

Google SRE Workbook은 카나리를 "어떤 변경을 서비스에 부분적이고 시간이 제한된 형태로 배포하고 그것을 평가하는 것"으로 정의하고, 나머지 서버들을 대조군(control)이라고 부릅니다. 이 정의에서 실무 요건 네 가지가 그대로 따라 나옵니다.

4-1. 동시 대조군이어야 합니다

Workbook은 배포 전후를 비교하는 방식을 명시적으로 경계합니다. 이유는 시간이 관측 지표를 변화시키는 가장 큰 요인 중 하나이기 때문입니다. 오전 10시와 오전 11시는 트래픽 구성도 캐시 적중률도 다릅니다. 따라서 비교 대상은 "어제의 나"가 아니라 "지금 옆에서 돌고 있는 이전 버전"이어야 합니다.

4-2. 지표는 SLI에서 출발하고, 수를 제한합니다

Workbook은 지표가 "서비스의 문제를 나타낼 수 있어야" 하며 개수는 "많아야 열두 개 정도"로 유지하라고 권합니다. 그리고 지표는 우리가 카나리하는 변경에 명확히 귀속될 수 있어야 합니다. 전사 대시보드의 모든 그래프를 게이트로 걸면 무관한 지표의 잡음 때문에 배포가 계속 중단되고, 결국 사람들이 게이트를 무시하게 됩니다.

4-3. 규모와 기간이 대표성을 가져야 합니다

카나리는 "전체 배포를 대표할 만큼 충분히 크고 충분히 오래" 지속되어야 합니다. 동시에 기간은 릴리스 주기와 맞아야 합니다. Workbook의 표현대로, 매일 릴리스한다면 카나리 하나를 일주일 동안 돌릴 수는 없습니다.

여기서 자주 잊는 산수가 있습니다. 관측하려는 문제가 0.1% 확률로 발생하는데 카나리 구간에 요청이 200건만 들어왔다면 기대 발생 건수는 0.2건입니다. 아무 일도 일어나지 않은 것이 정상이므로, 이 카나리는 "통과"가 아니라 "관측되지 않음"으로 읽어야 합니다. 이 산수는 위 자료에 나오는 것이 아니라 이 글에서 덧붙이는 해석입니다.

4-4. 카나리가 팔고 있는 것은 에러 버짓입니다

Workbook의 핵심 논거는 단순합니다. 카나리 대상이 전체의 5%이고 그 안에서 오류율이 20%라면 전체 오류율은 1%에 그칩니다. 즉 카나리는 버그를 없애는 장치가 아니라 버그의 노출 면적을 줄이는 장치입니다. 이 관점에서 카나리 비율과 기간은 임의로 정하는 값이 아니라 감내할 수 있는 에러 버짓 소진량에서 역산해야 하는 값입니다. SLI/SLO/Error Budget 기반 신뢰성 엔지니어링SLO 에러 버짓 계산기가 이 계산을 도와줍니다.

4-5. 카나리가 잡지 못하는 것

Workbook은 한계도 분명히 적어 둡니다. 테스트 환경은 프로덕션과 100% 동일하지 않고, 공유된 실패 도메인이나 일부 상태 저장 상호작용은 전체 규모에 도달해야만 드러납니다. 커넥션 풀 고갈, 캐시 폭주, 하위 의존성 포화는 5%에서는 얌전하다가 100%에서 터집니다. 카나리 통과는 안전 증명이 아니라 명백한 실패의 부재입니다.


5. 스키마 변경 — 배포 전략을 가장 자주 무너뜨리는 것

여기가 이 글의 중심입니다. 롤링이든 블루그린이든 카나리든, 전제는 모두 "두 버전이 동시에 살아 있어도 안전하다"였습니다. 스키마 변경은 그 전제를 직접 깨뜨립니다.

5-1. 확장·이행·축소

Martin Fowler가 정리한 Parallel Change 패턴은 이 문제의 표준 해법입니다. Fowler는 확장 단계를 "인터페이스를 늘려 옛 버전과 새 버전을 모두 지원하게 만드는 것"으로, 이행 단계를 "옛 버전을 쓰던 모든 클라이언트를 새 버전으로 옮기는 것이며 점진적으로 할 수 있다"고 설명합니다. 그리고 모든 사용처가 옮겨간 뒤에야 축소 단계에서 옛 버전을 제거합니다. 이 패턴은 Joshua Kerievsky에게 귀속됩니다.

-- 1단계 확장(expand): nullable로 추가한다. 기본값을 함께 주면 구현에 따라
-- 테이블 전체 재작성과 긴 잠금이 발생할 수 있으므로 분리한다.
ALTER TABLE orders ADD COLUMN currency_code text;

-- 2단계 이행(migrate): 애플리케이션은 두 컬럼에 모두 쓰고, 읽기는 아직 옛 컬럼에서 한다.
-- 과거 행은 배치로 채운다. 한 번에 전부가 아니라 키 범위를 잘라 재개 가능하게.
UPDATE orders SET currency_code = 'KRW'
 WHERE currency_code IS NULL AND id BETWEEN 1 AND 10000;

-- 3단계 축소(contract): 모든 읽기가 새 컬럼으로 옮겨간 것을 확인한 뒤,
-- 며칠에서 몇 주 뒤 별도의 배포에서 제거한다.
ALTER TABLE orders DROP COLUMN currency;

5-2. 규칙 하나만 지킨다면

한 번의 배포에 두 단계를 함께 넣지 않습니다. 확장과 이행을 같은 배포에 넣으면 롤백했을 때 옛 코드가 새 데이터를 만나고, 이행과 축소를 같은 배포에 넣으면 롤백할 컬럼이 이미 사라져 있습니다. 각 단계 사이에는 최소한 한 번의 안정화 기간이 있어야 하고, 그 기간의 길이는 롤백을 검토할 수 있는 최대 시간이어야 합니다.

5-3. 특히 위험한 DDL 목록

  • NOT NULL 제약 추가: 기존 행을 모두 검사하므로 큰 테이블에서 장시간 잠금이 걸립니다. 먼저 애플리케이션에서 값을 채우고, 백필을 끝낸 뒤, 마지막에 제약을 겁니다.
  • 컬럼 이름 변경: 원자적으로 보이지만 사실상 삭제와 추가입니다. 이름 변경 대신 확장·이행·축소로 처리합니다.
  • 타입 변경: 재작성이 필요한 경우가 많고, 옛 코드가 새 타입을 파싱하지 못하면 즉시 비가역이 됩니다.
  • 인덱스 생성: 온라인 생성 옵션이 있는지, 있다면 실패 시 잔여물이 남는지 확인합니다.
  • 대량 백필: 배치 크기, 배치 간 대기, 재개 지점, 그리고 중단 스위치가 있어야 합니다. 백필이 복제 지연을 만들어 읽기 전용 복제본을 무너뜨리는 사고가 흔합니다.

5-4. 다운 마이그레이션은 대개 거짓말입니다

많은 마이그레이션 도구가 down 스크립트를 요구하지만, 데이터가 삭제된 뒤의 down은 스키마만 되돌릴 뿐 데이터를 복원하지 못합니다. 그래서 실무에서 신뢰할 수 있는 되돌리기는 역방향 마이그레이션이 아니라 애초에 되돌릴 필요가 없도록 설계한 확장 단계입니다. 옛 코드가 새 스키마 위에서 그대로 동작한다면 코드만 되돌리면 되고, 그것이 확장 단계의 진짜 목적입니다.


6. 기능 플래그: 롤백 버튼인가 새 기술 부채인가

6-1. 플래그의 진짜 값어치

플래그의 값어치는 되돌리는 데 걸리는 시간을 배포 파이프라인의 속도에서 떼어 내는 것입니다. 파이프라인이 12분이라면 롤백도 12분이지만, 플래그는 수 초입니다. 감지 시간이 3분인 조직에서 이 차이는 장애 시간을 4분의 1로 줄입니다.

6-2. 플래그의 진짜 비용

플래그 하나는 코드 경로를 두 개로 만듭니다. n개의 플래그는 이론적으로 2의 n승 개 조합을 만들고, 그중 실제로 테스트되는 조합은 극히 일부입니다. 세 개의 플래그가 서로 독립이라고 믿었는데 특정 조합에서만 터지는 버그가 나오는 상황이 여기서 생깁니다.

릴리스 플래그  생성 시점에 제거 티켓과 만료일을 함께 만든다  수명: 며칠에서 2주
실험 플래그    실험 종료일이 곧 만료일                       수명: 실험 기간
운영 플래그    킬 스위치. 장기 생존을 인정하고 문서화한다     수명: 무기한
권한 플래그    사실 플래그가 아니라 제품 기능이다             수명: 영구

6-3. 플래그가 롤백 버튼이 되려면

  • 꺼진 경로가 실제로 실행되고 있어야 합니다. 한 달 동안 아무도 실행하지 않은 옛 경로는 이미 썩었을 가능성이 높습니다. 카나리나 스테이징에서 주기적으로 양쪽을 모두 태워야 합니다.
  • 플래그는 코드 경로만 되돌립니다. 켜져 있는 동안 새 형식으로 저장된 데이터는 플래그를 꺼도 그대로 남습니다. 즉 플래그를 켠 순간 그 기능은 2절 기준으로 조건부 가역이 됩니다.
  • 플래그 평가 실패 시 기본값을 정해 둡니다. 플래그 서비스가 응답하지 않을 때 안전한 쪽으로 떨어지지 않으면 플래그 자체가 새로운 단일 장애점이 됩니다.

6-4. 여기서 의견이 갈립니다

플래그가 위험을 줄이는가 늘리는가는 정직하게 논쟁 중인 주제입니다. 줄인다는 쪽은 롤백 시간과 노출 면적을 근거로 듭니다. 늘린다는 쪽은 남겨진 플래그가 영구 분기가 되어 코드 이해를 어렵게 하고, "언제든 끌 수 있다"는 감각이 검증을 느슨하게 만든다고 봅니다. 실무적으로 이 논쟁의 축은 플래그 제거를 강제하는 절차가 있는지 여부입니다. 제거 절차가 있으면 앞쪽 주장이, 없으면 뒤쪽 주장이 맞는 조직이 됩니다.


7. 롤백 자체를 설계하기

7-1. 롤백은 예외 절차가 아니라 정상 경로입니다

한 번도 실행해 보지 않은 롤백은 롤백 계획이 아니라 희망입니다. 실제로 동작하는 조직은 릴리스 리허설에서 롤백을 최소 한 번 실행하고, 이전 버전 아티팩트가 레지스트리에 남아 있는지, 롤백 명령의 권한을 누가 갖는지, 설정 변경이 코드와 함께 되돌아가는지를 매번 확인합니다.

[롤백 결정 체크리스트 — 배포를 시작하기 전에 채워 둔다]
1. 감지: 어떤 지표가 몇 분 안에 이 실패를 보여 주는가?
2. 임계: 그 지표가 어떤 값이면 중단인가? (배포 전에 숫자로 확정)
3. 실행: 롤백 명령은 무엇이고 누가 권한을 갖는가? 소요 시간은?
4. 데이터: 이 배포가 이미 쓴 데이터는 어떻게 되는가?
5. 비가역: 되돌릴 수 없는 부분의 보상 절차는 무엇인가?
6. 통지: 누구에게 알리는가? (내부, 고객, 외부 API 소비자)

7-2. 롤백과 롤포워드

롤백이 항상 정답은 아닙니다. 판단 기준은 두 가지입니다. 이전 버전이 확실히 정상이었는지, 그리고 롤백이 데이터 측면에서 안전한지입니다. 둘 중 하나라도 아니라면 수정본을 빠르게 앞으로 밀어내는 롤포워드가 더 안전합니다. 다만 롤포워드는 "빠르게 고칠 수 있다"는 낙관에 기대므로, 장애 중에는 시간 상한을 정해 두고 그 안에 해결되지 않으면 롤백으로 전환하는 규칙이 필요합니다.

7-3. 롤백이 유발하는 2차 장애

되돌리는 행위 자체가 장애를 만들 수 있습니다. Google SRE Book은 연쇄 장애를 "양의 되먹임의 결과로 시간이 지나며 커지는 장애"로 정의합니다. 롤백 직후에는 캐시가 비고, 커넥션이 다시 맺어지고, 실패했던 요청이 한꺼번에 재시도되면서 정확히 그 되먹임이 만들어집니다.

  • 재시도는 항상 무작위화된 지수 백오프로 예약합니다. SRE Book의 명시적 권고입니다.
  • 재시도 예산을 둡니다. 책의 예시는 프로세스당 분당 60회입니다.
  • 계층이 겹치면 재시도가 곱해집니다. 세 계층이 각각 4회씩 재시도하면 사용자 동작 하나가 64번의 시도가 됩니다.
  • 재시도 가능한 오류와 영구 오류를 코드로 구분하고, 영구 오류는 절대 재시도하지 않습니다.
  • 무한정 큐에 쌓기보다 일찍 거절하는 편이 낫습니다. 부하 차단과 우아한 성능 저하가 그 수단입니다.

재시도를 안전하게 만들려면 멱등성이 필요합니다. RFC 9110은 멱등을 "동일한 요청을 여러 번 보냈을 때 서버에 의도된 효과가 한 번 보낸 것과 같은 것"으로 정의하며 GET, HEAD, PUT, DELETE, OPTIONS, TRACE를 멱등으로 분류합니다. POST는 멱등이 아닙니다. 자세한 설계는 멱등성과 재시도: 신뢰할 수 있는 API재시도 누적 확률 계산기를 참고하세요.

7-4. 비가역 구간을 만난 뒤

되돌릴 수 없는 지점을 이미 지났다면 남는 것은 보상뿐입니다. 잘못 발송된 알림에 대한 정정 공지, 잘못 계산된 값을 고치는 정정 배치, 외부 소비자에게 보내는 변경 안내가 여기 해당합니다. 중요한 것은 이 절차를 사고가 난 뒤에 발명하지 않는 것입니다. 2절에서 비가역으로 분류된 항목은 배포 계획서에 보상 절차를 함께 적어야 합니다.


8. 무엇을 보고 중단할 것인가 — 배포 게이트와 SLO

8-1. 중단 기준은 배포 전에 숫자로 적습니다

배포 중에 대시보드를 보며 "이 정도면 괜찮은 것 같다"고 판단하는 것은 사후 합리화가 되기 쉽습니다. 숫자와 관측 시간을 미리 적어 두면 판단이 논쟁에서 확인으로 바뀝니다.

# 예시 — 배포 게이트를 선언적으로 적어 둔 형태
canary:
  steps: [1, 5, 25, 50, 100] # 트래픽 비율
  interval: 15m # 각 단계 관측 시간, 지표 지연보다 길게
  analysis:
    - metric: request_error_rate # SLI에서 유도한 지표
      compare_to: baseline # 동시 대조군, 과거 시점이 아님
      fail_if: canary > baseline * 1.2
    - metric: latency_p99
      fail_if: canary > baseline * 1.3
  on_failure: rollback # 자동 중단 후 사람에게 통지

8-2. 관측 지연이 단계 길이의 하한입니다

지표 파이프라인이 5분 지연된다면 3분짜리 카나리 단계는 아무것도 보지 못한 채 통과합니다. 각 단계의 관측 시간은 지표 지연에 최소 한 번의 집계 주기를 더한 값보다 길어야 합니다. 이 계산을 하지 않은 자동 승격 파이프라인은 빠르게 100%까지 올라간 뒤 그제서야 경보를 울립니다.

8-3. 게이트에 걸 지표와 걸지 말 지표

  • 걸어야 하는 것: 사용자 관점 SLI입니다. 요청 오류율, 지연 시간 상위 분위, 핵심 전환 흐름의 성공률입니다.
  • 참고만 하는 것: CPU, 메모리 같은 자원 지표입니다. 변경과의 인과가 약하고 잡음이 큽니다.
  • 걸면 안 되는 것: 변경과 귀속 관계가 없는 지표입니다. 앞서 인용한 Workbook의 귀속 요건이 이 이야기입니다.
  • 에러 버짓 소진율: 절대값보다 소진 속도가 배포 중단 판단에 더 유용합니다.

8-4. 게이트가 너무 민감할 때

거짓 양성이 잦으면 사람들은 게이트를 무시하거나 우회합니다. 게이트를 도입한 뒤에는 중단 건수 중 실제 결함이었던 비율을 함께 기록하십시오. 그 비율이 낮으면 임계값이 아니라 지표 선택이 잘못된 경우가 많습니다.


9. 배포를 측정하기

DORA는 네 개의 핵심 지표를 다음과 같이 정의합니다.

  • 배포 빈도: 주어진 기간의 배포 횟수 또는 배포 사이의 시간입니다.
  • 변경 리드 타임: 변경이 버전 관리에 커밋된 시점부터 프로덕션에 배포되기까지 걸리는 시간입니다.
  • 실패한 배포의 복구 시간: 즉각적인 개입이 필요한 배포 실패로부터 복구하는 데 걸리는 시간입니다.
  • 변경 실패율: 배포 이후 즉각적인 개입이 필요했던 배포의 비율입니다.
  • 재작업률: 프로덕션 장애로 인해 발생한 계획되지 않은 배포의 비율입니다.

9-1. 속도와 안정성은 트레이드오프가 아닙니다

DORA는 이 점을 명확히 적어 두었습니다. 연구 결과 속도와 안정성은 트레이드오프가 아니며, 대부분의 팀에서 두 지표는 오히려 상관관계를 보인다는 것입니다. DORA의 표현을 그대로 옮기면, 장기적으로 실제 트레이드오프는 "더 나은 소프트웨어를 더 빠르게"와 "더 나쁜 소프트웨어를 더 느리게" 사이에 있습니다.

이 결과가 이 글의 주제와 만나는 지점은 분명합니다. 배포를 자주 하는 팀이 안정적인 이유는 배포 단위가 작기 때문이고, 작은 단위가 곧 되돌리기 쉬운 단위이기 때문입니다. 가역성은 속도의 대가가 아니라 속도의 전제입니다.

9-2. 지표를 KPI로 걸 때의 왜곡

배포 빈도를 목표로 삼으면 의미 없는 배포를 쪼개서 숫자를 만들 수 있습니다. 변경 실패율을 목표로 삼으면 실패를 실패로 기록하지 않는 유인이 생깁니다. 네 지표는 함께 볼 때만 의미가 있고, 개별 지표를 성과 목표로 거는 순간 왜곡됩니다. 이 경고는 위 자료의 문장이 아니라 이 글에서 덧붙이는 실무 주의사항입니다.


퀴즈: 실력을 확인해 보세요

퀴즈 1: 블루그린 배포를 쓰고 있으니 어떤 배포든 초 단위로 되돌릴 수 있다고 말하는 동료에게 무엇을 확인시켜야 할까요?

정답: 데이터베이스가 두 환경에 공유되는지, 그리고 이번 배포에 스키마 변경이나 데이터 쓰기 형식 변경이 포함되는지를 확인시켜야 합니다.

설명: 블루그린이 원자적으로 되돌리는 것은 라우팅이지 데이터가 아닙니다. 대부분의 블루그린 구성은 데이터베이스를 공유하므로, green에서 실행된 마이그레이션과 green이 새 형식으로 쓴 데이터는 blue로 되돌아가도 그대로 남습니다. 2절 기준으로 그 배포는 이미 조건부 가역이거나 비가역입니다.

퀴즈 2: 5% 카나리를 30분 돌렸고 오류가 한 건도 없었습니다. 100%로 올려도 될까요?

정답: 그 30분 동안 카나리가 받은 요청 수와 검출하려는 문제의 예상 발생률을 먼저 계산해야 합니다.

설명: 0.1% 확률로 발생하는 문제를 200건의 요청으로 검증하면 기대 발생 건수는 0.2건입니다. 아무 일도 없는 것이 정상이므로 이 결과는 통과가 아니라 관측되지 않음입니다. 또한 SRE Workbook이 지적하듯 커넥션 풀 고갈이나 하위 의존성 포화처럼 전체 규모에서만 드러나는 문제도 있습니다. 단계적으로 25%, 50%로 올리며 각 단계에서 다시 관측하는 것이 정답에 가깝습니다.

퀴즈 3: 컬럼 하나를 새 이름으로 바꾸는 마이그레이션을 한 번의 배포로 처리하려 합니다. 무엇이 문제인가요?

정답: 이름 변경은 사실상 삭제와 추가이므로, 롤백하면 옛 코드가 찾는 컬럼이 이미 존재하지 않습니다.

설명: Parallel Change 패턴에 따라 세 번의 배포로 나눕니다. 먼저 새 컬럼을 추가하고 양쪽에 쓰기, 다음으로 읽기를 새 컬럼으로 옮기고 과거 데이터를 배치로 백필, 마지막으로 며칠 뒤 옛 컬럼을 제거합니다. 각 단계 사이의 간격은 롤백을 검토할 수 있는 최대 시간과 같아야 합니다.

퀴즈 4: 롤백 직후 오류율이 오히려 더 올라갔습니다. 가장 먼저 의심할 것은?

정답: 롤백 자체가 만든 2차 효과, 즉 콜드 캐시와 커넥션 재수립, 그리고 밀린 요청의 동시 재시도입니다.

설명: SRE Book은 연쇄 장애를 양의 되먹임으로 커지는 장애로 정의합니다. 롤백 순간 캐시가 비면 하위 계층 부하가 급증하고, 실패했던 요청이 한꺼번에 재시도되면 그 부하가 다시 증폭됩니다. 무작위화된 지수 백오프, 재시도 예산, 부하 차단이 이 되먹임을 끊는 표준 수단입니다. 계층별 재시도가 곱해진다는 점도 함께 확인해야 합니다.

퀴즈 5: 경영진이 배포 빈도를 팀 KPI로 걸자고 합니다. 어떻게 답해야 할까요?

정답: 네 지표를 함께 보되 개별 지표를 성과 목표로 걸지 말자고 제안하고, 특히 변경 실패율과 복구 시간을 함께 보도록 요청합니다.

설명: DORA는 속도와 안정성이 트레이드오프가 아니며 대부분의 팀에서 상관관계를 보인다고 보고합니다. 하지만 배포 빈도만 목표가 되면 의미 없이 배포를 쪼개는 행동이 나오고, 변경 실패율만 목표가 되면 실패를 기록하지 않는 행동이 나옵니다. 지표는 개선의 방향을 보기 위한 것이지 개인 평가 도구가 아닙니다.


마치며

배포 전략을 고르는 일은 도구를 고르는 일이 아닙니다. 이 변경이 아직 되돌릴 수 있는 상태인지 판별하고, 되돌릴 수 없는 부분을 최대한 뒤로 미루고, 그래도 남는 비가역 구간에 대해 보상 절차를 미리 적어 두는 일입니다.

이 글의 내용을 한 문장으로 줄이면 이렇습니다. 가역성은 배포 파이프라인이 아니라 데이터 모델에서 결정됩니다. 확장·이행·축소를 지키는 팀은 어떤 배포 도구를 쓰든 안전하고, 그것을 건너뛴 팀은 어떤 도구를 써도 같은 자리에서 넘어집니다.


참고 자료

  • Canarying Releases — Google SRE Workbook — 카나리의 정의, 동시 대조군 요건, 지표 선정과 개수 제한, 규모와 기간의 대표성, 5% 카나리에서 20% 오류가 전체 1%가 된다는 계산, 그리고 카나리가 잡지 못하는 한계를 인용했습니다. 2026-08-15 확인.
  • DORA metrics: the four keys — DORA — 배포 빈도, 변경 리드 타임, 실패한 배포의 복구 시간, 변경 실패율, 재작업률의 정의와 "속도와 안정성은 트레이드오프가 아니다"라는 결론을 인용했습니다. 2026-08-15 확인.
  • Parallel Change — Martin Fowler — 확장, 이행, 축소 세 단계의 정의와 Joshua Kerievsky 귀속을 인용했습니다. 2026-08-15 확인.
  • Addressing Cascading Failures — Google SRE Book — 연쇄 장애의 정의, 무작위화된 지수 백오프, 분당 60회 재시도 예산 예시, 계층별 재시도가 곱해지는 계산, 부하 차단을 인용했습니다. 2026-08-15 확인.
  • RFC 9110 — HTTP Semantics — 9.2.2절의 멱등 정의와 멱등 메서드 목록, POST가 멱등이 아니라는 점을 인용했습니다. 2026-08-15 확인.
  • 2절의 세 단계 가역성 분류, 4-3의 표본 수 산수, 7-1의 롤백 결정 체크리스트, 9-2의 KPI 왜곡 경고는 위 자료에 그대로 나오는 것이 아니라 이 글에서 정리한 절차와 해석입니다.

이어서 읽기

완전 가이드 시리즈