메인 콘텐츠로 건너뛰기

AWS가 다운돼도 서비스는 멈추지 않는 아키텍처 만들기

요약

얼마 전 AWS us-east-1 리전이 크게 장애를 일으키면서, 전 세계 서비스들이 줄줄이 멈춰 섰습니다. 디즈니+, 리프트, 맥도날드, 뉴욕타임즈, 레딧까지 이름만 들어도 아는 서비스들이 영향을 받았죠.

그런데 이 와중에도 멀쩡히 돌아간 서비스들이 있습니다. 이 글에서는 "어떻게 AWS가 다운돼도 서비스가 멈추지 않을 수 있었는지"를 실제 사례를 바탕으로 풀어보려고 합니다.

인증/인가(로그인, 권한관리)처럼 애플리케이션의 가장 핵심 경로에 있는 서비스를 99.999% 가용성(5 nines)로 운영하기 위해, 어떤 아키텍처와 사고 방식이 필요했는지 하나씩 뜯어보겠습니다.

5 nines 신뢰성, 말이 되나? 숫자부터 현실 체크

먼저 "신뢰성"을 이야기할 때 우리가 실제로 어떤 세계를 상상하고 있는지부터 짚어볼 필요가 있습니다.

5 nines, 즉 99.999% 가용성은 1년에 허용되는 총 장애 시간이 약 5분 15초에 불과하다는 뜻입니다. 하루도 아니고, 한 달도 아니고, "1년" 동안 다운될 수 있는 시간이 5분 남짓이라는 거죠.

이 정도면 사실상 "항상 살아 있어야 한다"는 말과 비슷합니다. 서버 한 대가 버티는 수준이 아니라, 네트워크, DNS, 데이터베이스, 인증, 서드파티 API, 배포, 심지어 고객 지원까지 모든 요소가 합쳐져 이 숫자를 만족해야 합니다.

여기서 중요한 포인트는 두 가지입니다.

  • 5 nines는 "개별 컴포넌트"의 목표가 아니라 "전체 서비스" 목표라는 것

  • 클라우드 제공사의 SLA만 믿고는 이 숫자를 절대 달성할 수 없다는 것

따라서 "5 nines가 정말 가능한가?"라는 질문은 사실 "얼마나 집요하게 실패를 가정하고 설계했는가?"에 가까운 질문입니다.

인증/인가 서비스가 다운되면 세상이 멈추는 이유

이번 사례의 주인공은 Authress라는 인증/인가 플랫폼입니다. 이 서비스가 하는 일은 여러분이 직접 만드는 애플리케이션 앞단에서 다음과 같은 기능을 맡는 것입니다.

  • 유저 로그인 및 토큰(JWT) 발급

  • 권한·역할 기반 접근 제어(ABAC, RBAC, ReBAC 등)

  • API 키 발급 및 머신 투 머신 인증

  • 권한 변경 이력에 대한 감사 로그

한마디로, "로그인 안 되면 서비스 자체를 못 쓰는" 구조에서 가장 첫 번째에 있는 인프라라고 보면 됩니다.

그래서 여기서 장애가 나면 어떤 일이 벌어질까요? 간단합니다. 고객 서비스 전체가 같이 죽습니다.

  • 쇼핑몰: 고객이 로그인을 못 해서 결제를 못 함

  • SaaS 서비스: 대시보드 진입 불가, API 호출 전부 401/403

  • 내부 시스템: 직원 업무 중단

이런 구조에서는 "가끔 다운돼도 크게 문제 없는 백그라운드 배치" 수준이 아니라, "절대 멈추면 안 되는 전력·통신망" 같은 마인드로 아키텍처를 설계해야 합니다.

AWS SLA만 믿으면 안 되는 이유

그렇다면 이렇게 생각할 수 있습니다.

"AWS가 알아서 고가용성을 보장해주니까, 우리는 그 위에 잘 얹어만 두면 되는 거 아닌가?"

문제는 AWS의 대표 서비스 SLA조차 5 nines에 미치지 못한다는 데 있습니다.

  • Lambda SLA: 5 nines 미만

  • API Gateway SLA: 5 nines 미만

  • SQS SLA: 5 nines 미만

