콘텐츠로 이동

CloudWatch Basics

분류: Layer 6 - 운영 심화: 관측성 & 복원력

Amazon CloudWatch는 AWS 리소스와 애플리케이션에서 나오는 로그, 지표, 알람, 대시보드를 모아 운영자가 서비스 상태를 판단하게 해주는 AWS 관리형 관측 서비스다.

여기서 관측은 “화면에 그래프를 띄우는 일”보다 넓다. 서비스가 느려졌는지 감지하고, 어느 리소스나 작업 경로가 의심스러운지 좁히고, 필요한 사람이나 자동화 경로로 알리는 과정까지 포함한다.

2. 선행 기술의 한계 - 리소스가 늘어나면 상태가 흩어진다

섹션 제목: “2. 선행 기술의 한계 - 리소스가 늘어나면 상태가 흩어진다”

작은 애플리케이션은 서버 한 대의 stdout, 프로세스 상태, 간단한 에러 로그만 봐도 어느 정도 운영할 수 있다. 하지만 AWS 위에서 API 서버, Worker, SQS, RDS, Lambda, ALB, ECS 태스크가 같이 움직이면 상태가 여러 콘솔과 여러 파일로 흩어진다. 장애가 났을 때 “CPU가 높은가”, “큐가 밀렸는가”, “로그가 끊겼는가”, “알림 경로가 죽었는가”를 매번 서비스별로 찾아야 한다.

CloudWatch는 이 한계를 줄이기 위해 AWS 서비스가 내보내는 신호를 공통 형식으로 수집한다. EC2 CPU, RDS 연결 수, SQS backlog, ECS 서비스 CPU, 애플리케이션 로그처럼 출처가 다른 데이터를 같은 시간축 위에서 보게 만들고, 임계값을 넘으면 Alarm을 통해 SNS나 EventBridge로 넘긴다.

프론트엔드에서 Network 탭으로 느린 요청을 찾는다면, CloudWatch는 서버와 AWS 리소스 관점에서 그 요청 뒤의 CPU, 큐, 로그, 알람 상태를 보는 출발점이다.

CloudWatch의 핵심 철학은 “AWS 리소스와 서비스 신호를 관리형 방식으로 먼저 보이게 한다”에 가깝다.

  • 애플리케이션마다 관측 스택을 직접 설치하기 전에 AWS 기본 지표를 바로 볼 수 있게 한다.
  • 로그와 지표를 같은 시간축에서 보고, 중요한 지표는 Alarm으로 운영 액션에 연결한다.
  • 리전별 저장과 AWS 서비스별 네임스페이스로 장애 범위와 데이터 범위를 나눈다.
  • 세밀한 관측이 필요할수록 커스텀 지표, 고해상도 지표, Metric Filter, Container Insights 같은 기능을 단계적으로 더한다.

이 철학 때문에 CloudWatch는 AWS 단일 환경의 기본 선택지로 강하다. 반대로 멀티클라우드 전체 관측, 복잡한 PromQL 기반 분석, 코드 수준 APM과 프로파일링까지 한 도구에서 끝내려는 요구에는 단독으로 부족할 수 있다.

CloudWatch 문서를 읽을 때는 서비스 이름보다 데이터 모델을 먼저 잡는 편이 쉽다.

용어첫 정의왜 필요한가
CloudWatch Metrics시간에 따라 쌓이는 숫자 데이터다. CPU 사용률, 요청 수, 에러 수, 큐 길이처럼 그래프로 비교할 수 있는 값이다.”느린가”, “늘었는가”, “줄었는가”를 빠르게 감지한다.
CloudWatch Logs애플리케이션이나 AWS 서비스가 남긴 텍스트 이벤트다.숫자가 이상해졌을 때 원인 후보와 요청 단서를 찾는다.
CloudWatch Alarms특정 지표가 조건을 만족하는지 주기적으로 평가하는 상태 기계다.사람이 계속 대시보드를 보지 않아도 상태 전환을 알림이나 자동화로 보낸다.
Dashboard여러 지표와 로그 위젯을 한 화면에 배치한 운영 화면이다.배포 직후나 장애 중에 공통 상황판을 만든다.
SNS(Simple Notification Service)Alarm 알림을 이메일, Slack 연동, 온콜 시스템 같은 구독자에게 fan-out하는 AWS 메시징 서비스다.Alarm 상태 변화가 사람에게 도달하는 기본 알림 경로가 된다.
EventBridgeAWS 서비스의 상태 변화 이벤트를 규칙으로 받아 다른 서비스나 자동화로 넘기는 이벤트 버스다.Alarm, ECS 태스크 상태 변화, 배포 이벤트를 후속 진단이나 자동화와 연결한다.
Namespace지표가 속한 논리적 묶음이다. 예: AWS/EC2, AWS/ECS, MyApp/Search.지표 이름 충돌을 막고 출처를 구분한다.
Dimension지표를 더 세부적으로 나누는 key-value다. 예: ServiceName=api, Environment=prod.같은 지표를 서비스, 환경, 인스턴스별로 필터링한다.
Period지표를 집계하는 시간 간격이다. 예: 60초, 5분.너무 짧으면 노이즈가 많고, 너무 길면 감지가 느려진다.
StatisticPeriod 안의 여러 샘플을 어떻게 요약할지 정하는 방식이다. 예: Average, Sum, Maximum, p95.CPU 평균, 에러 합계, 지연 p95처럼 질문에 맞는 숫자를 만든다.
Evaluation windowAlarm이 판단에 사용하는 시간 범위다. 보통 Period x Evaluation periods로 생각한다.일시 스파이크와 지속 장애를 구분한다.
Datapoints to alarmN개 평가 지점 중 M개가 조건을 위반해야 ALARM으로 바꿀지 정하는 값이다.1 out of 1은 빠르지만 시끄럽고, 3 out of 5는 느리지만 안정적이다.
High-resolution metric1초 단위로 저장할 수 있는 커스텀 지표다.빠른 감지가 필요할 때 쓰지만 비용과 노이즈가 늘어난다.
Metric Filter로그 패턴을 숫자 지표로 바꾸는 CloudWatch Logs 기능이다.worker_job_failed 로그를 WorkerJobFailureCount 지표로 바꿔 Alarm에 연결한다.
Log Group / Log StreamLog Group은 서비스나 앱 단위 로그 묶음이고, Log Stream은 컨테이너, 태스크, 인스턴스 같은 실행 단위의 로그 흐름이다.”어느 서비스의 어느 실행 단위에서 난 로그인가”를 나눈다.
Retention로그를 얼마나 오래 보관할지 정하는 기간이다.보관 기간이 없으면 장애 분석에는 편하지만 비용이 계속 쌓인다.
Logs InsightsCloudWatch Logs를 쿼리하는 분석 기능이다.시간 범위, 필터, 집계로 에러 로그와 패턴을 빠르게 찾는다.
Container InsightsECS, EKS, 컨테이너 워크로드의 CPU, 메모리, 네트워크, 태스크 수 같은 세부 지표를 수집하는 기능이다.기본 서비스 지표로는 안 보이는 컨테이너 단위 병목을 본다.
Missing dataAlarm 평가 시 해당 Period에 데이터가 없는 상태다.서비스가 멈춘 것인지, 트래픽이 없는 것인지, 수집이 끊긴 것인지 해석해야 한다.
CardinalityDimension 조합의 고유 개수다.userId 같은 값을 Dimension에 넣으면 지표 수와 비용이 폭증한다.

