단계적 출시
새 판을 전부에게 한 번에 내보내지 않기로 하는 결정입니다. 처음에는 일부에게만 닿게 합니다. 그 비율을 시간을 두고 올립니다. 문제가 보이면 남은 사람들에게 가기 전에 멈춥니다.
상세
받는 쪽이 여럿일 때, 새 판을 그 전부에게 동시에 밀어 넣을 이유는 없습니다. 단계적 출시는 받는 쪽을 비율로 잘라 앞쪽부터 내보내고 그 비율을 올려 가는 방식입니다. 잘린 조각 하나가 문제 없이 지나가면 다음 조각을 엽니다. 문제가 보이면 남은 조각을 열지 않습니다.
flowchart TD
A[새 판] --> B[일부에게 내보냄]
B --> C{문제가 보이나}
C -->|보임| D[중단]
C -->|안 보임| E[비율 올림]
E -->|100% 미만| C
E -->|100%| F[전량 도달]
사용자 기기에 설치되는 소프트웨어에서 이 결정은 스토어의 기능으로 굳어 있습니다. 부르는 이름은 스토어마다 갈립니다. Google 쪽 이름은 staged rollout 이고 Apple 쪽 이름은 phased release 입니다. Google Play Console 도움말은 단계적 출시를 쓰면 갱신이 사용자의 일정 비율에만 닿는다고 적습니다. 그 비율은 시간을 두고 올릴 수 있습니다. 프로덕션 트랙과 테스트 트랙에 쓸 수 있습니다. 같은 문서는 단계적 출시를 앱 갱신에만 쓸 수 있다고 못 박습니다. 앱을 처음 게시할 때는 못 씁니다. 대상은 새 사용자와 기존 사용자 모두입니다. 릴리스마다 무작위로 뽑힙니다. Apple 의 App Store Connect 도움말은 같은 자리를 7일에 걸친 점진 배포로 정해 두었습니다. 자동 업데이트를 켠 기기의 무작위 표본이 갱신을 받습니다. 자기가 그 표본에 들었다는 알림은 사용자에게 가지 않습니다.
서버 쪽에도 같은 결정이 있습니다. Google 의 SRE(Site Reliability Engineering) 책은 롤아웃 과정이 필요한 만큼 단순하거나 복잡할 수 있다고 적습니다. 관련된 잡을 즉시 전부 갱신할 수도 있습니다. 새 바이너리를 여러 시간에 걸쳐 연속된 클러스터에 내보낼 수도 있습니다. 같은 문서는 목표가 배포 과정을 그 서비스의 위험 프로필에 맞추는 것이라고 적습니다. 사용자를 크게 마주하는 서비스라면 Google 은 한 클러스터에서 시작해 모든 클러스터가 갱신될 때까지 지수적으로 넓힐 수 있다고 적습니다. 민감한 인프라라면 롤아웃을 며칠에 걸쳐 늘릴 수 있다고 적습니다. 그때는 지리적으로 다른 지역의 인스턴스에 번갈아 끼워 넣는다고 적습니다.
쿠버네티스 디플로이먼트의 롤링 업데이트도 이 형태입니다. 디플로이먼트 컨트롤러는 새 판을 볼 때마다 레플리카셋을 만들어 원하는 파드를 띄웁니다. 옛 레플리카셋은 0까지 줄어듭니다. 두 레플리카셋이 함께 존재하는 구간이 곧 비율이 옮겨 가는 구간입니다.
대가
되돌리기가 반쪽입니다. Google Play Console 도움말은 문제를 발견하면 단계적 출시를 중단할 수 있다고 적습니다. 중단하면 추가 사용자는 그 버전을 받지 않습니다. 그러나 같은 문서는 이미 그 버전을 받은 사용자는 그 버전에 남는다고 적습니다. 중단은 앞으로 갈 것을 막는 손잡이지 이미 간 것을 거두는 손잡이가 아닙니다.
전량에 닿는 시점이 뒤로 밀립니다. Play 도움말은 갱신이 단계적 출시 비율만큼의 사용자에게 제공되지만 전체 집단이 갱신을 받기까지는 시간이 걸릴 수 있다고 적습니다. Apple 쪽은 그냥 두면 7일에 걸쳐 나갑니다. 그 표를 앞당기려면 Ready for Distribution 상태에서 전체 사용자에게 내보내는 선택을 따로 해야 합니다. 단계별 배포에 맡겨 둔 채로는 급히 고친 것도 같은 일정을 탑니다.
같은 시점에 두 판이 필드에 함께 있습니다. Play 도움말은 새 사용자와 기존 사용자가 모두 대상이라고 적습니다. 릴리스마다 무작위로 뽑힌다고도 적습니다. 쿠버네티스 문서도 롤링 업데이트 동안 옛 레플리카셋과 새 레플리카셋이 함께 존재한다고 적습니다. 어느 쪽이든 두 판이 같은 데이터와 같은 상대를 마주하는 구간이 생깁니다. 다만 문서가 적는 것은 두 판이 공존한다는 사실까지입니다. 그 구간이 하위 호환을 요구한다는 문장은 없습니다.
부수 작업이 뒤로 밀립니다. Play 도움말은 앱 갱신이 스토어 등재정보 변경을 필요로 하면 릴리스가 100% 사용자에게 나간 다음에 등재정보를 갱신하기를 권합니다.
노출을 완전히 통제하지는 못합니다. Apple 도움말은 단계적 배포 중인 앱과 앱 갱신을 앱스토어에서 누구나 언제든 손으로 내려받을 수 있다고 적습니다. Play 쪽은 단계적 출시분을 받은 사용자가 Google Play 에 공개 리뷰를 남길 수 있다고 적습니다. 문제를 만난 사람이 소수여도 그 기록은 공개된 자리에 남습니다.
기기에 설치되는 소프트웨어에서는 통제가 더 얇아집니다. martinfowler.com 에 실린 Danilo Sato 의 「Canary Release」는 이 계통의 기법이 어려워지는 자리로 사용자의 컴퓨터나 모바일 기기에 설치되는 소프트웨어를 듭니다. 새 판으로의 업그레이드가 언제 일어나는지에 대한 통제가 그만큼 덜하다는 것입니다. 같은 글은 이 기법의 단점으로 여러 판의 소프트웨어를 한꺼번에 관리해야 하는 것을 듭니다.
예시
App Store Connect
Apple 의 단계별 배포는 날짜별 비율이 문서에 표로 박혀 있습니다.
| 단계별 배포 일차 | 사용자 비율 |
|---|---|
| 1 | 1% |
| 2 | 2% |
| 3 | 5% |
| 4 | 10% |
| 5 | 20% |
| 6 | 50% |
| 7 | 100% |
이 표는 선택지가 아니라 일정입니다. 문서는 단계별 배포를 고르면 갱신이 7일에 걸쳐 점진적으로 나간다고 적습니다. 다만 Ready for Distribution 상태가 되면 언제든 전체 사용자에게 내보내는 선택을 따로 할 수 있습니다.
Argo Rollouts
서버 쪽에서는 같은 결정을 배포 명세 안에 단계 목록으로 적습니다. Argo Rollouts 의 Canary 전략 문서가 보여주는 최소 형태입니다.
- setWeight: 10
- pause:
duration: 1h # 1 hour
- setWeight: 20
- pause: {}
setWeight 는 카나리로 보낼 트래픽의 비율을 정합니다. pause 는 롤아웃을 멈추라는 지시입니다.
duration 이 붙으면 그 시간만큼 멈추고, pause: {} 는 기한 없이 멈춥니다. 문서는 레플리카가
10개인 롤아웃에서 첫 setWeight 가 10% 면 컨트롤러가 새 레플리카셋을 1개로 키운다고 적습니다.
쿠버네티스 디플로이먼트
디플로이먼트의 롤링 업데이트는 비율을 두 손잡이로 잡습니다.
.spec.strategy.rollingUpdate.maxUnavailable: 25%
.spec.strategy.rollingUpdate.maxSurge: 25%
maxUnavailable 은 갱신 중에 쓸 수 없어도 되는 파드의 최대치입니다. maxSurge 는 원하는 파드
수를 넘겨 더 만들 수 있는 최대치입니다. 둘 다 절대 수나 비율로 적을 수 있습니다. 기본값은 25%
입니다. maxUnavailable 은 비율에서 절대 수를 낼 때 내림합니다. maxSurge 는 올림합니다. 문서는
maxUnavailable 이 30% 면 롤링 업데이트가 시작될 때 옛 레플리카셋을 원하는 파드의 70% 까지
즉시 줄일 수 있다고 적습니다. 갱신 내내 쓸 수 있는 파드의 총수는 원하는 수의 70% 이상으로
유지됩니다.
운영
비율은 저절로 오르지 않습니다. Play 도움말은 앱의 단계적 출시 비율이 자동으로 증가하지 않는다고 적습니다. 더 큰 비율을 열려면 사람이 다시 들어가 올려야 합니다. 릴리스를 내보낼 때 받을 사용자 비율을 고르는 것도 사람입니다.
중단과 재개에는 사용자 집단이 따라붙습니다. Play 도움말은 롤아웃을 중단했다가 재개하면 같은 사용자 집합에 영향을 준다고 적습니다. 앞선 릴리스의 롤아웃을 끝내기 전에 새 릴리스를 단계적으로 내보내면, 새 릴리스는 비율에 따라 앞선 릴리스와 같은 사용자 집단을 씁니다. 국가를 지정하면 그 국가의 Google Play 계정을 가진 사용자로 업그레이드가 제한됩니다.
Apple 쪽의 손잡이는 일시정지입니다. 단계별 배포 중에 최대 30일까지 멈출 수 있습니다. 멈추는 횟수에는 제한이 없습니다. 10일을 멈추고 재개하면 다시 멈출 수 있는 날은 20일이 남습니다. 재개하면 멈춘 그날부터 이어집니다.
stateDiagram-v2
state "단계적 배포 중" as 배포중
state "일시정지" as 정지
state "전원 공개" as 전원
state "배포 중지" as 중지
[*] --> 배포중
배포중 --> 정지: 누적 최대 30일
정지 --> 배포중: 멈춘 날부터 이어감
배포중 --> 전원: 전체 배포 선택
배포중 --> 중지: 판매 중단
중지 --> 전원: 판매 재개 시 즉시
판매를 내리면 단계별 배포가 멈춥니다. Apple 도움말은 앱을 판매 중단하면 단계별 배포가 멈추고 그 버전에는 다시 쓸 수 없다고 적습니다. Apple Developer Program 멤버십이 만료된 경우도 같습니다. 앱이 복구되면 중단 전에 도달한 비율과 상관없이 즉시 모든 사용자가 받게 됩니다. 통제된 롤아웃을 다시 하려면 그 판을 내려받을 수 없게 만들어야 합니다. 그런 다음 단계별 배포를 켠 새 판을 다시 제출합니다.
볼 자리는 지표입니다. Android vitals 문서는 Google Play 에서 타이틀의 노출을 극대화하려면 아래 값들 아래로 유지하라고 적고, 이 값들을 bad behavior threshold 라고 부릅니다.
| 지표 | 전체 평균 | 폰 모델별 | 워치 모델별 |
|---|---|---|---|
| 사용자 인지 크래시율 | 1.09% | 8% | 4% |
| 사용자 인지 ANR(Application Not Responding, 앱이 응답하지 않는 상태)율 | 0.47% | 8% | 5% |
| 과도한 배터리 사용 | 1% | - | 1% |
| 과도한 부분 웨이크 락 | 5% | - | - |
같은 문서는 앱이나 게임이 이 값을 넘으면 Play 가 타이틀의 노출을 줄일 수 있다고 적습니다. 스토어 등재정보에 경고를 띄울 수도 있습니다. Play 도움말은 단계적 출시 중에 크래시 보고와 사용자 피드백을 가까이 지켜보기를 권합니다.
관련 항목
이것이 속하는 상위 분류
배포 · SRE · 롤아웃 · 릴리스 엔지니어링 · 지속적 배포 · progressive delivery
이름이 겹치는 이웃 기법
progressive delivery 가 묶어 부르는 기법
기능 스위치 · A/B 테스트 · blast radius
이 이름을 붙이거나 쓰는 조직
Apple · Google · Microsoft · RedMonk · LaunchDarkly
이것이 걸리는 앱스토어 쪽 요소
Google Play Console · App Store Connect · 프로덕션 트랙 · 테스트 트랙 · 자동 업데이트 · 스토어 등재정보 · 알림
서버 쪽에서 이것을 실제로 굴리는 도구·설정값
바이너리 · 쿠버네티스 · 디플로이먼트 · 레플리카셋 · 파드 · 클러스터 · Argo Rollouts · maxSurge · maxUnavailable · setWeight · pause
이것의 속도를 정하는 기준
위험 프로필 · Android vitals · 사용자 인지 크래시율 · 사용자 인지 ANR율 · 크래시 보고
이것을 쓰면 떠안는 되돌리기·호환 부담
다른 이름: staged rollout · phased release · phased rollout · incremental rollout · 단계별 배포