AWS 고가용성과 확장성 제대로 이해하기: 모든 것은 결국 고장난다
장애를 전제로 리전과 AZ, 확장 방식, 로드 밸런서와 Auto Scaling, 데이터베이스 이중화, RTO/RPO를 정리합니다.
모든 것은 결국 고장납니다
고가용성 설계는 "서버가 죽지 않게 하는 기술"이 아니라 "서버가 죽어도 서비스는 살아 있게 하는 기술"입니다. 아마존 CTO 베르너 보겔스는 "모든 것은 언제나 고장난다(Everything fails, all the time)"라고 말했습니다. 디스크는 닳고, 네트워크 장비는 재부팅되고, 데이터센터는 정전을 겪고, 배포한 코드에는 버그가 숨어 있습니다.
그래서 질문을 바꿔야 합니다. "어떻게 고장을 막을까?"가 아니라 "이 부품이 지금 죽으면 사용자는 무엇을 겪을까?"를 묻는 것입니다. 이 글은 그 질문에 AWS가 어떤 도구로 답하는지, 그리고 그 도구들이 왜 그렇게 생겼는지를 차근차근 풀어 봅니다.
비슷해 보이는 네 가지 말
가용성, 확장성, 내구성, 내결함성은 서로 다른 질문에 답합니다. 하나를 갖췄다고 나머지가 저절로 따라오지는 않습니다.
| 개념 | 답하는 질문 | 예시 |
|---|---|---|
| 가용성(Availability) | 지금 접속하면 응답하는가? | 99.99%는 1년에 약 52분까지만 멈출 수 있음 |
| 확장성(Scalability) | 부하가 10배가 되어도 감당하는가? | 티켓 오픈 시간에 서버를 4대에서 40대로 |
| 내구성(Durability) | 저장한 데이터가 사라지지 않는가? | S3는 객체를 여러 시설에 복제해 내구성 99.999999999% |
| 내결함성(Fault tolerance) | 부품이 고장나도 사용자가 모르고 지나가는가? | 한 대가 죽어도 나머지가 즉시 받아냄 |
헷갈리기 쉬운 건 가용성과 내구성입니다. S3가 잠시 응답하지 않아도(가용성 문제) 데이터는 그대로 남아 있습니다(내구성 유지). 내결함성은 가용성의 더 강한 버전으로, 장애 순간에도 끊김이 거의 없는 상태를 말합니다.
리전과 AZ: 고장이 퍼지는 범위를 나누기
중복을 두려면 먼저 "무엇이 한꺼번에 죽는가"를 알아야 합니다. 이 단위를 장애 도메인이라고 부릅니다. 같은 랄에 서버 두 대를 두면, 랄 전원이 나갈 때 둘 다 죽습니다.
AWS는 이 범위를 두 단계로 나눠 두었습니다.
- 가용 영역(AZ)은 전원, 냉각, 네트워크를 따로 갖춘 하나 이상의 데이터센터입니다. 같은 리전의 AZ끼리는 수 km 이상 떨어져 있어서 화재나 정전이 같이 일어날 가능성이 낮습니다. 동시에 전용 광케이블로 연결돼 있어 지연은 한 자릿수 밀리초 수준입니다.
- 리전은 서울(ap-northeast-2)처럼 지리적으로 떨어진 AZ의 묶음입니다. 리전끼리는 서로 독립적이어서, 한 리전의 큰 장애가 다른 리전으로 번지지 않습니다.
여기서 첫 번째 설계 원칙이 나옵니다. 모든 계층을 최소 두 개의 AZ에 나눠 둔다. 그리고 그림을 그려 놓고 상자 하나씩 가리며 "이게 죽으면 전체가 멈추나?"를 물어 봅니다. 그렇다고 답하는 상자가 단일 장애 지점(SPOF)입니다. EC2 한 대에 올린 DB, NAT 게이트웨이 하나, 특정 서버 디스크에만 있는 업로드 파일이 흔한 예입니다.
크게 키울까, 많이 늘릴까
부하가 늘었을 때 택할 수 있는 길은 두 가지입니다.
| 수직 확장(Scale up) | 수평 확장(Scale out) | |
|---|---|---|
| 방법 | 더 큰 인스턴스로 교체 (m5.large → m5.4xlarge) | 같은 인스턴스를 여러 대로 |
| 장점 | 코드 변경이 거의 없음 | 사실상 한계가 없고, 한 대가 죽어도 버틸 |
| 한계 | 가장 큰 인스턴스가 천장, 교체 중 재시작 | 애플리케이션이 무상태여야 함 |
수직 확장은 여전히 서버 한 대라서 확장성은 얻어도 가용성은 얻지 못합니다. 그래서 클라우드에서는 수평 확장을 기본으로 생각합니다.
문제는 수평 확장의 전제조건입니다. 로그인 세션을 서버 메모리에 두면, 다음 요청이 다른 서버로 가는 순간 사용자는 로그아웃됩니다. 업로드한 프로필 사진이 한 서버 디스크에만 있으면, 그 서버가 사라질 때 사진도 사라집니다.
해법은 서버를 무상태(Stateless)로 만드는 것입니다. 상태를 서버 밖의 공용 저장소로 옮기면 됩니다.
- 세션 → ElastiCache(Redis)나 DynamoDB
- 업로드 파일 → S3
- 업무 데이터 → RDS나 DynamoDB
이렇게 하면 어떤 서버든 어떤 요청이든 처리할 수 있습니다. 서버는 언제든 버리고 새로 만들 수 있는 소모품이 되고, 바로 이 성질이 다음 절의 자동 확장과 자가 복구를 가능하게 합니다.
로드 밸런서와 Auto Scaling: 나누고, 늘리고, 고치기
서버를 여러 대 두었다면 요청을 나눠 줄 문지기와, 서버 수를 알아서 조절할 관리자가 필요합니다. 아래 그림은 이 둘을 갖춘 가장 기본적인 2-AZ 웹 구조입니다.
로드 밸런서는 들어온 요청을 여러 서버에 나누고, 주기적으로 헬스 체크를 보내 응답하지 않는 서버를 대상에서 뺍니다. 그래서 서버 하나가 죽어도 사용자는 눈치채지 못합니다. 로드 밸런서 자체도 여러 AZ에 걸쳐 동작하므로 그 자신이 단일 장애 지점이 되지 않습니다.
| ALB | NLB | |
|---|---|---|
| 동작 계층 | L7 (HTTP/HTTPS) | L4 (TCP/UDP) |
| 무엇을 보고 나누나 | URL 경로, 호스트 이름, 헤더 | IP 주소와 포트 |
| 잘 맞는 곳 | 웹과 API, /api와 /images를 다른 서버 묶음으로 | 게임 서버, IoT, 초저지연, 고정 IP가 필요할 때 |
Auto Scaling 그룹(ASG)은 최소·희망·최대 인스턴스 수를 정해 두고, 그 범위 안에서 서버 수를 조절합니다. 조절 기준은 상황에 맞게 고릅니다.
- 대상 추적: "평균 CPU 50% 유지"처럼 목표만 주면 알아서 늘리고 줄입니다.
- 예약: 매일 오전 9시처럼 예측 가능한 피크 전에 미리 늘려 둡니다.
- 사용자 지정 지표: CPU 대신 SQS 대기열 길이처럼 업무에 더 가까운 지표를 기준으로 삼습니다.
ASG의 덜 알려진 핵심 기능은 자가 복구입니다. 헬스 체크에 실패한 인스턴스를 종료하고 새 인스턴스를 띄워 개수를 유지합니다. AZ 하나가 통째로 사라지면 남은 AZ에 인스턴스를 다시 채웁니다. 앞 절에서 서버를 무상태로 만든 이유가 바로 이것입니다.
데이터베이스: 가장 늘리기 어려운 계층
웹 서버는 무상태로 만들면 그만이지만, 데이터베이스는 상태 그 자체입니다. 그래서 가용성과 확장성을 따로 풀어야 합니다. RDS의 두 기능이 딱 그 분업을 보여 줍니다.
| RDS Multi-AZ | 읽기 복제본(Read Replica) | |
|---|---|---|
| 목적 | 가용성 | 읽기 확장 |
| 복제 방식 | 다른 AZ의 대기 DB에 동기 복제 | 비동기 복제, 약간의 지연 가능 |
| 평소 역할 | 대기 DB는 트래픽을 받지 않고 기다림 | SELECT 요청을 나눠 받음 |
| 장애 시 | DNS가 대기 DB로 자동 전환(보통 1~2분) | 수동으로 승격해야 함 |
동기 복제는 "대기 DB에도 써진 뒤에야 커밋 완료"라는 뜻이라 장애 시 데이터 손실이 없습니다. 대신 대기 DB는 평소에 놀고 있어 부하를 나눠 주지 못합니다. 읽기가 많다면 복제본을, 멈추지 않아야 한다면 Multi-AZ를, 보통은 둘 다 씁니다.
처음부터 분산을 전제로 만든 데이터베이스도 있습니다. Aurora는 저장소를 3개 AZ에 6본으로 복제하고, 최대 15개의 읽기 복제본이 같은 저장소를 공유합니다. 복제본이 곧 대기 DB 역할도 해서, 장애 시 보통 30초 안팎으로 전환됩니다. DynamoDB는 서버 개념 자체가 없고, 데이터를 파티션으로 나눠 여러 AZ에 자동 복제합니다. 사용자는 용량이나 장애 조치를 거의 신경 쓰지 않아도 됩니다.
마지막으로, 가장 싼 DB 확장은 DB에 오지 않게 하는 것입니다. 자주 읽는 상품 목록을 ElastiCache에 담아 두면 DB 부하가 크게 줄고, 이미지나 정적 파일은 CloudFront가 사용자 가까운 엣지에서 대신 응답합니다. 캐시는 폭주하는 트래픽을 앞단에서 흡수하는 충격 완화장치입니다.
리전 하나가 통째로 멈춘다면
Multi-AZ는 데이터센터 하나의 고장을 견뎌니다. 하지만 리전 전체의 장애, 실수로 지운 데이터, 랜섬웨어까지 대비하려면 재해 복구(DR) 계획이 필요합니다. 이때 목표를 두 숫자로 정합니다.
- RPO(Recovery Point Objective)는 "얼마나 예전 시점의 데이터까지 잃어도 괜찮은가"입니다. 매일 밤 백업하면 RPO는 최대 24시간입니다.
- RTO(Recovery Time Objective)는 "얼마나 오래 멈춰 있어도 괜찮은가"입니다. 복구에 4시간 걸리면 RTO는 4시간입니다.
두 숫자를 줄일수록 비용이 올라갑니다. AWS는 이 균형점을 네 단계로 설명합니다.
| 전략 | 두 번째 리전의 평소 모습 | RTO/RPO | 비용 |
|---|---|---|---|
| 백업 및 복원 | 스냅샷과 백업만 보관 | 수 시간 | 낮음 |
| 파일럿 라이트 | DB만 복제되고 서버는 꺼져 있음 | 수십 분 | 중간 이하 |
| 웜 스탠바이 | 작은 규모로 전체가 돌고 있음 | 수 분 | 중간 이상 |
| 멀티 사이트(액티브-액티브) | 운영 리전과 같은 규모로 트래픽을 받음 | 거의 0 | 높음 |
파일럿 라이트는 가스보일러의 작은 불꽃에서 온 이름입니다. 핵심 데이터만 살아 있고, 필요할 때 서버를 켜서 불을 키웁니다. 어떤 전략이 맞는지는 기술이 아니라 "한 시간 멈추면 얼마를 잃는가"라는 비즈니스 질문이 정합니다. 어느 쪽이든 복구 절차를 실제로 연습해 보기 전까지는 그 RTO를 믿을 수 없습니다.
정리: 고장을 전제로 설계하는 다섯 가지 원칙
- 고장을 가정한다. 그림의 상자마다 "이게 죽으면?"을 물어 단일 장애 지점을 없앱니다.
- 장애 도메인을 나눈다. 모든 계층을 두 개 이상의 AZ에, 필요하면 두 개 이상의 리전에 둡니다.
- 서버는 소모품으로 다룬다. 상태를 밖으로 빼고, 고치기보다 교체합니다.
- 수요를 따라 늘고 줄게 한다. 사람이 서버 수를 정하지 않고 지표가 정하게 합니다.
- 목표를 숫자로 정하고 연습한다. 가용성 목표, RTO, RPO를 정하고 장애 훈련으로 확인합니다.
고가용성은 특정 서비스의 이름이 아니라 설계 습관입니다. 다음에 아키텍처를 그릴 때 상자 하나를 손가락으로 가리고 그 질문부터 던져 보세요.