처음에는 이 표를 외우기보다 “숫자 신호는 Metrics, 텍스트 단서는 Logs, 자동 판단은 Alarms, 전체 상황판은 Dashboards”라고 잡으면 된다.

4. CloudWatch가 동작하는 기본 흐름

섹션 제목: “4. CloudWatch가 동작하는 기본 흐름”

CloudWatch는 한 번에 모든 것을 마법처럼 이해하는 도구가 아니다. 신호를 수집하고, 저장하고, 집계하고, 조건을 평가하고, 상태 변화를 외부로 전달하는 파이프라인이다.

CloudWatch 수집에서 알림까지
flowchart TD
Source["AWS 서비스 또는 애플리케이션"] --> Metrics["Metrics: 숫자 지표"]
Source --> Logs["Logs: 텍스트 이벤트"]
Metrics --> Store["리전별 지표 저장소"]
Logs --> Group["Log Group / Log Stream"]
Group --> Insights["Logs Insights 검색"]
Group --> Filter["Metric Filter"]
Filter --> CustomMetric["로그에서 커스텀 지표 생성"]
Store --> Eval["Alarm 평가: Period, Statistic, M out of N"]
CustomMetric --> Eval
Eval --> State["OK / ALARM / INSUFFICIENT_DATA"]
State --> SNS["SNS 알림"]
State --> EventBridge["EventBridge 상태 변경 이벤트"]
SNS --> Human["Slack / 이메일 / 온콜"]
EventBridge --> Automation["자동화 또는 후속 워크플로"]

이 흐름에서 중요한 점은 Alarm이 “로그 한 줄을 보고 즉시 울리는 기능”이 아니라는 것이다. Alarm은 지표를 일정 Period마다 집계하고 조건을 평가한 뒤 상태를 바꾼다. 로그에서 바로 알람을 만들고 싶다면 먼저 Metric Filter로 로그 패턴을 지표로 바꾸어야 한다.

Managed observability가 해결하는 문제

섹션 제목: “Managed observability가 해결하는 문제”

CloudWatch는 직접 Prometheus 서버, 로그 수집기, 알림 시스템을 운영하지 않아도 AWS 기본 신호를 빠르게 볼 수 있게 해준다. 이 장점은 L6에서 특히 중요하다. Queue, Worker, Redis, 이벤트 기반 구조가 늘어나면 문제가 하나의 요청 처리 함수 안에 머물지 않는다. API 응답 지연, SQS backlog, ECS 태스크 재시작, RDS 연결 수, 애플리케이션 ERROR 로그를 같은 시간대에 놓고 봐야 한다.

다만 CloudWatch가 “관측성 전체”를 대신하지는 않는다. 요청 하나가 여러 서비스와 함수를 거쳐 어디서 느려졌는지 보려면 분산 추적이 필요하고, 코드 함수별 CPU 병목을 보려면 프로파일링 도구가 필요하다. CloudWatch는 AWS 신호의 기본 수집과 운영 판단의 시작점이다.

5. Metrics: 숫자 신호를 시간축에 저장한다

섹션 제목: “5. Metrics: 숫자 신호를 시간축에 저장한다”

Metric은 시간에 따라 기록되는 숫자다. CPUUtilization=78%, RequestCount=1200, ApproximateNumberOfMessagesVisible=450, SearchSuccess=840 같은 값이 Metric이 된다.

CloudWatch Metric은 보통 아래 네 가지를 같이 이해해야 한다.

구성 요소예시읽는 법
NamespaceAWS/ECS, AWS/RDS, MyApp/Search어느 서비스나 앱에서 온 지표인가
Metric nameCPUUtilization, DatabaseConnections, SearchSuccess무엇을 측정하는가
DimensionClusterName=prod, ServiceName=api, Environment=production어떤 하위 단위로 나누어 볼 것인가
Timestamp와 value2026-04-07T10:00:00Z, 82.5어느 시각에 값이 얼마였는가

