Skip to content
sweepty

가상 면접 사례로 배우는 대규모 시스템 설계 기초 2편 정리 (5장 지표 모니터링 및 경보 시스템)

— 15 min read

『가상 면접 사례로 배우는 대규모 시스템 설계 기초 2』 5장을 스터디에서 같이 보며 정리한 내용이다. 책의 흐름을 따라가되, 이해를 돕기 위해 예시는 직접 만들어 붙였다.

한 줄 요약

서버의 숫자 지표(CPU, 메모리, 요청 수, 에러율 등)를 모으고 → 옮기고 → 저장하고 → 이상하면 알리고 → 그래프로 보여 주는 시스템을 설계하는 장이다.

병원 중환자실 모니터에 빗대면 기억하기 쉽다.

병원시스템
센서가 심박·혈압을 계속 잰다데이터 수집
측정값이 시간순으로 기록된다시계열 DB에 저장
수치가 위험하면 간호사 호출경보
모니터 화면의 그래프시각화

로그 모니터링(ELK)이나 분산 추적(Zipkin)은 이 장의 범위가 아니다. 오직 숫자 지표만 다룬다.

1단계: 요구사항

  • DAU 1억 명 규모의 대형 서비스
  • 서버 풀 1,000개 × 풀당 서버 100대 × 서버당 지표 100개 = 약 1,000만 개 지표
  • 데이터는 1년 보관하되, 오래될수록 해상도를 낮춘다
    • 7일까지: 원본 그대로
    • 30일까지: 1분 단위
    • 1년까지: 1시간 단위
  • 경보 채널: 이메일, 전화, PagerDuty, 웹훅
  • 비기능 요구사항: 규모 확장성, 낮은 응답 지연, 안정성, 유연성

2단계: 개략적 설계

시스템은 다섯 덩어리로 나뉜다. "결제 서버 에러율이 5%를 넘었다"는 상황 하나로 따라가 보면 이렇다.

컴포넌트하는 일예시
데이터 수집여러 출처에서 지표를 모은다10초마다 에러율 측정
데이터 전송모은 지표를 저장소로 옮긴다수집기 → 카프카
데이터 저장소들어온 지표를 정리해 보관시계열 DB에 저장
경보이상 징후를 감지해 알린다5% 초과 감지, 온콜 호출
시각화그래프·차트로 보여 준다대시보드에 급등 그래프

데이터 모델

지표 한 건은 보통 이렇게 생겼다.

cpu.load host=web-01,env=prod 1727600000 0.75
지표 이름 레이블(키=값) 타임스탬프 값

지표 이름 + 레이블 조합 하나가 시계열 하나다. 위 예시라면 cpu.load{host=web-01, env=prod}라는 시계열에 (시각, 값) 쌍이 계속 쌓인다.

시각값
10:00:000.62
10:00:100.71
10:00:200.75

레이블에는 값의 종류가 한정된 것(host, env, region)만 넣어야 한다. user_id 같은 걸 넣으면 사용자 수만큼 시계열이 생겨서 저장소가 감당하기 어려워진다.

데이터 접근 패턴과 저장소 선택

  • 쓰기: 늘 많고 꾸준하다. 1,000만 개 지표를 10초마다 모은다고 가정하면 초당 약 100만 건이다.
  • 읽기: 대시보드를 열거나 경보 규칙이 돌 때 한꺼번에 몰린다. 대부분 "특정 기간 + 특정 레이블"로 묶어 보는 질의다.

이런 패턴에는 범용 관계형 DB보다 시계열 DB(InfluxDB, Prometheus, OpenTSDB 등)가 맞다. 책에 따르면 InfluxDB는 8코어·16GB 서버 한 대로 초당 25만 건 넘는 쓰기를 처리할 수 있다.

3단계: 상세 설계

풀 모델 vs 푸시 모델