게다가 이론이 아니라 실제 장애 기록을 보면 더 무섭습니다.

  • 특정 리전 전력 문제로 전체 서비스 중단

  • 사람 실수로 핵심 S3 서버 삭제

  • 네트워크 컨트롤 플레인 장애로 리전 전체 서비스 영향

  • DNS 문제로 EC2, DynamoDB 등 핵심 서비스 다수 불능

이게 10년에 한 번 있는 일도 아닙니다. 클라우드 이용자와 서비스 수가 늘어날수록 장애 발생 빈도도 같이 올라갑니다.

결론은 명확합니다.

  • "AWS가 SLA를 보장하니까 우리 SLA도 괜찮겠지" → 절대 아님

  • "클라우드가 안정적이니까 아키텍처는 단순하게 가도 된다" → 현실 부정

우리는 "클라우드도 언제든지 실패할 수 있다"는 전제를 깔고, 그 위에 우리의 SLA를 별도로 설계해야 합니다.

서드파티 의존성, 얼마나 불안정해도 버틸 수 있을까?

5 nines를 이야기할 때 가장 많이 간과되는 부분이 바로 "서드파티 API 의존성"입니다.

예를 들어 이런 시나리오를 생각해 봅시다.

  • 우리 API가 사용자 로그인 요청을 받음

  • 내부에서 구글이나 Okta 같은 외부 IdP에 한 번 호출

  • 결과를 데이터베이스에 저장하고 응답 반환

여기서 서드파티가 90%만 성공하는 서비스라면 어떻게 될까요? 10번 중 1번은 실패한다는 뜻입니다.

만약 우리는 5 nines, 즉 "10만 번 중 1번 정도만 실패"해야 하는 서비스를 만들고 싶다면, 이 서드파티 실패를 재시도(retry)로 얼마나 보완할 수 있을까요?

대략적인 감각으로 보면:

  • 서드파티 성공률이 90%라면,

  • 우리 서비스가 99.999%에 가깝게 올라가려면,

  • 동일 요청을 최소 5번 이상 재시도해야 합니다.

문제는 여기서 끝이 아닙니다.

재시도 자체도 하나의 컴포넌트이기 때문에, 재시도 로직도 실패할 수 있습니다. 즉:

  • 재시도 핸들러도 우리 SLA 이상으로 안정적이어야 하고,

  • 너무 자주, 많이 호출되면 재시도 로직이 오히려 전체 가용성을 깎아 먹습니다.

계산을 해보면 이런 결론에 도달합니다.

  • 서드파티 자체 성공률이 최소 약 99.7% 이상은 되어야

  • "재시도"라는 무기를 통해서 5 nines까지 끌어올릴 수 있습니다.

즉, 90%짜리 서드파티를 "빈틈없는 재시도 로직"으로 구제하는 건 불가능에 가깝습니다. 이런 컴포넌트는 그냥 "크리티컬 경로에서는 안 쓴다"가 정답입니다.

마이크로서비스를 설계할 때:

  • 어떤 외부 API가 우리 SLA를 함께 끌어내리는지

  • 이 컴포넌트를 critical path에서 완전히 분리할 수 있는지

  • 아니면 비동기 처리로 돌려도 되는지

를 냉정하게 판단해서 "과감히 버릴 건 버려야" 합니다.

리전 장애에 대응하는 DNS 기반 페일오버 전략

서드파티 이전에, 인프라 자체도 언제든 실패합니다.

  • DB가 느려지거나 에러를 뿜기 시작할 수 있고

  • 컴퓨트 리소스가 제때 증설되지 않을 수 있고

  • 네트워크나 DNS 문제로 아예 요청이 도착하지 않을 수도 있습니다.

이럴 때 가장 직관적인 대응은 하나입니다.

"그 리전은 죽었다고 보고, 다른 리전으로 넘긴다."

이를 위해 필요한 게 바로 DNS 기반 페일오버입니다.

Authress가 사용한 전략은 다음과 같습니다.

  • Route 53에서 헬스 체크를 정의하고

  • 각 리전에 배포된 서비스의 상태를 실질적으로 체크한 뒤

  • 문제가 감지되면 DNS가 자동으로 프라이머리 리전에서 세컨더리 리전으로 트래픽을 옮깁니다.