Worked example: 검색 성공 커스텀 지표

섹션 제목: “Worked example: 검색 성공 커스텀 지표”

팀이 검색 API의 성공 건수를 보고 싶다고 하자. CloudWatch 기본 AWS 지표에는 “우리 서비스에서 검색이 몇 건 성공했는지”가 없다. 이때 애플리케이션이 커스텀 지표를 보낸다.

import {
CloudWatchClient,
PutMetricDataCommand,
} from "@aws-sdk/client-cloudwatch";
const client = new CloudWatchClient({ region: "ap-northeast-2" });
await client.send(
new PutMetricDataCommand({
Namespace: "MyApp/Search",
MetricData: [
{
MetricName: "SearchSuccess",
Dimensions: [
{ Name: "Environment", Value: "production" },
{ Name: "ServiceName", Value: "search-api" },
],
Value: 1,
Unit: "Count",
},
],
}),
);

이 예제에서 Namespace는 앱의 지표 묶음이고, MetricName은 측정 이름이며, Dimensions는 조회 축이다. Environment=productionServiceName=search-api 정도는 안전한 축이다. 반대로 userId, searchQuery, requestId를 Dimension에 넣으면 고유 조합이 너무 많이 생긴다.

CloudWatch에서 Dimension 조합이 달라지면 별도 시계열로 취급된다. 그래서 Dimension은 “나중에 필터링하고 싶은 값”이 아니라 “장기적으로 관리할 수 있는 낮은 개수의 축”이어야 한다.

설계조합 수 감각문제
Environment 3개 x ServiceName 10개 x Status 2개60개 시계열관리 가능하다.
위 조합에 Region 3개 추가180개 시계열여전히 예측 가능하다.
위 조합에 userId 100,000개 추가18,000,000개 시계열 가능성비용, 조회, 알람 관리가 폭발한다.
requestId를 Dimension에 추가요청 수만큼 계속 증가지표가 아니라 로그나 트레이스에서 찾아야 할 값이다.

가격표의 숫자는 바뀔 수 있으므로 금액은 공식 가격 페이지에서 확인해야 한다. 하지만 학습할 때 중요한 직관은 안정적이다. Dimension은 곱셈으로 늘어나고, 높은 Cardinality는 비용과 운영 복잡도를 같이 키운다.

Period와 Statistic을 잘못 고르면 결론이 바뀐다

섹션 제목: “Period와 Statistic을 잘못 고르면 결론이 바뀐다”

같은 데이터라도 Period와 Statistic에 따라 다른 이야기가 된다.

질문적합한 Statistic이유
”요청 수가 늘었는가”SumPeriod 안의 총량이 중요하다.
”CPU가 지속적으로 높았는가”Average 또는 Maximum평균 부하와 순간 피크를 구분해야 한다.
”사용자 지연이 나빠졌는가”p95, p99평균은 일부 느린 사용자를 숨긴다.
”에러가 한 번이라도 있었는가”Sum 또는 MaximumCount 지표의 합계나 최대값이 유용하다.

예를 들어 1분 동안 응답시간 샘플이 80ms, 90ms, 100ms, 120ms, 3000ms라면 평균은 약 678ms다. 평균만 보면 “조금 느림”처럼 보일 수 있지만, 한 요청은 3초가 걸렸다. 사용자 영향이 tail latency에 몰리는 API라면 p95나 p99가 더 맞는 질문일 수 있다.

CloudWatch의 일반적인 지표는 60초 단위로 보는 경우가 많다. High-resolution metric은 1초 단위로 커스텀 지표를 저장할 수 있게 해준다. 짧은 장애를 빨리 잡아야 하는 결제 승인, 실시간 입찰, 짧은 배치 작업 같은 경우에는 유용할 수 있다.

하지만 첫 선택으로 쓰면 안 된다. 1초 단위는 더 많은 데이터 포인트를 만들고, 더 빠른 Alarm은 노이즈도 같이 키운다. 대부분의 API와 Worker는 먼저 60초 Period로 시작하고, “1분 감지로는 실제 사용자 피해를 줄이기에 늦다”는 근거가 있을 때만 고해상도 지표를 검토한다.

EC2의 Basic Monitoring, Detailed Monitoring, high-resolution custom metric은 서로 다른 축이다. Basic Monitoring은 EC2 기본 지표를 더 느슨한 간격으로 보는 기본 모드이고, Detailed Monitoring은 EC2 지표를 더 촘촘한 1분 단위로 보는 옵션이다. High-resolution custom metric은 애플리케이션이 직접 보내는 커스텀 지표를 1초 단위까지 저장하는 기능이다. 처음에는 “AWS 기본 지표를 더 자주 볼 것인가”와 “애플리케이션 고유 신호를 직접 더 촘촘히 보낼 것인가”를 구분하면 된다.

6. Logs: 숫자로 설명되지 않는 단서를 남긴다

섹션 제목: “6. Logs: 숫자로 설명되지 않는 단서를 남긴다”

Log는 텍스트 이벤트다. Metric이 “에러가 20건으로 늘었다”를 알려준다면, Log는 “어떤 요청에서 어떤 에러 메시지가 반복됐는가”를 알려준다.

CloudWatch Logs의 기본 구조는 Log Group과 Log Stream이다.

  • Log Group: 서비스나 애플리케이션 단위의 로그 묶음이다. 예: /ecs/order-api, /aws/lambda/payment-worker.
  • Log Stream: 특정 컨테이너, ECS 태스크, Lambda 실행 환경, EC2 인스턴스처럼 실행 단위별 로그 흐름이다.
  • Retention: Log Group별 보관 기간이다. 설정하지 않으면 오래 보관되어 비용과 검색 범위가 커질 수 있다.