지표를 어떻게 모을지는 크게 두 가지다.

  • 풀(Pull): 수집기가 각 서버의 /metrics 엔드포인트를 주기적으로 긁어 간다. 선생님이 출석을 부르는 방식. 대상 서버 목록은 etcd나 ZooKeeper 같은 서비스 탐색으로 얻고, 수집기가 여러 대면 안정 해시 링으로 담당 서버를 나눈다. 대표 예: 프로메테우스.
  • 푸시(Push): 서버에 설치된 수집 에이전트가 지표를 모아 수집기로 보낸다. 학생이 직접 출석 카드를 내는 방식. 에이전트가 1분치 카운터를 합산해서 한 번만 보내기도 한다. 수집기는 로드밸런서 뒤에 오토스케일링 클러스터로 둔다. 대표 예: CloudWatch, Graphite.
항목풀푸시
디버깅유리 · /metrics를 직접 열어 보면 됨에이전트까지 확인해야 함
상태 진단유리 · 응답 없으면 바로 장애로 판단안 오면 네트워크 문제인지 모호
짧게 끝나는 작업긁기 전에 프로세스가 끝날 수 있음유리 · 끝나기 전에 보내면 됨
방화벽·복잡한 망모든 서버에 접근할 수 있어야 함유리 · 수집기 LB만 열면 됨
성능보통 TCP유리 · 보통 UDP라 지연이 낮음
데이터 신빙성유리 · 설정된 서버에서만 수집누구나 보낼 수 있어 인증 필요

정답은 없다. 예를 들어 매일 새벽 10초 만에 끝나는 배치 작업은 풀 방식으로는 긁으러 가기 전에 사라질 수 있어서 푸시가 필요하다. 대규모 조직이라면 둘 다 지원하는 편이 현실적이다.

카프카로 전송 파이프라인 확장

지표 수집기 → 카프카 → 소비자(Flink, Spark, Storm 등) → 시계열 DB

카프카를 사이에 두면 얻는 것:

  • 완충: DB가 잠깐 멈춰도 지표가 카프카에 쌓여 있다가 복구 후 처리된다. 트래픽이 몰리는 날에도 유실이 없다.
  • 분리: 수집과 처리가 느슨하게 연결되어 수집기와 소비자를 각자 늘릴 수 있다.
  • 파티션 활용: 지표 이름별로 파티션을 나누면 같은 지표끼리 집계하기 쉽다. 태그로 더 쪼개거나 중요한 지표를 먼저 처리할 수도 있다.

대신 카프카 자체를 운영하는 부담이 생긴다. 페이스북의 고릴라(Gorilla)처럼 쓰기 장애에 강한 메모리 기반 시계열 DB를 쓰면 카프카 없이 가는 선택지도 있다.

어디서 집계할까

집계 지점예시장점단점
수집 에이전트1분간 요청 수를 세서 합계만 전송전송량 감소단순한 집계만 가능
수집 파이프라인Flink가 1분 단위로 집계 후 저장DB 쓰기량이 크게 줄어듦늦게 도착한 데이터 처리가 까다롭고 원본 정밀도를 잃음
질의 시점원본 저장, 조회할 때 합산데이터 손실 없음질의할 때마다 계산해서 느림

왼쪽으로 갈수록 저장량이 줄고, 오른쪽으로 갈수록 유연하다.

질의 서비스와 캐시

질의 서비스는 시각화·경보 시스템과 시계열 DB 사이에서 질의를 받아 처리하고, 자주 쓰는 결과는 캐시에 둔다. 다만 요즘 시계열 DB는 PromQL, Flux 같은 자체 질의 언어를 제공하기 때문에 별도 질의 서비스 없이 바로 써도 되는 경우가 많다.

저장 공간 줄이기

① 데이터 인코딩·압축 (델타 인코딩)

지표는 거의 일정한 간격으로 들어오니, 타임스탬프 전체를 매번 저장하는 대신 기준값과 차이값만 저장한다.

원본: 1727600000 1727600010 1727600020
델타: 1727600000 +10 +10

작은 차이값은 훨씬 적은 비트로 표현할 수 있다.

② 다운샘플링

오래된 데이터는 해상도를 낮춘다. 10초 단위 CPU 사용률 6개를 1분 평균 하나로 합치는 식이다.

