모든 복구 계획은 첫 번째보다 조용한 두 번째 가정을 품고 있다. 첫 번째는 인프라의 일부가 사건에서 살아남는다는 것이고, 이 시리즈의 1부와 2부가 그것을 시험했다. 두 번째는 사건이 왔을 때 여전히 수정을 배포할 수 있다는 것이다. API가 응답하고, 콘솔이 로드되며, 파이프라인이 역할을 assume할 수 있고, Auto Scaling 그룹이 교체분을 띄울 수 있다는 것. 2023년 6월 13일, Lambda의 컴퓨트 용량을 관리하는 서브시스템의 잠복 결함이 us-east-1에서 함수 호출을 저하시켰고, 이후 네 시간 중 일부 동안 그 리전의 AWS Management Console은 오류 페이지를 서빙했으며 STS는 높은 오류율을 던졌다. 그날 대부분 고객의 인프라에서는 아무것도 망가지지 않았다. 망가진 것은 그들이 그것을 고치는 데 썼을 계층이었다. 컨트롤 플레인이 blast radius 안에 있으면, 수습 경로는 장애 도메인 안에 있다.

이 글은 Nothing Fails Alone의 3부다. 1부는 5월 us-east-1 사건을 다루며 존 경계가 버티는 동안 고객 아키텍처가 그 안에서 실패하는 것을 보여 줬다. 2부는 3월 me-central-1 이벤트를 다루며 경계가 무엇을 상대로 설계됐는지, 즉 시설 고장, 그리고 무엇을 상대로 설계되지 않았는지, 즉 두 존에 닿는 하나의 원인을 보여 줬다. 두 부 모두 AWS가 두 사건 한복판에서 게시한 같은 단서 근처에서 끝났다. "longer than usual provisioning times". 1부는 이 부가 당신의 복구 계획이 다른 모두의 복구 계획과 무엇을 공유하는지에 관한 것이라고 약속했다. 답은 이렇다. 그것은 컨트롤 플레인을 공유한다. 당신의 페일오버는 그 리전의 다른 모든 페일오버와 같은 리전 API를 호출하는데, 그 API는 공급자가 운영하고, 당신이 그것을 필요로 하게 만드는 바로 그 사건들에 의해 저하된다. 그 의존성은 당신이 복제본에 주는 것과 같은 정밀 조사를 받을 자격이 있다.

2023년 6월: 수정에는 실패한 그것이 필요했다

이 메커니즘은 AWS가 2023년 6월 13일에 대한 사후 이벤트 요약을 게시한 이래 공개 기록에 남아 있다. 정확히 읽을 가치가 있다. 그 아래의 인프라가 계속 돌아가는 동안 컨트롤 플레인이 실패한 가장 깔끔하게 문서화된 사례이기 때문이다. PDT 오전 10시 1분, us-east-1의 Lambda Frontend 플릿이 평범한 일일 트래픽에 맞춰 스케일링하기 시작했다. 오전 11시 49분, AWS의 말로 "a capacity threshold that had previously never been reached within a single cell"을 넘었고, 이는 "triggered a latent software defect". 실행 환경은 할당됐지만 사용되지 않았고, "responsible for managing the underlying compute capacity"인 서브시스템은 작동하는 교체분을 프로비저닝할 수 없었으며, 그 리전의 Lambda 호출이 실패하기 시작했다.

그러자 의존성 그래프가 제 일을 했다. 요약은 Amazon STS, AWS Management Console, Amazon EKS, Amazon Connect, Amazon EventBridge를 "as a result of the degraded Lambda function invocations"로 저하된 것으로 나열한다. STS는 오전 11시 49분부터 PDT 오후 2시 10분까지 "with three distinct periods of impact"와 함께 높은 오류율을 반환했다. us-east-1의 콘솔은 오전 11시 48분부터 오후 2시 2분까지 "AWS Management Console is currently unavailable" 페이지 또는 "504 Time-out"을 서빙했다. 페더레이션 로그인도 저하됐다. "Existing IAM sessions were not impacted, but new sign-in federation via SAML was degraded." 완전 복구는 영향이 시작된 지 3시간 48분 뒤인 PDT 오후 3시 37분에 왔다.

그것을 평범한 런북에 대응시켜 보라. 1단계, 콘솔에 로그인: 저하. 2단계, 파이프라인이 새 자격 증명을 위해 역할을 assume: STS, 저하, 세 차례 따로. 3단계, 수습 Lambda 호출: 그것이 곧 장애다. 당신의 인스턴스는 하나도 실패하지 않았다. 당신의 데이터베이스는 페일오버하지 않았다. 이벤트는 당신의 인프라에 전혀 닿지 않았는데도, 당신의 계획이 가정한 도구들을 앗아갔다. 교훈은 역사적이 아니라 구조적이다. 운영 계층과 실패 계층이 같은 계층이었고, 앞으로도 그럴 것이다.