중요한 포인트는 "헬스 체크의 수준"입니다.

단순히 "/healthz가 200을 주면 OK"로 끝내지 않습니다. 실제 헬스 체크 핸들러 안에서:

  • DynamoDB 조회

  • SQS 같은 보조 컴포넌트 호출

  • 핵심 비즈니스 로직 실행

  • 모델 검증 로직 수행

을 모두 돌려 보고, 이 중 하나라도 비정상이라면 해당 리전을 "문제 있음"으로 판단합니다.

즉, 헬스 체크는:

  • 단순 네트워크 핑이 아니라

  • "우리 서비스가 실제로 고객 요청을 처리할 수 있는 상태인지"를 검증하는 작은 통합 테스트인 셈입니다.

이렇게 해야 "AWS 내부 헬스 체크는 초록불인데, 실제론 서비스가 반쯤 죽어 있는 상황"을 막을 수 있습니다.

엣지(Edge) 아키텍처로 페일오버를 더 정교하게

DNS 페일오버는 강력하지만, 한계도 분명합니다.

  • 리전 단위로 한 번에 갈아타야 해서 "부분적인 장애"에 세밀하게 대응하기 어렵고

  • DNS TTL, 캐싱 등의 이유로 전환에 시간이 걸릴 수 있습니다.

그래서 가능한 경우, CloudFront + Lambda@Edge 같은 엣지 아키텍처를 도입하면 페일오버 전략이 훨씬 정교해집니다.

이 구조에서는:

  • 전 세계 엣지 로케이션에서 요청을 받아

  • 가장 가까운(또는 헬스 상태가 좋은) 리전의 컴퓨트로 라우팅하고

  • 각 리전의 DB 상태를 보고 필요하면 바로 인접 리전으로 재시도할 수 있습니다.

예를 들어:

  1. 서울 리전 DB에 문제가 있으면

  2. 바로 도쿄 리전의 DynamoDB Global Table로 요청을 보내고

  3. 그래도 안 되면 세 번째 리전으로 한 번 더 시도

같은 식으로 세 단계를 시도해 볼 수 있습니다.

몇 번까지 이런 페일오버를 허용할지는 아까 이야기한 확률 계산과 연결됩니다. "이 정도 시도까지는 우리 SLA 안에서 감당 가능하다"는 지점까지가 한계선이 됩니다.

핵심 아이디어는 이겁니다.

  • 장애를 "리전 전체"가 아니라 "특정 컴포넌트" 단위로 쪼개서 보고

  • 네트워크 엣지 레벨에서 유연하게 우회할 수 있게 만들어 둔다

이렇게 하면 단순 DNS 페일오버보다 "더 작게, 더 세밀하게, 더 빠르게" 장애를 우회할 수 있습니다.

애플리케이션 버그는 반드시 나온다, 그 다음이 중요하다

인프라와 서드파티를 아무리 잘 설계해도, 결국 애플리케이션 코드에서 버그는 나옵니다.

여기서 할 수 있는 가장 어리석은 선택은 "우리는 테스트 잘 짜니까 버그 안 날 거야"라고 믿는 것입니다.

현실적인 전략은 다음 두 가지입니다.

  1. 배포 전: 최대한 가치 있는 테스트에 투자

  2. 배포 후: 버그가 터지면 얼마나 빨리 알아채고 되돌릴 수 있는지 준비

테스트 전략에서 중요한 건 "커버리지 퍼센트"가 아니라 "테스트의 가치"입니다.

  • 모든 코드를 100% 테스트하는 건 불가능에 가깝고

  • 20%의 테스트로 80%의 위험을 줄일 수 있다는 80/20 법칙을 적용해야 합니다.

  • 특히 인증/인가, 요금 청구, 데이터 무결성 같은 부분은 반드시 집중 테스트 대상입니다.

하지만 "얼마나 잘 테스트를 해도 모든 버그를 막을 수는 없다"는 걸 인정하는 순간, 시야가 확 넓어집니다.

그래서 필요한 게:

  • 롤백이 빠른 배포 전략

  • 배포 단위를 작게 나누는 점진적 롤아웃

  • 배포 후 실제 프로덕션에서 돌아가는 코드를 검증하는 메커니즘

입니다.