ECS Fargate에서는 보통 Task Definition의 awslogs 설정으로 stdout/stderr를 CloudWatch Logs로 보낸다.

{
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/order-api",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
}
}

이 설정은 운영 명령어라기보다 구조를 이해하기 위한 예시다. 컨테이너가 로그를 파일에만 쓰고 CloudWatch로 보내지 않으면 Logs Insights에서 아무것도 검색되지 않는다.

Logs Insights: 시간 범위와 스캔 비용을 같이 생각한다

섹션 제목: “Logs Insights: 시간 범위와 스캔 비용을 같이 생각한다”

Logs Insights는 Log Group을 대상으로 쿼리를 실행한다. 가장 자주 쓰는 학습용 쿼리는 아래 세 가지다.

-- 최근 에러 로그 보기
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 20
-- 특정 요청 또는 비즈니스 키워드 추적
fields @timestamp, @message
| filter @message like /payment_failed/
| sort @timestamp desc
| limit 50
-- 시간대별 에러 발생 건수 집계
filter @message like /ERROR/
| stats count(*) as errorCount by bin(5m)
| sort @timestamp desc

Log Insights에서 결과가 비어 있을 때는 “에러가 없다”고 바로 결론 내리면 안 된다. 시간 범위가 너무 좁거나, Log Group을 잘못 골랐거나, 애초에 로그가 CloudWatch로 들어오지 않았을 수 있다. 또한 쿼리는 스캔한 로그 양이 커질수록 비용과 시간이 늘어나므로 장애 중에도 시간 범위를 먼저 좁히는 습관이 필요하다.

Retention: 비용과 조사 가능 기간의 계약

섹션 제목: “Retention: 비용과 조사 가능 기간의 계약”

Retention은 로그를 몇 일 동안 보관할지 정하는 설정이다. 보관 기간은 기술 선택이면서 비즈니스 계약이다. 결제 실패 로그는 감사와 고객 문의 때문에 더 오래 필요할 수 있고, staging debug 로그는 하루면 충분할 수 있다.

로그 종류예시 보관 기간판단 이유
결제, 정산, 보안 이벤트90일 이상 또는 별도 감사 저장소장애 분석보다 감사와 추적 가능성이 중요하다.
프로덕션 API 에러 로그14일에서 30일최근 배포와 반복 장애를 분석하기에 충분한 기간을 둔다.
액세스 로그, 상세 debug 로그7일 또는 더 짧게양이 많고 장기 분석 가치가 낮으면 비용을 줄인다.
staging, 개발 로그1일에서 3일개발 확인 목적이면 오래 둘 이유가 적다.

수치 감각도 필요하다. 하루 2GB 로그를 남기는 Log Group을 7일 보관하면 대략 최근 14GB 규모를 다룬다. 90일 보관하면 180GB 규모가 된다. 실제 과금 방식은 세부 항목이 더 있지만, 보관 기간이 비용을 선형으로 키운다는 직관은 유효하다.

7. Metric Filter: 로그 패턴을 지표로 바꾼다

섹션 제목: “7. Metric Filter: 로그 패턴을 지표로 바꾼다”

Metric Filter는 CloudWatch Logs에 들어오는 로그를 패턴으로 검사하고, 일치하면 커스텀 지표 값을 증가시키는 기능이다. 로그는 원인 분석에 좋지만 Alarm은 지표를 평가하므로, 로그 기반 알림에는 Metric Filter가 중간 다리 역할을 한다.

Metric Filter로 로그를 알람으로 바꾸는 흐름
flowchart LR
App["Worker 로그"] --> Group["Log Group: /ecs/image-worker"]
Group --> Filter["Metric Filter: worker_job_failed"]
Filter --> Metric["WorkerJobFailureCount +1"]
Metric --> Alarm["Alarm: 5분 안에 10회 초과?"]
Alarm --> SNS["SNS Topic"]
SNS --> Notify["Slack / 이메일 / 온콜"]

중요한 경계가 있다.

  • Metric Filter는 생성 이후 들어온 로그에 적용된다. 과거 로그를 소급해서 지표로 만들지 않는다.
  • JSON 로그는 JSON 필드 패턴으로 검사해야 한다. 단순 문자열 ERROR{ $.level = "ERROR" }는 다른 패턴이다.
  • 같은 로그에서 너무 많은 Dimension을 추출하면 커스텀 지표 Cardinality가 커진다.

Metric Filter는 “모든 에러 로그를 다 알림으로 보낸다”보다 “운영 판단에 즉시 필요한 패턴만 지표화한다”에 가깝다. 예를 들어 worker_job_failed, image_resize_failed, dlq_message_received 같은 패턴은 Metric Filter 후보가 될 수 있다.

8. Alarms: 지표를 운영 판단으로 바꾼다

섹션 제목: “8. Alarms: 지표를 운영 판단으로 바꾼다”

CloudWatch Alarm은 지표를 평가해서 OK, ALARM, INSUFFICIENT_DATA 중 하나의 상태를 가진다.

상태의미오해하기 쉬운 점
OK최근 평가 데이터가 조건을 위반하지 않았다.서비스가 완전히 정상이라는 보장은 아니다. 알람으로 보지 않는 문제가 있을 수 있다.
ALARM설정한 조건을 만족했다.상태가 이미 ALARM이면 같은 조건이 계속되어도 매번 새 알림이 나가지 않을 수 있다.
INSUFFICIENT_DATA평가할 데이터가 부족하다.”문제없음”이 아니다. 지표 수집 중단, 리소스 종료, 트래픽 없음이 모두 가능하다.