2025년 10월: 컨트롤 플레인 관점에서 다시 본 붕괴

2025년 10월 us-east-1이 다운됐을 때, 이 사이트는 그날 바로 클라우드가 재채기하면 세계가 감기에 걸린다에서 다뤘다. 그 글은 blast radius의 폭, 인터넷의 절반이 한 리전에 의존하는 부조리에 관한 것이었고, 무엇을 바꿔야 하는지로 끝났다. 이 부는 그 글이 약속한 후속편으로, AWS의 공식 사후 이벤트 요약의 도움을 받아 쓰였다. 그 요약은 그날이 허락한 것보다 더 차가운 독해에 보답한다. 앱이 아니라 도구에 무슨 일이 일어났는지 보라.

방아쇠는 DNS였다. dynamodb.us-east-1.amazonaws.com에 대한 "a latent race condition in the DynamoDB DNS management system that resulted in an incorrect empty DNS record"였고, 자동화가 "failed to repair"한 레코드였다. DynamoDB의 엔드포인트는 몇 시간 안에 복원됐다. 컨트롤 플레인의 피해는 훨씬 오래갔다. 요약에 따르면 EC2는 "Between 11:48 PM PDT on October 19 and 1:50 PM PDT on October 20, customers experienced increased EC2 API error rates, latencies, and instance launch failures"였다. 그 리전의 모든 멀티 AZ 아키텍처의 표준 복구 수단인 교체 용량 띄우기 자체가 손상된 14시간이다. STS는 오후 11시 51분부터 오전 9시 59분까지 "API errors and latency"를 반환했다. IAM 사용자로 하는 콘솔 로그인은 오전 1시 25분까지 "increased authentication failures"로 실패했고, 그 리전의 Identity Center 사용자는 전혀 로그인할 수 없었으며, 루트 자격 증명과 페더레이션 로그인은 다른 리전에서도 오류를 던졌다. 로그인 경로 자체가 us-east-1에 있었기 때문이다.

두 글을 나란히 두면 역할 분담이 분명해진다. 10월 글은 한 리전에 의존하는 비용이 얼마인지 물었다. 이 글은 그 안의 더 좁고 더 고약한 질문을 묻는다. 리전이 나쁜 하루를 보냈을 때, 왜 잘 구축된 멀티 AZ 아키텍처가 몇 시간 동안 다운된 채였는가? 그들의 복구가 컨트롤 플레인 작업이었기 때문이다. 스케일 아웃이 수정이었고, 스케일 아웃이 바로 14시간의 손상된 인스턴스 실행이 앗아간 것이었다. 모두의 계획이 같은 시각에 같은 저하된 API로 수렴했고, 이것이 "당신의 계획이 다른 모두의 것과 컨트롤 플레인을 공유한다"가 실무에서 의미하는 바다.

2026년 2월: Azure, 같은 형태, 다른 로고

이것이 AWS의 별난 점이라면 AWS의 문제일 것이다. 그렇지 않다. 2026년 2월 2일, Microsoft는 사건 FNJ8-VQZ를 기록했고, 그 사후 사건 리뷰는 이렇게 시작한다. "Between 18:03 UTC on 02 February 2026 and approximately 00:30 UTC on 03 February 2026, a platform issue caused some customers to experience degraded performance and control plane failures, for multiple Azure services across multiple regions." Microsoft 관리 스토리지 계정에서 익명 접근을 비활성화하려던 보안 수습 정책이, "a data synchronization problem in the targeting logic"을 통해 "intentionally configured to allow anonymous read access for platform functionality"인 계정들, 즉 VM 확장 패키지를 서빙하는 계정들에 적용됐다. 가상 머신은 "failures when deploying or scaling"에 부딪혔고, AKS는 "failures in node provisioning"에 부딪혔으며, GitHub Actions 작업은 호스티드 러너를 확보하려 기다리는 동안 "queued and timed out while waiting to acquire a hosted runner".