프로덕션 데이터를 지키는 검증(Validation) 테스트

버그의 일부는 테스트 환경에서 절대 재현되지 않고, 실제 프로덕션 데이터에서만 모습을 드러냅니다.

그래서 Authress는 "프로덕션용 검증 테스트"라는 개념을 적극적으로 활용합니다.

아이디어는 단순합니다.

  • 동일한 의미를 가진 데이터를 서로 다른 저장소나 포맷으로 보관해 두고

  • 정기적으로 둘을 비교해서 모순이 없는지 확인하는 것

예를 들어:

  • 권한 설정이 저장된 DB

  • 그 권한이 실제로 어떻게 사용되었는지 남긴 감사 로그

  • 캐시나 인덱스에 저장된 유도 데이터

이 세 가지를 비교해서:

  • "논리적으로 같아야 하는데 다른 경우"를 찾아냅니다.

이 작업은 고객 요청 흐름과 분리된 스케줄 작업으로 돌아갑니다. AWS CloudWatch Events(이제는 EventBridge 스케줄 규칙)를 이용해 정기적으로 데이터를 읽어서 비교하고, 이상이 발견되면 바로 알림을 발생시킵니다.

이런 검증이 중요한 이유는:

  • AWS조차 "DB 내구성 100%"를 보장하지 않습니다.

  • 특정 샤드 손상, 네트워크 오류, 일시적 쓰기 실패 등으로 데이터가 어긋날 수 있습니다.

  • 유저 입장에서는 "권한이 있어야 하는데 막힌다" 같은 상황이 바로 '장애'입니다.

따라서 "데이터 모순"을 미리 잡아내는 것은 신뢰성을 "확률" 관점에서 확실히 끌어올려 줍니다.

장애의 '확률'이 아니라 '영향'을 줄이는 법: 점진적 롤아웃

여기까지는 주로 "장애가 발생할 가능성"을 줄이는 이야기였습니다.

하지만 아무리 잘 준비해도 언젠가는 사고가 납니다. 그래서 두 번째 축이 필요합니다.

  • 장애가 나더라도 "얼마나 적은 사람에게만 영향을 줄 것인가"

Authress는 이를 위해 고객을 여러 그룹(버킷)으로 나누고, 코드 배포를 순차적으로 진행합니다.

  • 1번 버킷(일부 고객)에게만 새 버전 배포

  • 일정 시간 모니터링 → 이상 없으면 2번 버킷 배포

  • 또 이상 없으면 3번, 4번… 이런 식으로 전체에 확산

만약 첫 번째나 두 번째 단계에서 이상 징후가 발견되면? 그 시점에서 롤아웃을 중단하고 원인을 분석합니다.

이렇게 하면:

  • "새 버그가 프로덕션에 들어오는 것" 자체는 완전히 막을 수 없지만

  • "한 번에 모든 고객에게 피해가 가는 상황"은 막을 수 있습니다.

즉, 장애의 "확률"은 어쩌면 비슷하더라도, 장애의 "영향 범위"를 극적으로 제한할 수 있습니다.

진짜 AI보다 먼저 써야 할 것: 비즈니스 지표 기반 이상 탐지

이제 "어떻게 장애를 빨리 알아차리나?"의 문제로 넘어가 봅시다.

대부분의 모니터링은 이런 것들을 봅니다.

  • 500 에러 비율

  • 응답시간 증가

  • CPU/메모리 사용량

하지만 이 숫자는 "서비스에 진짜 문제가 있는지" 말해주지 못하는 경우가 많습니다.

그래서 Authress는 "비즈니스 지표"에 집중합니다. 그 중 하나가 바로 "Authorization Ratio"라는 지표입니다.

  • 전체 인증/인가 요청 중

  • 정상적으로 성공한 비율 vs 거절·타임아웃·미완료 비율

이 비율이 평소 패턴에서 얼마나 벗어나는지를 기반으로 이상 여부를 감지합니다.

  • 단순 에러율이 아니라

  • "유저 입장에서 실제로 문제가 체감되는지"를 반영하는 지표라서

  • 진짜 장애에 훨씬 더 민감하게 반응할 수 있습니다.