API p95 응답시간이 800ms를 넘으면 알람을 울리고 싶다고 하자.

설정:

  • Metric: TargetResponseTime
  • Statistic: p95
  • Period: 1분
  • Evaluation periods: 5
  • Datapoints to alarm: 3
  • Threshold: 800ms 초과

최근 5개 데이터 포인트가 아래와 같다면:

p95 응답시간위반 여부
10:01650ms정상
10:02920ms위반
10:03880ms위반
10:04700ms정상
10:05910ms위반

5개 중 3개가 임계값을 넘었으므로 Alarm은 ALARM으로 전환된다. 같은 조건을 1 out of 1로 만들면 10:02에 바로 울리지만 일시 스파이크에도 자주 울린다. 5 out of 5로 만들면 확실한 지속 장애만 잡지만 감지가 늦어진다.

이 예제의 핵심은 임계값 하나가 아니라 “얼마나 빨리 울릴 것인가”와 “얼마나 많은 노이즈를 허용할 것인가”의 선택이다.

Missing data는 설정이 아니라 해석 문제다

섹션 제목: “Missing data는 설정이 아니라 해석 문제다”

CloudWatch Alarm에는 누락 데이터를 어떻게 처리할지 정하는 옵션이 있다. 하지만 정답은 지표 성격에 따라 다르다.

지표 성격Missing data 처리 감각이유
항상 있어야 하는 인프라 지표breaching 후보ECS RunningTaskCount, heartbeat 지표가 사라진 것은 장애일 수 있다.
요청이 없으면 자연스럽게 없는 지표notBreaching 또는 missing 후보야간에 트래픽이 없어서 에러 카운트가 없는 것은 정상일 수 있다.
간헐적 배치 작업 지표missing 후보작업 실행 시간 외에는 데이터가 없는 것이 자연스럽다.
커스텀 애플리케이션 heartbeatbreaching 후보앱이 살아 있음을 의도적으로 보내는 지표라면 끊김 자체가 문제다.

ECS 태스크가 모두 STOPPED되면 컨테이너 지표도 멈출 수 있다. 이때 “CPU가 낮다”가 아니라 “데이터가 없다”가 된다. 태스크 중단을 즉시 감지해야 하면 RunningTaskCount 같은 지표의 missing data 처리나 EventBridge의 ECS Task State Change 이벤트를 같이 봐야 한다.

Alarm이 ALARM으로 바뀌면 보통 SNS Topic으로 알림을 보낸다. SNS는 이메일, Slack 연동, 온콜 시스템 같은 구독자에게 메시지를 fan-out한다. 이메일 구독은 확인 링크를 눌러야 활성화되므로 PendingConfirmation이면 알람은 울렸지만 사람이 못 받을 수 있다.

EventBridge는 Alarm 상태 변경이나 ECS 태스크 상태 변경 같은 이벤트를 후속 자동화로 넘길 때 유용하다. 예를 들어 “결제 서비스 p95와 에러율이 같이 나빠지면 Slack 알림”은 SNS만으로 충분할 수 있지만, “특정 Alarm이 ALARM이면 자동으로 진단 Lambda를 실행”하려면 EventBridge가 더 자연스럽다.

9. Dashboards: 판단 화면을 설계한다

섹션 제목: “9. Dashboards: 판단 화면을 설계한다”

Dashboard는 그래프를 많이 붙이는 화면이 아니라, 장애 중 첫 5분에 팀이 같은 질문을 보게 만드는 화면이다. 좋은 대시보드는 서비스의 정상 기준선과 장애 후보를 한 화면에 둔다.

예를 들어 주문 API 대시보드는 아래처럼 구성할 수 있다.

지표질문
사용자 영향ALB RequestCount, 5xx, TargetResponseTime p95/p99사용자 요청이 실제로 실패하거나 느려졌는가
애플리케이션ECS CPU, Memory, RunningTaskCountAPI 컨테이너가 부족하거나 재시작 중인가
비동기 경로SQS backlog, DLQ 메시지 수, Worker CPU요청 밖 작업이 밀리거나 죽었는가
데이터 계층RDS CPU, DatabaseConnections, Read/Write latencyDB가 병목인가
비즈니스 지표OrderSuccess, PaymentFailureCount기술 증상이 실제 거래 흐름에 영향을 주는가

Dashboard는 Alarm을 대체하지 않는다. Dashboard는 사람이 상황을 해석하기 위한 화면이고, Alarm은 상태 전환을 사람이나 자동화에 보내는 장치다.

10. Container Insights: 컨테이너 단위로 더 좁혀 본다

섹션 제목: “10. Container Insights: 컨테이너 단위로 더 좁혀 본다”

ECS나 EKS를 쓰면 기본 CloudWatch 지표만으로는 “서비스 전체가 느리다”까지만 보이고, 어떤 태스크나 컨테이너가 병목인지 좁히기 어려울 수 있다. Container Insights는 클러스터, 서비스, 태스크, 컨테이너 단위의 CPU, 메모리, 네트워크, 태스크 수 같은 지표를 더 자세히 제공한다.

지표읽는 법
CpuUtilized실제 사용한 CPU 양이다. CPUUtilization 비율과 함께 보면 할당 대비 사용량을 이해할 수 있다.
MemoryUtilized컨테이너나 태스크가 실제 사용 중인 메모리다. 지속 증가하면 누수나 큰 payload 처리를 의심한다.
NetworkRxBytes / NetworkTxBytes네트워크 수신/송신량이다. 외부 API 호출 증가나 응답 크기 증가를 볼 수 있다.
RunningTaskCount서비스가 기대한 수만큼 태스크를 유지하는지 본다.
EphemeralStorageUtilizedFargate 임시 스토리지 사용량이다. 임시 파일, 로그, 압축 작업이 쌓이는지 확인한다.

