기준: SOA-C02 시험 가이드오류 제보
시험을 코앞에 두고 도메인을 "복습"한다는 건 보통 표를 다시 외우는 일로 끝난다. 하지만 SOA-C02 도메인 1(모니터링·로깅·수정 20%)과 도메인 2(안정성·BCP 16%)는 사실 하나의 운영 루프를 앞뒤로 자른 것이다 — 관측해서 이상을 잡고(도메인 1), 그 이상이 장애로 번지기 전에 시스템이 스스로 견디게 만드는 것(도메인 2). 둘을 따로 외우면 시험의 시나리오 문제, 즉 "관측 → 감지 → 대응 → 복구 → 감사"가 한 문장에 섞여 나오는 문제에서 길을 잃는다.
이 글은 두 도메인의 키워드 표를 그냥 나열하는 대신, 각 서비스가 왜 그렇게 설계됐는지, CloudWatch의 메트릭이 실제로 어떤 시간 해상도로 저장되는지, CloudTrail과 Config가 근본적으로 다른 데이터 모델을 쓰는 이유, 그리고 RTO/RPO라는 BCP의 두 숫자가 어디서 왔는지를 파고든다. 복습이되, 한 겹 더 깊은 복습이다.
"모니터링"과 "Observability(관측가능성)"는 흔히 같은 말로 쓰이지만 출신이 다르다. Observability는 1960년 제어 이론가 루돌프 칼만(Rudolf Kálmán)이 정의한 개념이다 — 시스템의 외부 출력만 보고 내부 상태를 얼마나 추론할 수 있는가가 그 시스템의 observability다. 칼만은 동시에 controllability(제어가능성)도 정의했는데, 이 둘은 현대 제어 시스템 설계의 양대 축이다.
이 정의를 클라우드 운영에 옮기면 핵심이 분명해진다. 모니터링은 "내가 미리 정해둔 질문에 답하는 것"이다 — CPU가 80%를 넘는가? 디스크가 가득 찼는가? 반면 Observability는 "미리 예상하지 못한 질문에도 답할 수 있는 능력"이다. 운영에서 진짜 무서운 장애는 항상 예상 밖에서 온다. 그래서 Metric(무엇이 얼마나)·Log(무슨 일이 있었나)·Trace(요청이 어디를 거쳤나) 세 축을 모두 남겨두는 것이다 — 세 축이 충분히 풍부하면, 장애가 터진 뒤에도 외부 신호만으로 내부에서 무슨 일이 있었는지 역추적할 수 있다.
💡 관련 이론: Observability 3축(Metric/Log/Trace)은 각각 데이터의 차원이 다르다. Metric은 시간에 따른 숫자(시계열)로, 저장 비용이 가장 싸고 집계가 빠르지만 "왜"를 모른다. Log는 이산 이벤트(텍스트)로, 맥락이 풍부하지만 양이 많고 검색이 비싸다. Trace는 분산 시스템에서 하나의 요청이 여러 서비스를 거친 인과 사슬로, 마이크로서비스의 병목을 찾는 유일한 수단이다. 이 셋은 카디널리티(cardinality, 고유 값의 수) 측면에서 다르게 다뤄야 한다 — 메트릭에 user_id 같은 고카디널리티 차원을 dimension으로 넣으면 시계열이 폭발해 비용이 치솟는다. 그래서 AWS는 고카디널리티 정보는 로그(Logs Insights)나 X-Ray Trace로 밀고, 메트릭 dimension은 의도적으로 낮은 카디널리티(인스턴스 타입, AZ 등)로 제한하도록 설계됐다.
CloudWatch를 "복습"할 때 대부분 표준 메트릭 5분/Detailed 1분만 외운다. 하지만 그 숫자 뒤에는 CloudWatch의 내부 저장 모델이 있고, 시험은 이 모델의 결과(데이터 보존·해상도·비용)를 묻는다.
EC2 표준 메트릭은 기본 5분 간격이다. Detailed Monitoring을 켜면 1분으로 내려가지만 추가 요금이 붙는다. 그런데 PutMetricData로 직접 올리는 커스텀 메트릭은 고해상도(high-resolution), 즉 1초 단위까지 가능하다. 이 1분과 1초 사이의 차이는 단순한 옵션이 아니라 CloudWatch가 데이터를 자동으로 다운샘플링하는 구조와 얽혀 있다.
CloudWatch는 데이터를 시간이 지날수록 거친 해상도로 굴린다. 1초 해상도 데이터는 3시간만 보관하고, 1분 데이터는 15일, 5분 데이터는 63일, 1시간 데이터는 455일(15개월) 보관한다. 즉 오래된 데이터를 조회하면 자동으로 더 큰 시간 단위로 집계된 값만 남는다. 이건 시계열 데이터베이스의 보편적 패턴인 roll-up(롤업)이다 — 세밀한 데이터는 비싸므로 최근 것만 세밀하게, 옛날 것은 거칠게 보관해 저장 비용과 조회 성능을 맞춘다.
| 해상도 | 보존 기간 | 용도 |
|---|---|---|
| 1초 (high-res custom) | 3시간 | 급격한 스파이크 포착 (예: 배포 직후 1초 단위 지연) |
| 1분 | 15일 | 일반 운영 알람 |
| 5분 | 63일 | 표준 EC2 메트릭, 주간 추세 |
| 1시간 | 455일 (15개월) | 장기 용량 계획 |
고해상도 메트릭의 진짜 함정은 알람 평가 주기에 있다. 표준 메트릭으로 만든 알람은 최소 60초 주기로 평가하지만, 고해상도(1초) 메트릭에는 10초·30초 주기 알람을 걸 수 있다. 빠른 알람은 더 빠른 대응을 가능케 하지만, 짧은 평가 주기는 일시적 스파이크에 과민 반응해 알람이 펄럭이는(flapping) 문제를 낳는다. 그래서 실무에서는 고해상도 알람에 "M of N" 데이터포인트 조건(예: 최근 5개 평가 중 3개가 위반)을 걸어 노이즈를 흡수한다. 시험에서 "급격한 트래픽 스파이크를 더 빠르게 감지"가 나오면 고해상도 커스텀 메트릭 + 짧은 평가 주기가 단서지만, "알람이 너무 자주 울린다"가 나오면 M-of-N 또는 평가 주기 조정이 답이다.
시험에서 틀리기 쉬운 쌍이 CloudTrail과 Config다. "누가 삭제했나 = CloudTrail, 이전 설정은 = Config"로 암기하면 표면은 맞지만, 둘이 왜 다른지를 모르면 변형 문제에서 무너진다. 핵심은 두 서비스가 기록하는 데이터의 본질이 다르다는 것이다.
CloudTrail은 이벤트 기반(event-sourced) 모델이다. AWS API가 호출될 때마다 "누가(principal), 언제(timestamp), 무엇을(eventName), 어디서(sourceIPAddress)" 하나의 이벤트를 남긴다. 이건 동사(verb)의 기록이다 — TerminateInstances, DeleteBucket, AttachRolePolicy. CloudTrail에게 "지금 이 인스턴스의 상태"를 물어볼 수는 없다. CloudTrail은 행위의 흐름만 알 뿐, 리소스의 현재 모습은 모른다.
Config는 상태 기반(state-snapshot) 모델이다. 리소스가 변경될 때마다 그 리소스의 전체 구성 스냅샷을 찍어 타임라인으로 쌓는다. 이건 명사(noun)의 기록이다 — "이 보안 그룹은 14:00 시점에 이런 규칙들을 가지고 있었다". 그래서 Config에게는 "3일 전 이 SG의 인바운드 규칙은?"을 물을 수 있다. 대신 Config는 "누가 그 변경을 했는지"를 직접 알려주진 않는다(그 답은 CloudTrail에 있다).
| CloudTrail | Config | |
|---|---|---|
| 데이터 모델 | 이벤트 소싱 (API 호출 스트림) | 상태 스냅샷 (구성 타임라인) |
| 기록 단위 | 동사 (행위) | 명사 (리소스 상태) |
| 답하는 질문 | "누가 언제 무엇을 했나" | "이 리소스는 그때 어떤 모습이었나" |
| 컴플라이언스 | 감사 추적 (audit trail) | 규칙 평가 (Config Rule) |
| 자동 수정 | 직접 없음 (EventBridge 경유) | Remediation (SSM Automation) |
이 둘은 경쟁 관계가 아니라 보완 관계다. 실제 인시던트 조사에서는 Config로 "언제 잘못된 상태가 됐는지"를 타임라인에서 찾고, 그 시점을 CloudTrail에서 검색해 "누가 그 API를 호출했는지"를 알아낸다. 두 데이터 모델이 만나야 완전한 이야기가 된다.
2019년 Capital One 데이터 유출 사고는 이 두 축의 가치를 보여준 대표 사례다. 한 전직 AWS 직원이 잘못 설정된 WAF(웹 방화벽)를 통해 SSRF 공격으로 EC2 인스턴스 메타데이터의 IAM 자격증명을 탈취하고, 그 권한으로 S3 버킷에서 약 1억 600만 명의 신용카드 신청 데이터를 빼냈다. 사후 조사에서 CloudTrail 로그가 ListBuckets와 대량 GetObject 호출의 비정상 패턴을 보여줬고, 이것이 침해 범위 산정의 핵심 증거가 됐다. 교훈은 두 가지였다 — ① CloudTrail이 켜져 있어야 사후 추적이 가능하다(끄면 증거가 없다), ② GuardDuty 같은 실시간 위협 탐지가 있었다면 이 비정상 API 패턴을 공격 진행 중에 잡았을 것이다. 그래서 SOA 시험은 "조직 전체 CloudTrail + GuardDuty 상시 활성화"를 거의 기본 모범사례로 다룬다.
도메인 1의 "수정(Remediation)"은 단순히 "Config Rule + SSM Automation"으로 외우고 끝낼 수 없다. 자동 수정의 진짜 난제는 같은 수정이 여러 번 실행돼도 안전한가, 즉 멱등성(idempotency)이다.
자동 수정은 보통 이벤트에 반응한다 — Config Rule이 비준수를 감지하면 Remediation을 호출하고, 그 Remediation이 SSM Automation Document를 실행한다. 문제는 분산 시스템에서 이벤트가 정확히 한 번(exactly-once) 전달된다는 보장이 거의 없다는 점이다. EventBridge도, SQS도 기본은 최소 한 번(at-least-once) 전달이다 — 즉 같은 이벤트가 중복 전달될 수 있다. 만약 "S3 버킷을 비공개로 바꾼다"는 수정이 멱등하지 않게 짜여 있다면(예: 매번 새 정책을 append), 중복 실행은 정책을 망가뜨릴 수 있다.
그래서 잘 설계된 Remediation Document는 선언적이다 — "이 상태가 되도록 보장하라(ensure)"는 식이지 "이걸 추가하라(add)"는 식이 아니다. "퍼블릭 액세스 차단을 켠다"는 수정은 이미 켜져 있어도 다시 켜는 것이 무해하므로 멱등하다. 이것이 SSM State Manager가 "원하는 상태(desired state)를 유지"하는 association 모델로 설계된 이유이기도 하다 — 매 주기 현재 상태를 원하는 상태로 수렴시키되, 이미 맞으면 아무것도 하지 않는다.
멱등성은 자동화 시스템 설계의 기둥이다. HTTP에서도 GET·PUT·DELETE는 멱등(같은 요청을 여러 번 보내도 결과 동일)하지만 POST는 멱등하지 않다고 정의한다(RFC 7231). 인프라 자동화 도구들(Ansible, Terraform, SSM)이 모두 "선언적·멱등적"을 지향하는 이유가 여기 있다 — 명령형("이걸 실행해")은 중복·재시도에 취약하지만, 선언형("이 상태가 되게 해")은 몇 번을 돌려도 같은 결과로 수렴한다. 자동 복구 루프를 짤 때 "이 액션이 두 번 실행돼도 괜찮은가?"를 먼저 물어야 하는 이유다. 괜찮지 않다면 그 자동화는 장애를 막기는커녕 키운다.
도메인 2는 결국 두 개의 숫자로 압축된다. RTO(Recovery Time Objective)는 "장애 후 얼마나 빨리 복구해야 하는가"(시간의 길이), RPO(Recovery Point Objective)는 "얼마만큼의 데이터 손실까지 용인하는가"(과거로 거슬러 가는 시점)다. 이 둘은 독립적인 축이고, DR 전략 4종은 이 2차원 평면 위의 좌표다.
RPO는 백업 주기로 결정된다. 6시간마다 백업하면 최악의 경우 장애 직전 6시간치 데이터를 잃는다(RPO = 6시간). RPO를 0에 가깝게 하려면 동기 복제나 연속 복제가 필요하다. RTO는 복구 절차의 속도로 결정된다. 백업에서 통째로 복원하면 몇 시간 걸리지만, 이미 떠 있는 대기 환경으로 전환만 하면 몇 분이다.
| 전략 | RTO | RPO | 비용 | 핵심 메커니즘 |
|---|---|---|---|---|
| Backup & Restore | 시간 단위 | 시간 단위 | 가장 저렴 | 백업만 보관, 장애 시 복원 |
| Pilot Light | 10분~수십분 | 분 단위 | 중간 | 핵심(DB)만 상시 복제, 나머지는 꺼둠 |
| Warm Standby | 분 이내 | 초~분 | 비쌈 | 축소판 전체 스택 상시 가동, 장애 시 확장 |
| Multi-Site Active-Active | ~0 | ~0 | 가장 비쌈 | 모든 리전이 항상 트래픽 처리 |
핵심 trade-off는 명확하다 — RTO·RPO를 0에 가깝게 할수록 비용이 기하급수적으로 오른다. Active-Active는 RTO/RPO 0에 수렴하지만 인프라를 두 배로 상시 가동해야 한다. 시험은 거의 항상 "비용 대비 적정한 전략"을 묻는다 — "분 단위 복구 + 적당한 비용"이면 Pilot Light, "거의 무중단 + 비용 감수"면 Warm Standby나 Active-Active다.
⚠️ 함정: RTO와 RPO를 섞어 쓰면 답이 틀린다. "데이터 손실을 최소화"는 RPO 이야기(복제 주기), "다운타임을 최소화"는 RTO 이야기(전환 속도)다. 예를 들어 "금융 거래라 단 1건의 데이터 손실도 안 된다"면 RPO≈0이 요구되어 동기 복제(Multi-AZ 동기, Aurora 연속 백업)가 필요하고, "복구가 몇 시간 걸려도 되지만 데이터는 다 살려야 한다"면 RPO는 작되 RTO는 커도 되므로 Backup & Restore로 충분하다. 두 숫자가 따로 주어졌을 때 어느 쪽이 비싼 메커니즘을 강제하는지 보는 것이 함정 회피의 핵심이다.
도메인 2에서 두 번째로 많이 틀리는 쌍이 RDS Multi-AZ와 Read Replica다. 둘 다 "데이터를 복제한다"는 점은 같지만, 무엇을 위해 복제하느냐가 정반대다 — 그리고 그 목적 차이가 동기/비동기라는 복제 방식의 차이로 직결된다.
Multi-AZ는 고가용성(HA)을 위한 복제다. 같은 리전의 다른 AZ에 standby 복제본을 두고 동기식(synchronous)으로 복제한다 — primary에 쓰기가 일어나면 standby에도 기록이 확정된 뒤에야 클라이언트에 성공을 응답한다. 그래서 primary가 죽어도 standby는 단 1건의 손실 없이(RPO≈0) 이어받는다. 대신 동기 복제는 매 쓰기마다 네트워크 왕복을 기다리므로 약간의 쓰기 지연을 감수한다. 그리고 standby는 평소에 트래픽을 받지 않는다 — 순수하게 대기만 한다(읽기 확장이 아니다).
Read Replica는 읽기 성능 확장을 위한 복제다. 비동기식(asynchronous)으로 복제한다 — primary는 자기 쓰기를 마치고 곧바로 응답하며, 복제는 백그라운드에서 따라간다. 그래서 복제 지연(replication lag)이 존재하고, replica는 항상 primary보다 약간 과거의 데이터를 본다. 대신 비동기라 primary의 쓰기 성능에 거의 영향을 안 주고, replica를 여러 개 두어 읽기 부하를 분산할 수 있다.
동기 vs 비동기 복제는 분산 시스템의 근본 trade-off인 CAP 정리와 연결된다. 동기 복제(Multi-AZ)는 일관성(Consistency)을 우선해 모든 복제본이 같은 데이터를 보장하지만, 그 대가로 지연이 늘고 네트워크 분단 시 가용성이 흔들릴 수 있다. 비동기 복제(Read Replica)는 가용성·성능을 우선하지만 일시적으로 복제본이 뒤처지는 약한 일관성(eventual consistency)을 허용한다. 그래서 "방금 쓴 데이터를 곧바로 읽어야 하는" 워크로드를 Read Replica로 보내면 lag 때문에 옛 데이터를 읽는 버그가 난다 — 이건 read-after-write consistency가 깨진 전형적 사례다. Aurora는 공유 스토리지 구조로 이 lag를 보통 수십 밀리초 이내로 줄였지만, 0은 아니다. 시험에서 "읽기 일관성이 중요한데 Read Replica를 썼더니 옛 데이터가 보인다"가 나오면 답은 "복제 지연 — 일관성이 필요한 읽기는 primary로 보내야 한다"이다.
도메인 1과 2는 "관측해서 견딘다"는 하나의 운영 철학을 앞뒤로 나눈 것이다. 키워드 표를 외우되, 그 뒤의 설계 의도를 잡으면 변형 문제가 풀린다.
정리하면 다섯 가지다. ① Observability는 "예상 못 한 질문에도 답하는 능력"이고, Metric·Log·Trace는 카디널리티가 달라 다르게 다뤄야 한다. ② CloudWatch 메트릭은 시간이 지나면 자동 롤업되며, 고해상도(1초)는 빠른 알람을 주지만 노이즈는 M-of-N으로 흡수한다. ③ CloudTrail은 동사(API 행위)의 이벤트 스트림, Config는 명사(리소스 상태)의 스냅샷 타임라인 — 둘은 보완 관계다. ④ 자동 수정은 멱등성이 생명이다 — 선언적("이 상태가 되게 하라")이어야 중복 실행에 안전하다. ⑤ DR은 RTO(복구 속도)와 RPO(손실 허용)라는 두 축의 좌표 위에 있고, 0에 가까울수록 비용이 폭증한다. RDS는 Multi-AZ(동기·HA)와 Read Replica(비동기·읽기 확장)가 복제 철학부터 다르다.
다음 글에선 도메인 3(배포·자동화)과 도메인 4(보안)를 같은 깊이로 다시 읽는다 — CloudFormation이 왜 멱등적인지, IAM 정책 평가가 어떤 순서로 결정되는지, 그리고 Session Manager가 SSH를 대체하는 내부 메커니즘을 파고든다.
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
운영팀이 배포 직후 1초 단위로 치솟는 짧은 지연 스파이크를 포착하려 한다. 그런데 평소엔 그 메트릭이 5분 단위로만 기록된다. 가장 적절한 접근은?
문제 2
한 S3 버킷이 어느 시점부터 퍼블릭으로 바뀌어 있었다. ① 언제 그 상태가 됐는지 타임라인으로 보고, ② 누가 그 변경 API를 호출했는지를 알아내야 한다. 각각 어떤 서비스를 쓰나?
문제 3
Config Rule의 자동 수정(Remediation)이 이벤트 중복 전달로 같은 SSM Document를 두 번 실행했는데, 두 번째 실행이 리소스 구성을 망가뜨렸다. 근본 원인과 올바른 설계 원칙은?
문제 4
금융 거래 DB라 단 1건의 데이터 손실도 허용되지 않지만(RPO≈0), 복구가 몇 분 걸리는 건 용인된다. 가장 적합한 RDS 구성은?
문제 5
애플리케이션이 데이터를 쓰자마자 곧바로 다시 읽는데, 읽기를 Read Replica로 보냈더니 가끔 방금 쓴 데이터가 안 보인다. 원인과 해결은?
문제 6
회사가 "리전 전체 장애 시 거의 무중단(RTO 수분 이내) + 데이터 손실 거의 0"을 요구하지만, 비용은 가능한 한 아끼고 싶다. 평소 트래픽은 한 리전이면 충분하다. 가장 균형 잡힌 DR 전략은?
문제 7
Observability를 "예상하지 못한 질문에도 답할 수 있는 능력"으로 본다면, 메트릭 dimension에 user_id처럼 고유 값이 수백만 개인 차원을 넣는 것이 왜 권장되지 않는가?