무엇이 일어나지 않았는지 주목하라. 실행 중인 VM은 계속 실행됐다. 데이터 플레인은 멀쩡했다. 죽은 것은 여러 리전에서 한꺼번에 생성, 스케일, 변경하는 능력이었다. 컨트롤 플레인은 데이터 플레인과 달리 공유되는 방식으로 공유되기 때문이다. 그것이 일반화할 가치가 있는 속성이다. 컨트롤 플레인은 데이터 플레인이 조심스럽게 분리해 두는 존들, 때로는 리전들을 가로지르는 하나의 논리적 시스템이다. 그것은 모두가 복구하는 바로 그때 최대 부하를 받는 조각이고, 멀티 리전 다이어그램이 보여 주지 않는 방식으로 실패한다. 다이어그램은 당신의 리소스를 그리지, 그것들을 변형하는 기계를 그리지 않기 때문이다. 두 공급자, 4개월 간격, 같은 형태.

정적 안정성, 제대로 정의하기

이 방어에는 이름이 있다. 정적 안정성(static stability). 정적으로 안정된 시스템은 의존성이 실패할 때 아무것도 바꿀 필요 없이 요구 사항을 계속 충족한다. 의존성에 요청했을 그것이 이미 제자리에 있기 때문이다. 그 정의가 "정적"이라는 단어를 얻는다. 변형이 필요 없는 복구는 변형을 수행하는 계층에 의해 막힐 수 없다. 구체적으로, 그것은 미리 계산된 결정의 작은 집합을 뜻한다.

  • 사전 프로비저닝된 여유 용량. 각 존이 충분한 용량을 돌려, 살아남은 존들이 신규 실행 없이 전체 부하를 감당한다. 존 상실은 Auto Scaling 이벤트(컨트롤 플레인 작업)가 아니라 로드 밸런서 결정(데이터 플레인 작업)이 된다.
  • 페일오버 시 생성이 아니라 사전 생성. 스탠바이의 DNS 레코드, 타깃 그룹 연결, 스탠바이 인스턴스가 사건 전에 존재한다. 페일오버는 헬스 체크와 가중치를 뒤집을 뿐, Terraform을 돌리지 않는다.
  • 사전 빌드된 이미지. 패키지 미러, 구성 서비스, 시크릿 엔드포인트에 닿지 않고 서빙 상태로 부팅하는 AMI는, 주변의 모든 것이 저하돼도 실행을 유용하게 유지한다.
  • 실패한 계층을 피하는 브레이크 글라스 경로. 10월 요약은 로그인에 대해 무뚝뚝하다. IAM 사용자, Identity Center, 페더레이션이 모두 함께 저하됐다. 긴급 접근 경로는 당신이 구하려는 리전과 아이덴티티 플레인을 지나가지 않을 때에만 진짜이고, 실제로 훈련될 때에만 진짜다. 테스트되지 않은 브레이크 글라스 자격 증명은 소망이다.

공통된 맥락은 작업을 사건 도중에서 사건 이전으로, 컨트롤 플레인의 일정에서 당신의 일정으로 옮기는 것이다. 공급자의 컨트롤 플레인을 신뢰성 있게 만들 수는 없다. 첫 한 시간 동안 그것이 필요 없도록 준비할 수는 있다.

랩: 주장하지 말고 차이를 측정하라

이 부의 랩 03-static-stability는 시리즈 규칙 하나를 알면서 깬다. read-only가 아니다. Terraform이 VPC, 인터넷 대면 ALB, 여섯 개의 t3.micro 인스턴스를 만들고, 파괴하기 전까지 돈이 들므로, 샌드박스 계정에 두고 같은 날 쓰레기통에 넣어야 한다. 그 값으로 사는 것은 내 주장이 아니라 당신의 계정에서 이 글이 설명하는 정확한 간극의 측정이다. AWS 자체의 결함 주입 문서가 그 전제를 분명히 밝힌다. AZ 전원 중단 시나리오에서 "EC2 API calls made by the Auto Scaling control plane to recover lost capacity in the AZ will fail". 랩은 그 문장에 대한 두 답을 하나의 로드 밸런서 뒤에 만든다. 경로 A는 표준 설계다. 존당 인스턴스 하나와 스케일링 정책을 가진 Auto Scaling 그룹으로, 존을 잃으면 ASG가 복구를 위해 ec2:RunInstances를 호출해야 한다. 경로 B는 정적으로 안정된 설계다. 같은 워크로드를 두 배 용량으로, 존당 두 인스턴스로 사전 프로비저닝해, 어느 한 존만으로도 이미 전체 부하를 감당한다.