Container Insights는 “항상 켜야 하는 정답”이라기보다 컨테이너 단위 진단이 필요한 서비스에 켜는 선택지다. 기본 지표로 충분한 작은 서비스에서는 비용과 필요성을 같이 봐야 한다. 반대로 장애 중에 CPU 평균은 정상인데 일부 태스크만 메모리를 먹고 죽는다면 Container Insights가 없을 때 원인 좁히기가 어려워진다.

도구 선택은 기능 목록 비교보다 운영 환경과 팀의 책임 범위로 결정하는 편이 낫다.

모니터링 도구 선택 기준

CloudWatch

AWS 리소스 기본 지표, CloudWatch Logs, Alarm, SNS/EventBridge 연동을 관리형으로 쓰고 싶을 때 적합하다.

AWS 중심 서비스이고, 관측 스택 운영 부담을 줄이며, 기본 운영 신호부터 빠르게 갖춰야 할 때

Prometheus

Kubernetes와 서비스 메트릭을 직접 수집하고 PromQL로 복잡한 비율, rate, histogram 계산을 하고 싶을 때 적합하다.

멀티클라우드, 자체 클러스터, 오픈소스 운영 역량, 세밀한 메트릭 쿼리가 중요할 때

Datadog

메트릭, 로그, APM, 프로파일링, RUM을 SaaS로 통합하고 팀 간 운영 화면을 빠르게 맞추고 싶을 때 적합하다.

멀티클라우드와 애플리케이션 추적을 한 제품에서 묶고 싶고, SaaS 비용을 감당할 수 있을 때

실무에서는 하나만 고르는 경우보다 섞어 쓰는 경우도 많다. AWS 기본 리소스 알람은 CloudWatch에 두고, Kubernetes 서비스 메트릭은 Prometheus로 모으고, 사용자 요청 추적과 프로파일링은 Datadog이나 OpenTelemetry 기반 스택으로 보는 식이다.

CloudWatch에서 다른 도구를 검토할 때의 질문은 아래처럼 구체적이어야 한다.

신호의미다음 선택지
AWS 밖 리소스가 많아진다CloudWatch만으로 전체 상태를 통합하기 어렵다.Datadog, Prometheus, OpenTelemetry Collector
PromQL 수준의 rate, ratio, histogram 계산이 자주 필요하다CloudWatch 기본 조회 모델이 분석 요구를 따라가기 어렵다.Prometheus 또는 Managed Prometheus
요청 하나의 서비스 간 경로를 추적해야 한다Metric과 Log만으로 병목 위치를 좁히기 어렵다.X-Ray, OpenTelemetry, Datadog APM, Jaeger
커스텀 지표 Cardinality가 계속 커진다Dimension 설계를 다시 보거나 다른 메트릭 백엔드를 검토해야 한다.Dimension 축소, 로그/트레이스 이동, Prometheus/Datadog 검토
알림은 많은데 액션이 없다도구 문제가 아니라 알람 설계와 SLO 기준 문제일 수 있다.SRE Practices에서 SLI/SLO와 alert policy 재설계

CloudWatch를 처음 배울 때 자주 생기는 오해는 아래와 같다.

오해실제 경계
”로그만 많으면 관측성이 충분하다”로그는 원인 단서에는 좋지만 전체 추세와 자동 알림에는 지표가 필요하다.
”Metric은 자세할수록 좋다”Dimension이 많을수록 비용과 관리 복잡도가 늘어난다. requestId 같은 값은 로그나 트레이스에 둔다.
”Dashboard가 있으면 운영 준비가 끝났다”Dashboard는 사람이 보는 화면이다. 중요한 조건은 Alarm과 대응 경로가 있어야 한다.
”INSUFFICIENT_DATA는 정상이다”데이터가 없다는 뜻일 뿐이다. 지표 성격에 따라 장애일 수 있다.
”Alarm은 매번 조건을 넘을 때마다 울린다”Alarm은 상태 전환 중심이다. 이미 ALARM 상태면 같은 조건 지속만으로 새 알림이 반복되지 않을 수 있다.
”CloudWatch 하나로 APM까지 끝난다”CloudWatch는 AWS 신호의 기본 통합에 강하다. 분산 추적과 프로파일링은 X-Ray, OpenTelemetry, Datadog 같은 추가 도구가 필요할 수 있다.

긴 트러블슈팅 절차를 외우기보다 증상, 의심할 개념, 첫 확인 지점을 연결하는 것이 학습에 더 도움이 된다.

