이벤트 당일 오전 10시, 트래픽이 평소 30배로 치솟습니다. 인스턴스 한 대는 CPU 100%로 헉헉대다 다운, 사용자는 에러 화면을 봅니다. 반대로 새벽 3시엔 그 큰 인스턴스가 1% 부하로 돈만 먹습니다. 한 대 고정으로는 피크에 죽고 평소엔 낭비합니다. 오토스케일링과 로드밸런서는 "필요한 만큼 자동으로, 죽은 건 알아서 빼고"를 만들어 줍니다.
- 1로드밸런서가 트래픽 분산과 헬스체크로 무엇을 해주는지 안다
- 2오토스케일링 그룹이 지표 기반으로 늘고 주는 원리를 설명할 수 있다
- 3오토스케일링의 전제인 '무상태' 설계의 이유를 안다
- 4헬스체크 경로 설계가 왜 중요한지 예로 들 수 있다
- 5탄력성이 가용성·비용에 동시에 기여하는 구조를 이해한다
분산과 자동 증감, 두 축
로드밸런서 — 단일 진입점 + 죽은 놈 빼기
로드밸런서는 사용자에게 하나의 주소를 주고, 뒤에 있는 여러 인스턴스로 트래픽을 나눕니다. 동시에 각 인스턴스에 주기적으로 헬스체크를 보내, 응답 없는 인스턴스는 라우팅에서 빼고 복귀하면 다시 넣습니다. 그래서 인스턴스 한 대가 죽거나 배포 중이어도 사용자는 거의 모릅니다.
L7(애플리케이션) 로드밸런서는 URL 경로·호스트로 라우팅(/api는 이쪽, /img는 저쪽)까지 합니다.
오토스케일링 그룹 — 지표를 보고 머릿수를 조절
오토스케일링 그룹(ASG)은 "최소 2대, 최대 10대, 평균 CPU 50% 목표" 식으로 정책을 둡니다. 부하가 올라 임계치를 넘으면 scale-out(추가), 내려가면 scale-in(제거)합니다. 새 인스턴스는 검증된 AMI([[compute-instances]])로 동일하게 찍어내고, LB가 헬스체크 통과 후 트래픽에 합류시킵니다.
핵심 전제: 인스턴스는 언제 추가·제거돼도 안전해야 합니다 — 즉 무상태여야 합니다.

왜 무상태(stateless)가 필수인가
scale-in은 인스턴스를 죽입니다. 그 인스턴스 로컬에 세션이나 업로드 파일이 있었다면 함께 사라집니다. 다른 인스턴스는 그 세션을 모르니 사용자는 로그아웃됩니다. 그래서:
- 세션 → 외부 캐시/DB(예: Redis)에 저장
- 업로드 파일 → 오브젝트 스토리지([[object-block-storage]])에 저장
- 인스턴스는 "아무 때나 죽여도 되는 일회용"으로
이 원칙을 지키면 인스턴스 수를 자유롭게 조절할 수 있습니다.
LB 뒤 인스턴스들이 healthy인지 확인합니다. 배포·스케일 직후 unhealthy가 오래 남으면 헬스체크 설정을 의심합니다.
aws elbv2 describe-target-health --target-group-arn "$TG_ARN" \
--query "TargetHealthDescriptions[].{Id:Target.Id,State:TargetHealth.State}" --output table
+----------------------+-----------+
| i-0aaa... | healthy |
| i-0bbb... | healthy |
| i-0ccc... | unhealthy| ← 조사 대상
+----------------------+-----------+
aws elbv2 describe-target-healthASG가 최소·최대·희망 용량 사이에서 어떻게 동작 중인지 봅니다.
aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names web-asg \
--query "AutoScalingGroups[0].{Min:MinSize,Max:MaxSize,Desired:DesiredCapacity,InService:length(Instances)}"
{ "Min": 2, "Max": 10, "Desired": 4, "InService": 4 }
aws autoscaling describe-auto-scaling-groups- describe-target-health에 unhealthy가 지속되는 인스턴스 — 앱 미기동인지(진짜 문제) 헬스체크 경로/타임아웃이 빡센지(오판) 구분
- DesiredCapacity vs InService 수 일치 여부 — 불일치면 인스턴스 기동 실패·헬스체크 탈락 반복(롤링 폭주) 의심
- scale 이벤트 로그의 빈도 — 짧은 시간에 늘었다 줄었다 반복(flapping)하면 임계치·쿨다운이 너무 민감. 쿨다운 늘리기
- scale-in 시 사용자 로그아웃/업로드 유실 신고 — 상태가 인스턴스 로컬에 남아 있다는 신호. 외부 저장소로 분리
상황: 새 인스턴스가 헬스체크를 통과 못 해 LB가 빼고, ASG가 죽이고 또 띄우는 루프.
원인: ① 헬스체크 경로(/health)가 앱 준비 전에 호출됨(기동 시간 < 체크 시작), ② 경로가 200을 안 줌(앱 버그/포트 불일치), ③ 보안그룹이 LB→인스턴스 헬스체크 포트를 안 허용.
진단: 인스턴스에 직접 들어가 curl localhost:<port>/health 응답 확인 → LB 대상그룹 헬스체크 경로·포트·정상 임계 확인 → 보안그룹에서 LB SG로부터의 인바운드 허용 확인.
해결: 헬스체크에 시작 유예(health check grace period) 를 둬 기동 시간을 확보. 경로를 가볍고 정확한 /health로. 보안그룹에 LB로부터의 헬스체크 포트 인바운드 추가. 헬스체크 설계는 [[slo-error-budget]]의 가용성 측정과도 연결됩니다.
면접 단골: "트래픽이 급증하면 어떻게 대응하나요?" → "오토스케일링 그룹으로 지표 기반 증설하고 앞에 로드밸런서를 둔다. 단, 앱을 무상태로 만들어 세션은 외부 캐시, 파일은 오브젝트 스토리지에 둔다"가 좋은 답입니다.
실무 함정: 오토스케일링은 만능이 아닙니다. 인스턴스 기동에 수 분이 걸리면 갑작스런 스파이크는 못 따라잡습니다(예측 스케일링·여유 용량 필요). 또 DB가 병목이면 웹 인스턴스만 늘려도 소용없습니다 — 병목 지점을 먼저 찾아야 합니다([[managed-database]]).
다음 모듈에서는 이 인스턴스·LB가 사는 네트워크 자체 — VPC·서브넷·라우팅·게이트웨이 로 들어가, 퍼블릭과 프라이빗을 어떻게 나누는지 다룹니다.