그리고 여기에 이상 탐지(Anomaly Detection)를 더합니다.

  • 특정 시간대에 평소보다 실패 비율이 미묘하게 증가했다면?

  • 일시적 노이즈인지, 실제 문제의 전조인지?

이런 상황에 자동 알림을 걸되, 일정 시간 이상 지속될 때에만 "진짜 장애"로 간주하는 식으로 튜닝해 나갑니다.

중요한 건, 이게 요즘 말하는 LLM 기반 AI가 아니라는 점입니다. 오히려 오래전부터 있던 "이상 탐지" 개념을 제대로 적용하는 게, 신뢰성을 높이는 데 훨씬 직접적인 도움이 됩니다.

장애란 무엇인가? 고객 관점과 우리의 관점이 엇갈릴 때

재미있는 문제 하나가 있습니다. "어떤 상태를 장애라고 부를 것인가?"

다음 네 가지 경우를 생각해보세요.

  1. 우리도 괜찮다고 생각하고, 고객도 괜찮다고 느낀다 → 정상

  2. 우리도 문제라고 느끼고, 고객도 문제를 겪고 있다 → 명백한 장애

  3. 우리 시스템은 이상 징후를 감지했는데, 고객은 아무도 모른다

  4. 우리는 멀쩡하다고 생각하는데, 고객은 '서비스 죽었다'고 느낀다

3번의 경우:

  • 고객은 잠들어 있고(예: 새벽 3시, 한 국가에만 있는 고객),

  • 우리는 알람을 받고 난리지만

  • 실제로는 아무도 쓰지 않는 시간대에만 잠깐 문제가 있었던 케이스일 수 있습니다.

이때 매번 엔지니어를 깨워서 대응하게 한다면? 인력 소모에 비해 효과가 너무 작습니다.

"언제든 장애를 바로 고쳐야 한다"는 강박보다는 "어떤 장애는 다음 근무 시간에 고쳐도 된다"라는 현실적인 기준이 필요합니다.

반대로 4번의 경우가 훨씬 위험합니다.

  • 우리 모니터링은 초록불인데

  • 고객은 이미 "서비스 다운"을 외치고 있는 상황

이걸 Gray Failure라고 부릅니다. 이 상황을 방치하면, 나중에는 정말 큰 장애로 번질 수 있습니다.

그래서 Authress는:

  • 고객 지원 채널을 SLA의 핵심 요소로 보고

  • 들어오는 모든 티켓을 엔지니어링 팀에 직접 전달합니다. (중간 티어를 여러 단계를 두지 않음)

  • "왜 이 티켓이 생겼는가" 자체를 원인 분석 대상에 포함합니다.

이 접근은 고통스럽지만 효과적입니다.

  • 엔지니어가 고객의 실제 통증을 직접 보고

  • 문서, 에러 메시지, UX, API 설계까지 전반을 개선하게 만들기 때문입니다.

악의적인 트래픽과 과도한 사용으로부터 서비스를 지키는 법

여기까지는 "선의의 사용자와 정상적인 코드"를 상정한 이야기였습니다.

하지만 현실 세계에는:

  • 이상한 "보안 취약점 제보" 메일을 보내는 사람도 있고

  • 의도적으로 리소스를 소진시키려는 공격자도 있고

  • 고객의 고객(또는 그 고객의 고객)이 잘못된 사용 패턴으로 우리 시스템을 압박하는 경우도 있습니다.

특히 멀티테넌트 SaaS 환경에서는 세 가지를 모두 신경 써야 합니다.

  • 한 고객 계정 안에서 "특정 서비스"가 리소스를 다 빨아먹는 상황 (Intra-tenant)

  • 한 고객(테넌트)이 전체 플랫폼 리소스의 대부분을 가져가 버리는 상황 (Inter-tenant)

  • 고객의 고객, 또는 더 아래 단계의 사용자가 폭주하는 상황

이 모든 상황에서 결국 우리가 보호해야 할 것은:

  • "특정 사용자의 폭주가, 다른 정상적인 사용자에게 영향을 주지 않도록 하는 것"

그리고 이를 위한 가장 현실적인 답은 결국 Rate Limiting + WAF입니다.