10:00:00 40% | 10:00:10 60% | 10:00:20 50% | 10:00:30 70% | 10:00:40 30% | 10:00:50 50%
→ 10:00 평균 50%

저장량은 6분의 1이 되지만, 10:00:30의 70% 같은 순간적인 튐은 평균에 묻힌다는 점은 알아 둬야 한다.

③ 냉동 저장소

거의 조회하지 않는 오래된 데이터는 훨씬 저렴한 저장소로 옮긴다.

경보 시스템

경보가 울리기까지의 흐름은 이렇다.

  1. 규칙 불러오기: YAML로 작성한 경보 규칙을 읽어 캐시에 올린다.
  2. 주기적으로 질의: 경보 관리자가 규칙대로 질의 서비스를 호출하고, 임계치를 넘으면 경보 이벤트를 만든다.
  3. 거르고 합치기: 필터·병합·중복 제거, 접근 제어. 같은 서버의 같은 경보는 하나로 묶는다.
  4. 상태 기록: 카산드라 같은 키-값 저장소에 경보 상태를 남긴다.
  5. 카프카로 전달: 보낼 경보를 카프카에 넣어 발송과 분리한다.
  6. 채널로 발송: 경보 소비자가 이메일·문자·PagerDuty·웹훅으로 보낸다. 실패하면 재시도해서 최소 한 번은 전달한다.

규칙은 대략 이런 모양이다(프로메테우스 스타일로 만든 예시).

- name: instance_down
expr: up == 0
for: 5m
labels:
severity: page

up 값이 0인 상태가 5분 이어지면 담당자를 호출한다. for: 5m 구간이 "응답 대기" 상태라서, 조건이 잠깐 튀었다 사라지면 실제 경보까지 가지 않는다.

경보 상태는 다음 순서로 바뀐다.

비활성(inactive) → 응답 대기(pending) → 격발(firing) → 해소(resolved)

중복 제거 예시: web-01의 디스크 사용률 90% 초과 이벤트가 1분 사이에 3번 발생해도 알림은 1번만 보낸다.

시각화

품질 좋은 시각화 시스템은 직접 만들기 어렵다. 그라파나(Grafana) 같은 기존 제품을 쓰는 것이 낫고, 경보 시스템도 마찬가지로 구현보다 구입을 권한다.

4단계: 최종 설계안

┌─ 이메일
├─ 단문 메시지
경보 시스템 ──┼─ PagerDuty
│ └─ 웹훅(HTTPS)
│ 질의 전송
▼
지표 출처 → 지표 수집기 → 카프카 → 소비자 → 시계열 DB ← 질의 서비스 ← 시각화 시스템
│
▼
캐시
  • 가로 줄: 지표가 흘러 쌓이는 길
  • 위쪽: 경보가 나가는 길
  • 오른쪽: 사람이 보는 길

정리

이 장에서 가져갈 다섯 가지.

  1. 수집 모델: 디버깅·상태 진단은 풀, 짧게 끝나는 작업·방화벽 환경은 푸시가 유리하다.
  2. 카프카로 규모 확장: 수집과 저장 사이 버퍼로 유실을 막고, 파티션으로 나눠 처리한다.
  3. 시계열 DB 선택: 많은 쓰기와 레이블 기반 집계에 맞춰 만들어진 저장소를 쓴다.
  4. 다운샘플링: 오래된 데이터일수록 해상도를 낮춰 저장 공간을 아낀다.
  5. 경보·시각화는 구입: 그라파나, PagerDuty 같은 기존 제품을 쓰자.

스터디에서 나눈 질문

  • 우리 서비스라면 풀과 푸시 중 무엇을 고를까? 배치나 서버리스 작업은?
  • 레이블에 user_id를 넣으면 저장소와 질의에 어떤 일이 생길까?
  • 밤마다 쓸모없는 경보가 울린다면, 병합·중복 제거 말고 무엇을 바꿀 수 있을까?
    • 임계치 재조정, for 기간 늘리기, 심각도별로 채널 나누기(한밤 호출은 정말 급한 것만) 등
© 2026 by sweepty. All rights reserved.
Theme by LekoArts