증상먼저 의심할 개념왜 그런가첫 확인
Alarm이 ALARM인데 Slack이나 이메일이 오지 않는다SNS 구독 또는 알림 경로Alarm 상태 전환은 되었지만 SNS 구독이 PendingConfirmation이거나 Slack 연동이 끊겼을 수 있다.Alarm의 Actions, SNS Topic 구독 상태
지표가 임계값을 넘었는데 ALARM으로 바뀌지 않는다Evaluation window, datapoints to alarm, Unit3 out of 5이면 세 번 위반해야 하고, Unit 불일치도 평가를 헷갈리게 한다.Alarm 조건의 Period, Evaluation periods, Datapoints to alarm
ECS 태스크가 죽었는데 CPU Alarm은 조용하다Missing data태스크가 죽으면 CPU가 낮아지는 것이 아니라 지표가 끊길 수 있다.Missing data 처리, RunningTaskCount, EventBridge ECS Task State Change
Log Insights 결과가 비어 있다시간 범위, Log Group, 로그 수집쿼리가 틀린 것이 아니라 시간 범위나 Log Group이 틀렸거나 로그가 수집되지 않았을 수 있다.시간 범위 확장, /ecs/<service> Log Group, logConfiguration
CloudWatch 비용이 갑자기 늘었다Retention, Cardinality, Query scan, high-resolution metric로그 보관 기간, 고유 Dimension, 반복 쿼리, 고해상도 지표가 비용을 키운다.Retention 없는 Log Group, 커스텀 지표 Dimension, Logs Insights 사용량
Metric Filter를 만들었는데 지표가 0이다패턴 불일치 또는 소급 적용 오해Metric Filter는 생성 이후 로그에만 적용되고, JSON 로그는 필드 패턴이 필요하다.Test pattern, 새 테스트 로그, JSON 패턴
알람이 너무 자주 울린다Alert fatigue, threshold, evaluation policy단일 지표의 짧은 스파이크를 모두 사람에게 보내면 실제 장애를 놓친다.임계값 기준선, 1 out of 1 여부, Composite Alarm 후보
배포 후 느려졌는데 원인이 안 좁혀진다Dashboard 설계와 지표 축사용자 영향, 앱 리소스, 큐, DB, 비즈니스 지표가 따로 떨어져 있으면 상관관계를 보기 어렵다.배포 시각 기준으로 핵심 지표를 같은 대시보드에서 비교

이 표는 실제 대응 순서를 완전히 대체하지 않는다. 대신 어떤 개념을 먼저 의심해야 하는지 알려준다. 실전 런북은 팀 서비스 이름, 알림 채널, 배포 도구, 롤백 절차에 맞게 따로 있어야 한다.

14. Alert fatigue를 줄이는 알람 설계

섹션 제목: “14. Alert fatigue를 줄이는 알람 설계”

Alert fatigue는 알람이 너무 자주 울려서 사람이 무시하게 되는 상태다. CloudWatch Alarm을 많이 만드는 것보다 “울리면 행동할 수 있는 알람”을 만드는 것이 중요하다.

알람을 만들 때는 아래 순서로 생각한다.

  1. 사용자 영향 지표를 먼저 잡는다. 예: 5xx 비율, p95 응답시간, 결제 실패 수.
  2. 인프라 지표는 원인 후보로 연결한다. 예: ECS CPU, RDS 연결 수, SQS backlog.
  3. 일시 스파이크를 걸러낼 Evaluation window를 정한다.
  4. 사람이 받을 알람과 대시보드에서만 볼 지표를 분리한다.
  5. 단일 지표로 오탐이 많으면 Composite Alarm을 검토한다.

예를 들어 CPU 85%만으로 결제 서비스 장애 알람을 보내면 배치 작업이나 순간 피크에도 자주 울릴 수 있다. 반대로 5xx 비율 > 1%p95 응답시간 > 2초가 동시에 발생할 때 알람을 보내면 사용자 영향에 더 가까운 신호가 된다. CPU는 그 다음 원인 후보로 대시보드에 두는 편이 낫다.

CloudWatch를 공부할 때 “장애 대응”보다 먼저 익히기 좋은 상황은 배포 직후 관찰이다. 배포 시각을 기준으로 전후 지표를 비교하면 CloudWatch의 기본 모델을 손으로 따라갈 수 있다.

확인 지표정상 해석위험 신호
ALB 5xx, TargetResponseTime p95/p99배포 전 기준선과 비슷하다.5xx가 새로 생기거나 p95/p99가 20% 이상 악화된다.
ECS RunningTaskCountdesired count와 일치한다.새 태스크가 RUNNING으로 안정화되지 않거나 반복 교체된다.
ECS CPU/Memory기존 범위와 비슷하다.CPU가 지속적으로 높거나 메모리가 계단식으로 증가한다.
RDS DatabaseConnections, latency기존 범위와 비슷하다.연결 수가 급증하거나 latency가 같이 오른다.
Log Insights ERROR count새 에러 패턴이 없다.배포 이후 특정 ERROR가 반복된다.
비즈니스 커스텀 지표주문, 결제, 가입 흐름이 유지된다.기술 지표는 정상인데 성공 건수가 줄어든다.

이 예시는 긴 온콜 런북이 아니라 학습용 관찰 순서다. 핵심은 “한 지표가 나빠졌다”에서 멈추지 않고 사용자 영향, 앱 리소스, 데이터 계층, 비즈니스 결과를 같은 시간축에서 비교하는 것이다.

CloudWatch를 업무에 연결할 때는 아래 질문으로 시작하면 된다.

  • 우리 API, Worker, 배치, Lambda의 Log Group 이름을 알고 있는가?
  • 배포 직후 보는 Dashboard가 있는가? 없다면 어떤 5개 지표가 첫 화면에 있어야 하는가?
  • 사용자가 느끼는 장애와 가장 가까운 Alarm은 무엇인가? 5xx, latency, 실패 건수, backlog 중 무엇인가?
  • Alarm이 울렸을 때 SNS, Slack, 온콜, EventBridge 중 어디로 흘러가는가?
  • Log Group Retention이 서비스 중요도에 맞게 설정되어 있는가?
  • 커스텀 지표 Dimension에 userId, orderId, requestId 같은 높은 Cardinality 값이 들어가 있지 않은가?
  • ECS/Fargate에서 기본 지표만으로 원인을 좁힐 수 있는가, 아니면 Container Insights가 필요한가?