Authress가 취한 접근은 대략 이렇습니다.

  • AWS WAF의 "IP 평판 리스트"를 적극 활용해 이미 악명이 자자한 IP는 선제 차단

  • 하지만 기타 매니지드 룰은 신중하게 사용 (높은 비용 + 오탐 가능성 때문)

  • 계정별 RPS(초당 요청 수)에 상한선 설정 – 예: 2,000 RPS 초과 시 기본 차단

  • 100, 200, 500, 1,000 RPS 등 임계값마다 모니터링 알림을 걸어서 "폭주 전조"를 조기에 포착

  • WAF 로그를 기반으로 "개별 요청은 정상처럼 보여도, 패턴상 이상한 트래픽"을 묶어서 차단

특히 마지막 부분이 중요합니다.

  • 한 번 들어온 /some-path 요청은 멀쩡해 보이지만

  • 같은 IP(혹은 동일한 TLS 핑거프린트)가 동일 요청을 매초 수십, 수백 번 보내고 있다면?

  • 또는 우리 서비스에는 존재하지 않는 /admin.php 같은 워드프레스 흔적을 계속 두드린다면?

이런 트래픽은 개별 요청만 보면 정상이지만, "시간과 패턴을 같이 보면" 분명 이상합니다.

이 패턴을 주기적으로 분석하고, 자동화된 룰로 승격시키면:

  • 2,000 RPS까지 기다리지 않고

  • 훨씬 이른 시점에 악성 트래픽을 차단할 수 있습니다.

그리고 이 모든 보호 장치는:

  • 계정 단위, 리전 단위, 전역(Global) 단위 세 레벨에서 동시에 설계되어야 합니다.

마무리: 5 nines는 '보장'이 아니라 '방어 전략'이다

지금까지 이야기를 한 번 정리해 보겠습니다.

5 nines에 가까이 가기 위해 Authress가 실제로 적용한 것들은 대략 이런 것들입니다.

  • 서드파티 컴포넌트의 신뢰성을 수학적으로 검토하고, 기준 미달은 크리티컬 경로에서 제거

  • DNS 기반 리전 페일오버와, 실제 비즈니스 로직까지 검증하는 커스텀 헬스 체크

  • CloudFront + Lambda@Edge를 활용한 엣지 아키텍처로 더 세밀한 페일오버

  • 배포 전 테스트는 "커버리지"보다 "가치"에 집중

  • 배포 후에는 검증(Validation) 테스트로 프로덕션 데이터 일관성 모니터링

  • 고객을 버킷으로 나눠 점진적으로 롤아웃함으로써 장애의 영향을 최소화

  • 비즈니스 지표(Authorization Ratio)를 중심으로 한 이상 탐지

  • 고객 지원을 SLA의 핵심 축으로 보고, 모든 티켓을 엔지니어링으로 직접 연결

  • WAF + Rate Limiting으로 멀티테넌트 환경에서의 리소스 오남용과 공격 방어

그리고 이 모든 것을 7년 넘게 쌓아 올린 뒤에도, 결론은 꽤 겸손합니다.

  • "우리는 5 nines를 약속한다."

  • "하지만 이 모든 건 5 nines를 '보장'하기 위한 것이 아니라, 그 약속을 지키기 위해 할 수 있는 최대한의 '방어 전략'이다."

여러분이 지금 만드는 서비스가 당장 5 nines를 필요로 할 수도, 그렇지 않을 수도 있습니다. 하지만 아래 질문 세 가지는 어떤 규모에서든 한 번쯤 진지하게 던져 볼 가치가 있습니다.

  • 우리의 SLA 목표는 얼마인가? (막연히 "안정적이어야지"가 아니라 숫자로)

  • 그 목표를 AWS나 서드파티 SLA에 그냥 위임하고 있지는 않은가?

  • 장애의 "확률"과 "영향"을 줄이기 위해 지금 당장 바꿀 수 있는 설계는 무엇인가?

모든 걸 한 번에 바꿀 필요는 없습니다. 오늘은 서드파티 의존성부터, 내일은 헬스 체크, 그 다음은 배포 전략… 하나씩 손보는 것만으로도 여러분 서비스의 신뢰성 곡선은 눈에 띄게 달라질 것입니다.

출처 및 참고 : How when AWS was down, we were not | Authress - Knowledge Base

이 노트는 요약·비평·학습 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.