측정 스크립트에는 주석이 필요하다. 첫 초안이 교훈적인 방식으로 틀렸기 때문이다. ASG에서 실패한 존의 서브넷을 단순히 제거하는 것은 존 상실이 아니다. 그것은 리밸런싱을 촉발하고, 리밸런싱은 무언가를 종료하기 전에 교체분을 띄우므로, 건강한 용량이 결코 떨어지지 않아 측정할 것이 없다. 진짜 존 상실은 인스턴스를 죽인다. 그래서 measure.py는 서브넷을 제거한 다음 그 존의 서비스 중 인스턴스를 TerminateInstanceInAutoScalingGroupShouldDecrementDesiredCapacity=False로 종료해, 각 그룹이 다른 곳에서 복구해야 할 실제 용량만큼 부족한 상태로 둔다. 경로 A에 대해서는 결함부터 로드 밸런서의 완전한 건강 카운트까지의 간격을 재는데, 이는 순수한 컨트롤 플레인이다. 실행 호출, 부팅, 헬스 체크. 경로 B에 대해서는 정착 창 동안 건강 카운트를 지켜보며 최솟값을 기록하는데, 그것은 넷에서 둘로 떨어진다. 둘은 정확히 장애 후 요구 사항이므로, 통과 조건은 자명하게 유지되는 대신 실제 하락에 대해 시험된다. 이것이 스크립트가 출력하는 표의 형태이지 내가 얻은 결과가 아니다. 이 글을 위해 라이브 계정에 대해 이것을 돌리지 않았고, 독자가 얻는 숫자는 독자의 것이다.

PATH                    | TIME TO RECOVER               | API CALLS REQUIRED                | SURVIVES CONTROL PLANE LOSS
path-a (control plane)  | measured on your run          | yes: ec2:RunInstances via the ASG | no
path-b (static)         | 0s, capacity already in place | none                              | yes

경로 A가 당신에게 어떤 숫자를 출력하든, 그것을 최선의 경우로 읽어라. 그것은 조용한 날의 건강하고 협조적인 컨트롤 플레인에 대해 측정됐다. 10월의 컨트롤 플레인은 둘 다 아니었다. 랩 04는 경로 A의 숫자를 그날 밤 되었을 값으로 바꾸는 용량 부족 오류를 주입해, 그 간극을 메우기 위해 존재한다.

정직한 비용, 그리고 그것이 더는 값어치를 못하는 지점

경로 B는 같은 트래픽을 서빙하기 위해 정상 상태의 두 배 용량을 돌린다. 그것은 각주가 아니라 거래다. 정적 안정성은 매시간 유휴 컴퓨트로 보험을 사는 것이며, 연 단위 시간으로 측정되는 사건에 대비하는 것이다. 존이 둘이면 보험료는 100퍼센트다. 존이 셋이고 각각 하나를 잃어도 흡수하도록 사이징하면 50으로 떨어지고, 더 많은 존이나 오버프로비저닝을 고려한 사이징에서는 더 낮아진다. 다운타임이 매출이나 안전으로 측정되는 서빙 경로에, 두 배로 늘려도 절대 금액이 저렴한 작은 플릿에, 그리고 복구가 그렇지 않으면 사건 도중 컨트롤 플레인의 작동에 의존할 모든 것에 대해 그 값을 치러라.

계산이 맞지 않는 곳에서는 그 값 치르기를 멈춰라. 배치와 비동기 작업은 존 상실을 관통해 큐잉해야지, 그것에 대비해 사전 프로비저닝하지 말아야 한다. 개발과 스테이징에는 필요 없다. 아주 큰 플릿은 여유 용량에 실제 돈을 치르며, 그곳에서 정직한 수는 계층을 나누는 것이다. 크리티컬한 조각에는 정적 안정성을, 나머지에는 눈을 뜬 채 컨트롤 플레인 복구를 받아들인다. 그리고 이 기법이 커버하지 않는 것을 알아라. 그것은 1부의 Coinbase를 구하지 못했을 것이다. 그들의 실패는 자신들의 데이터 플레인, 즉 한 건물을 공유하는 쿼럼에 있었기 때문이다. 그것은 2부의 리전 상실에 답하지 못한다. 파멸한 리전 안의 여유 용량은 파멸한 여유 용량이기 때문이다. 그것은 컨트롤 플레인이 당신의 여유 용량이 충분하지 않게 되기 전에 돌아온다는 베팅으로, 첫 몇 시간을 보호한다. 그 베팅은 2023년 6월과 2025년 10월에 성립했다. 당신 버전의 그것이 성립하는지는 당신이 테스트하는 것이며, 이 시리즈는 다음으로 그리로 간다.

다음으로 읽을 글

AWS, 클라우드 아키텍처, 복원력 리뷰, 플랫폼 작업에 대한 컨설팅은 ercanermis.com에서 시작하라.

참고 자료