CloudWatch 학습 확인

  • CloudWatch Metrics, Logs, Alarms, Dashboards의 역할을 각각 한 문장으로 설명할 수 있다.
  • Namespace, Dimension, Period, Statistic이 Metric 조회와 Alarm 평가에 어떤 영향을 주는지 설명할 수 있다.
  • `3 out of 5` Alarm 평가 예시를 손으로 판단할 수 있다.
  • INSUFFICIENT_DATA가 왜 정상 상태가 아닌지 설명할 수 있다.
  • Log Group, Log Stream, Retention의 차이를 설명할 수 있다.
  • Log Insights 쿼리 결과가 비어 있을 때 시간 범위, Log Group, 로그 수집을 먼저 확인할 수 있다.
  • Metric Filter가 로그를 지표로 바꾸지만 과거 로그에는 소급 적용되지 않는다는 점을 알고 있다.
  • Container Insights와 기본 ECS 지표의 차이를 설명할 수 있다.
  • 고카디널리티 Dimension이 비용과 운영 복잡도를 키우는 이유를 예시로 설명할 수 있다.
  • CloudWatch, Prometheus, Datadog을 환경과 운영 책임 기준으로 비교할 수 있다.

CloudWatch Logs Insights, Metric Filter, Composite Alarm, Anomaly Detection, Container Insights, CloudWatch Agent, Embedded Metric Format, Metrics Insights, CloudWatch Synthetics, AWS X-Ray, OpenTelemetry, Cross-Account Observability.

처음 읽을 때는 모두 깊게 파지 않아도 된다. 이 문서의 핵심은 CloudWatch의 기본 데이터 모델과 Alarm 평가 방식이다. X-Ray, OpenTelemetry, SLI/SLO는 뒤의 Logs / Metrics / Traces, SRE Practices에서 더 자세히 다룬다.

  1. CloudWatch는 AWS 리소스와 애플리케이션의 Metrics, Logs, Alarms, Dashboards를 모으는 관리형 관측 서비스다.
  2. Metrics는 숫자 신호이고, Logs는 원인 단서이며, Alarms는 지표 평가 결과를 알림이나 자동화로 연결한다.
  3. Alarm은 Period, Statistic, Evaluation window, Datapoints to alarm, Missing data 처리에 따라 완전히 다르게 동작한다.
  4. Dimension은 곱셈으로 늘어나므로 userId, requestId 같은 고카디널리티 값은 지표가 아니라 로그나 트레이스에 둔다.
  5. CloudWatch는 AWS 운영의 기본 출발점이고, 멀티클라우드, 고급 쿼리, 분산 추적 요구가 커지면 Prometheus, Datadog, OpenTelemetry 계열과 함께 비교한다.

선택 부록: 직접 확인해볼 작은 관찰 과제

섹션 제목: “선택 부록: 직접 확인해볼 작은 관찰 과제”

아래 과제는 본문 이해에 필수는 아니다. 실제 AWS 계정이나 팀 서비스가 있을 때 CloudWatch 콘솔에서 개념을 손으로 확인하기 위한 최소 관찰 목록이다.

Log Group과 Retention 확인
  1. CloudWatch 콘솔에서 Logs -> Log groups로 이동한다.
  2. API, Worker, Lambda에 해당하는 Log Group을 찾는다. 예: /ecs/order-api, /aws/lambda/payment-worker.
  3. Retention 컬럼이 Never expire인지 확인한다.
  4. 로그 성격을 기준으로 7일, 30일, 90일처럼 보관 기간 후보를 적어 본다.

관찰 포인트: “모든 로그를 오래 보관”은 단순하지만 비용과 검색 범위를 키운다. 결제/감사 로그와 debug 로그의 보관 기간은 달라야 한다.

Logs Insights로 ERROR 추세 보기
fields @timestamp, @message
| filter @message like /ERROR/
| stats count(*) as errorCount by bin(5m)
| sort @timestamp desc

확인할 것:

  • 시간 범위를 1시간, 24시간으로 바꿨을 때 결과가 어떻게 달라지는가
  • Log Group을 잘못 고르면 어떤 식으로 비어 보이는가
  • 배포 시각 이후 새 에러 패턴이 생겼는가
Alarm 평가 조건 손으로 읽기

Alarm 상세 화면에서 아래 값을 찾는다.

  • Metric name
  • Namespace와 Dimensions
  • Statistic
  • Period
  • Evaluation periods
  • Datapoints to alarm
  • Treat missing data
  • Actions 또는 SNS Topic

관찰 포인트: 같은 임계값이라도 1 out of 13 out of 5는 완전히 다른 알람이다. Treat missing data는 지표 성격에 맞아야 한다.

Metric Filter 패턴 점검

텍스트 로그라면:

ERROR
payment_failed

JSON 로그라면:

{ $.level = "ERROR" }
{ $.statusCode >= 500 }
{ $.event = "payment_failed" }

관찰 포인트: Metric Filter는 생성 이후 들어온 로그에만 적용된다. 과거 장애 로그를 기준으로 필터를 만들었다면 새 테스트 로그를 흘려보내서 지표가 생기는지 확인해야 한다.

ECS/Fargate에서 Container Insights 필요성 판단

기본 ECS 지표와 Container Insights 지표를 비교해 본다.

질문기본 지표로 충분한가Container Insights가 필요한 신호
서비스 전체 CPU가 높은가대체로 충분하다.태스크별 편차가 커서 특정 태스크만 죽는지 봐야 한다.
메모리 누수가 있는가서비스 평균만으로는 부족할 수 있다.특정 컨테이너의 MemoryUtilized가 계단식으로 증가한다.
태스크 수가 기대와 맞는가RunningTaskCount가 있으면 시작 가능하다.태스크/컨테이너 레벨 재시작과 리소스 사용량을 같이 봐야 한다.