모니터링 시스템 구축기

2025. 7. 14. 16:57·Etc

모니터링 시스템이 왜 필요할까?

서비스가 정상적으로 운영되고 있을 때는 모니터링 시스템의 필요성을 쉽게 체감하지 못한다. 그러나 예기치 못한 오류나 성능 저하가 발생하면 상황은 급변한다. 사용자로부터 불만이 접수되기 시작하고, 개발자는 “무슨 일이 일어난 걸까?”라는 질문부터 던지게 된다. 이때 모니터링 시스템의 유무는 문제 해결 속도를 결정짓는 중요한 요소가 된다.

모니터링 시스템은 단순히 데이터를 수집하고 시각화하는 도구가 아니다. 시스템의 상태를 실시간으로 파악하고, 장애를 빠르게 감지하며, 그 원인을 추적할 수 있도록 도와주는 운영의 필수 구성 요소다. 또한, 장기적으로는 성능 개선과 리소스 최적화에도 기여하여 서비스의 안정성과 신뢰도를 높이는 데 중요한 역할을 한다.

메트릭 기반 모니터링: Prometheus와 Spring Actuator

현대의 애플리케이션은 단순한 기능 제공을 넘어서, 안정성과 성능을 지속적으로 보장해야 한다. 그러나 서비스가 복잡해질수록 장애의 원인을 파악하고, 시스템 상태를 실시간으로 파악하는 일은 점점 어려워진다. 이때 필요한 것이 바로 모니터링 시스템이며, 그 중에서도 메트릭 기반 모니터링(Metrics-based Monitoring)은 빠르고 효과적인 운영 가시성을 제공하는 방식이다.

메트릭이란?

메트릭(Metrics)은 시스템이나 애플리케이션의 상태를 나타내는 정량적인 수치 지표다. 일반적으로 시계열(time-series) 데이터로 구성되며, 시간의 흐름에 따라 변화하는 값을 기록한다. 예를 들어, CPU 사용률 (%), 메모리 사용량 (MB), 초당 처리 요청 수 (TPS), HTTP 요청 응답 시간 (ms), 에러 발생 횟수 와 같은 값들이 모두 메트릭에 해당한다. 메트릭은 경량성, 빠른 수집 속도, 집계 편의성 등의 장점 때문에, 시스템 전반의 상태를 지속적으로 관찰하고 이상을 감지하는 데 적합하다.

Prometheus

Prometheus는 CNCF(Cloud Native Computing Foundation)에서 관리하는 오픈소스 메트릭 수집 시스템이다.

Prometheus가 널리 사용되는 이유는 단순한 메트릭 수집 도구를 넘어, 강력한 기능과 유연한 설계 구조를 갖추고 있기 때문이다. 대표적인 특징 몇 가지를 중심으로 Prometheus의 장점을 하나씩 살펴보자.

가장 먼저, 프로메테우스의 메트릭 수집 방식은 Pull 기반 수집 방식이다.

일반적인 모니터링 시스템은 에이전트가 데이터를 수집한 뒤 서버로 Push하는 구조를 많이 사용한다. 그러나 Prometheus는 반대로, Prometheus 서버가 주기적으로 각 서비스의 메트릭 엔드포인트에 직접 요청을 보내 데이터를 가져오는 Pull 방식을 채택하고 있다. 이 구조는 설정이 단순하고, 수집 대상의 상태를 Prometheus가 직접 판단할 수 있기 때문에 장애 발생 시 격리와 대응이 용이하다. 또한, 서비스 인스턴스를 추가하거나 제거해도 설정을 일괄적으로 관리하기 쉬워 구성의 일관성을 유지하는 데 유리하다.

두 번째는 자체 내장된 시계열(Time Series) 저장소다. Prometheus는 수집한 메트릭 데이터를 외부 데이터베이스 없이 자체적으로 저장한다. 물론 이는 대규모 장기 저장소로는 적합하지 않지만, 최근 몇 시간~며칠 단위의 실시간 분석에는 충분한 성능과 효율성을 보여준다. 따라서 빠른 모니터링과 장애 감지, 알림 트리거 같은 단기 운영 목적에 이상적이다.

Prometheus의 진짜 강점은 단순한 수집을 넘어, 수집된 메트릭을 분석하고 조합할 수 있는 쿼리 언어인 PromQL에 있다. PromQL은 단일 메트릭뿐만 아니라, 집계, 비율 계산, 필터링, 파생 지표 계산까지 지원하여, 조건들을 정밀하게 분석하거나 알림 조건으로 설정할 수 있다. Grafana에서도 이 PromQL을 그대로 사용해 다양한 대시보드를 구성할 수 있다.

마지막으로, Prometheus는 다양한 Exporter 생태계를 기반으로 거의 모든 시스템과 연동이 가능하다는 장점이 있다. 대표적인 예로 Node Exporter는 Linux 서버의 CPU, 메모리, 디스크 사용량 등을 수집하고, JMX Exporter는 Java 애플리케이션의 MBean 정보를 체크한다. 이 외에도 데이터베이스, 캐시, 메시지 큐, 클라우드 인프라 등 주요 시스템을 모니터링할 수 있는 Exporter들이 활발하게 개발되고 있다.

Spring Actuator

Spring Boot Actuator는 Spring 기반 애플리케이션에 운영과 관련된 정보를 노출해주는 도구이다. 애플리케이션의 상태, 환경, 로그, 쓰레드, 메트릭 등을 엔드포인트 형태로 제공해 준다. 기본적으로는 Micrometer라는 추상화 계층을 통해 메트릭을 수집한다.

Grafana
Grafana는 Prometheus 등 다양한 데이터 소스를 시각화하는 오픈소스 도구이다. Prometheus가 수집한 메트릭은 기본적으로 숫자와 텍스트로 이루어져 있어 사람이 보기 어렵기 때문에, 이를 시각적으로 보여주는 것이 필요하다. Grafana는 이를 해결해주는 도구이며, Prometheus 외에도 Elasticsearch, Loki, InfluxDB, MySQL 등 여러 데이터 소스를 동시에 다룰 수 있다.

로그 기반 모니터링

로그 기반 모니터링은 애플리케이션이나 시스템이 출력하는 로그 데이터를 수집, 분석, 시각화하여 서비스 상태를 파악하고 이상을 감지하는 방식이다. 단순히 로그를 파일로 남기는 것에 그치지 않고, 이를 중앙화하여 효율적으로 관리하고 시각화함으로써 운영 효율성을 크게 높일 수 있다.

로그 기반 모니터링을 구축할 때 대표적으로 선택되는 두 가지 스택이 있다. 바로 ELK 스택과 Grafana + Loki 조합이다.

1. ELK 스택

ELK는 Elasticsearch, Logstash, Kibana의 약자다. Elasticsearch는 로그 데이터를 저장하고 빠르게 검색할 수 있는 분산 검색 엔진이다. Logstash는 로그를 수집하고 필요한 경우 데이터를 필터링하거나 가공하는 역할을 하며, Kibana는 Elasticsearch에 저장된 데이터를 시각화하는 웹 기반 대시보드 도구이다. ELK 스택의 가장 큰 강점은 복잡하고 세밀한 검색 쿼리를 지원한다는 점이다. 예를 들어, 특정 기간 동안 발생한 오류 로그 중 특정 사용자나 요청 ID와 관련된 것만 골라내는 것이 가능하다. 또한 Logstash가 제공하는 다양한 플러그인을 활용하면 로그를 원하는 형식으로 쉽게 가공할 수 있어, 매우 유연한 로그 처리 파이프라인을 구성할 수 있다. 그러나 ELK 스택은 구성 요소가 많고 설정이 복잡해 운영에 신경 쓸 부분이 많다. 특히 리소스 사용량이 상당히 높아, 소규모 환경이나 가벼운 서버에서는 부담이 될 수 있다.

2. Grafana + Loki

Grafana와 Loki 조합은 상대적으로 최근에 등장한 경량화된 로그 모니터링 솔루션이다. Grafana는 원래 메트릭 데이터를 시각화하는 도구로 유명하지만, Loki라는 로그 집계 시스템과 함께 사용하면 로그 데이터도 통합해 시각화할 수 있다. Loki는 Elasticsearch와 달리 인덱싱을 최소화하여 로그를 저장하기 때문에 자원 소모가 적고, 설치와 운영이 훨씬 간단하다. Promtail이라는 에이전트가 애플리케이션 로그를 수집해 Loki에 전달하며, Grafana는 이 데이터를 기반으로 로그와 메트릭을 한 화면에서 볼 수 있게 해준다. 이 방식의 가장 큰 장점은 메트릭과 로그를 함께 모니터링할 수 있다는 점이다. 예를 들어 서버 CPU 사용량이 급격히 올라간 시점의 로그를 바로 확인할 수 있어 문제 원인 분석이 쉬워진다. 하지만 Loki는 역색인을 사용하지 않고 메타데이터 기반 필터링을 하기에, ELK처럼 복잡한 텍스트 기반 검색은 어려운 편이다. 따라서 로그가 비교적 정형화되어 있어야 하고, 대규모 로그 분석에는 한계가 있을 수 있다.

Promtail

Promtail은 Grafana Labs에서 개발한 로그 수집 에이전트로, 서버에서 생성되는 로그 데이터를 수집해 Loki로 전송하는 역할을 한다. 역할 면에서는 Logstash나 Fluentd 같은 로그 수집기와 유사하지만, Loki와의 연동에 최적화된 경량화된 수집기다. 때문에 Loki를 사용하는 환경에서는 거의 필수적으로 함께 사용된다.

Promtail은 서버의 로그 파일을 실시간으로 감지하는 tail 방식으로 로그를 읽고, 필요한 메타데이터인 레이블(Label)을 붙여 Loki로 전송한다. 이 과정은 모두 비동기적으로 처리되며, 시스템 부하를 최소화하는 효율적인 구조를 가지고 있다.

 

로그 파일을 실시간으로 읽는 tail 방식

Promtail이 로그를 읽는 방식은 흔히 tail 방식이라 불린다. 로그 파일은 애플리케이션이 실행되면서 계속해서 새로운 로그가 뒤에 추가된다. Promtail은 로그 파일의 끝부분을 지속적으로 감시하며, 새로운 로그 라인이 추가되면 그 부분만 읽어 처리한다.

이 방식을 사용하면 전체 파일을 반복해서 읽는 부담이 없기 때문에, 최신 로그만 신속하고 효율적으로 수집할 수 있어 시스템 자원 낭비를 줄일 수 있다. 특히 로그가 끊임없이 쌓이는 서버 환경에서 실시간 모니터링에 매우 적합한 방식이라고 볼 수 있다.

 

로그에 메타데이터를 붙이는 레이블(Label) 시스템

Promtail은 단순히 로그 내용만 전송하는 것이 아니라, 로그에 메타데이터 역할을 하는 레이블(Label)을 함께 붙여 Loki로 보낸다. 이 레이블 덕분에 해당 로그가 어떤 서버에서, 어떤 애플리케이션에서, 그리고 어떤 환경(dev, prod)에서 발생했는지 명확하게 구분할 수 있다.

또한 레이블은 Promtail 설정 파일에서 자유롭게 커스텀할 수 있다. 예를 들어, 요청 URL이나 로그 레벨 같은 커스텀 레이블을 추가해 보다 세밀한 분류와 필터링이 가능하다. 이런 커스터마이징 덕분에 다양한 조건으로 로그를 효율적으로 조회하고 분석할 수 있다.


결국 어떤 도구를 선택할지는 서비스 규모와 요구 사항, 운영 환경에 따라 달라진다. ELK 스택은 대규모 서비스에서 고급 검색과 유연한 로그 가공이 필요한 경우에 적합하다. 반면 Grafana와 Loki는 이미 Prometheus와 Grafana를 사용해 메트릭 모니터링을 하는 환경에 로그 모니터링을 손쉽게 추가하고자 할 때나, 운영 단순화와 경량화를 추구하는 중소규모 서비스에 적합하다.

로그 기반 모니터링은 단순히 로그를 수집하는 데 그치지 않고, 그 데이터를 어떻게 활용하느냐가 핵심이다. 어떤 도구를 선택하든, 로그 포맷을 일관되게 관리하고 필요한 메타데이터를 잘 남겨야 효과적인 분석과 시각화가 가능하다. 앞으로는 AI 기반 이상 탐지나 자동화 알림과 같은 고도화된 기능까지 로그 기반 모니터링의 영역이 확장될 것이므로, 탄탄한 기본 체계를 갖추는 것이 무엇보다 중요하다.

프로젝트에 적용해보자

우리 서비스에 사용자가 점점 유입되면서 다양한 장애 상황을 마주하게 되었다. 특히 회원가입 시 이메일이 발송되지 않는 오류가 발생했을 때, 로그를 제대로 처리해두지 않아 docker logs -f 명령어로 일일이 로그를 확인해야 했다. 어떤 로그가 어디에 찍혔는지 찾는 데 시간이 오래 걸렸고, 문제 원인을 파악하는 데에도 큰 어려움이 있었다. 이런 반복적인 불편함을 줄이기 위해, 우리는 로그를 체계적으로 수집하고 분석하고 인프라 상태나 트래픽 흐름 등을 파악하기 위해 모니터링 툴을 도입하기로 결정했다. 

설계

현재 우리는 운영 서버와 개발 서버를 따로 운영하고 있다. 하지만 모니터링은 두 환경 모두를 대상으로 동일하게 진행하고 싶었기 때문에 각각의 EC2 인스턴스마다 별도로 모니터링 도구를 띄우는 방식은 비효율적이라고 판단했고 하나의 대시보드에서 모든 서버의 로그와 메트릭을 통합해 확인할 수 있는 구조를 원했다. 이러한 필요로 인해 중앙 집중형 로그 및 지표 모니터링 시스템을 도입하게 되었다.

로그 시각화

로그 시각화 도구로는 Grafana + Loki 조합을 선택했다. 이미 운영 중이던 Prometheus + Grafana 기반의 메트릭 모니터링 환경과 자연스럽게 통합할 수 있다는 점이 가장 큰 장점이었다. 별도의 툴을 새로 학습하거나 이질적인 대시보드를 따로 관리할 필요 없이, 로그와 메트릭을 하나의 화면에서 통합적으로 분석있기 때문에 빠른 도입이 가능했다.

또한 Loki는 Elasticsearch 기반의 ELK 스택에 비해 훨씬 가볍고 단순한 아키텍처를 가지고 있다. 로그 데이터를 저장할 때 인덱싱을 하지 않고, 메타데이터 기반으로 검색을 수행하기 때문에 리소스 사용량이 적고, 유지보수가 간편하다. 우리처럼 트래픽이 많지 않은 소규모 서비스에서는 과도한 검색 성능보다, 경량성과 운영 간소화가 훨씬 중요한 요소였다.

로그 수집도 매우 간단하게 시작할 수 있었다. 각 인스턴스에 Promtail 에이전트를 설치한 뒤, 애플리케이션의 로그 파일 경로만 지정하면 된다. 이 덕분에 별도의 복잡한 설정 없이도 다양한 조건의 로그를 효율적으로 조회할 수 있게 되었다. Logback 설정은 어떤 식으로 해야할 지에 대해서는 따로 블로그 글을 작성하였다. 해당 글을 참고하자.

트러블 슈팅

어느 날, Loki 컨테이너에서 OOM(Out Of Memory) 문제가 발생해 컨테이너가 강제로 종료된 사례가 있었다.

// Loki 컨테이너가 "시그널 9(SIGKILL)"에 의해 강제로 종료됨
1f2059519a88   grafana/loki:3.4.1    "/usr/bin/loki -conf…"   13 days ago   Exited (137) 26 hours ago  loki

// OOMKilled 여부 확인
docker inspect loki --format='{{.State.OOMKilled}}'
→ true

Grafana에서 로그가 조회되지 않는 현상이 발생했고, 모니터링 서버를 확인해본 결과, Loki 컨테이너가 정상 종료되지 않고 시스템(Docker)에 의해 강제로 종료된 상태(OOMKilled)임을 확인했다. 문제 원인을 파악하기 위해 로그를 확인하였고, docker inspect 명령어로 OOMKilled: true 상태가 확인되었다. 이는 컨테이너가 할당받은 메모리 한도를 초과해, Docker가 해당 프로세스를 강제로 종료시켰다는 뜻이다.

 

Loki의 메모리 한도 초과, 뭐가 원인이었을까?

Loki는 기본적으로 로그를 인메모리 버퍼에 저장한 뒤, 주기적으로 압축해서 파일로 플러시한다. 즉, 진행 과정을 적어보면 다음과 같다.

[로그 발생 (SpringBoot)]
      ↓
[Promtail에서 수집]
      ↓
[Loki로 전송]
      ↓
[Loki 메모리에 잠시 저장]
      ↓
[일정 시간마다 디스크에 저장 (flush)]

Loki는 모든 로그를 실시간으로 디스크에 기록하지 않고, 일정 시간 동안 메모리(RAM)에 버퍼링한 뒤 묶어서 압축하고 디스크에 기록한다.
하지만 우리 시스템은 /actuator/health, /metrics, Prometheus scrape 등으로 인해 초당 수천 건의 요청 로그가 promtail을 통해 Loki로 유입되는 상황이었다. 이로 인해 로그가 메모리에 과도하게 쌓이며 RAM 사용량이 급격히 증가했고, 결국 OOM(Out Of Memory)으로 컨테이너가 강제 종료되는 문제가 발생하였다.

이를 해결하기 위해 promtail의 pipeline_stages에 필터링 로직을 추가하여 /actuator/health, /metrics 등 불필요한 요청 URI를 포함하는 로그를 사전 차단(drop 처리)함으로써 Loki로 유입되는 로그량을 감소시켰다. 또한, 이번 문제와는 상관없지만 오래된 로그(7일 이상)는 자동으로 삭제되도록 retention 정책을 설정하여 디스크 공간도 함께 확보할 수 있도록 추가 설정하였다.

메트릭 기반 모니터링

또한, 메트릭 기반 모니터링도 함께 구축했다. 애플리케이션의 상태를 실시간으로 파악하기 위해 Spring Actuator를 활용하여 CPU 사용률, 메모리, HTTP 요청 수 등 다양한 메트릭을 수집했다. 이 메트릭은 애플리케이션 내에 내장된 /actuator/prometheus 엔드포인트를 통해 노출되며, Prometheus가 주기적으로 이 엔드포인트를 스크래핑(scraping) 하여 데이터를 수집하고 저장하도록 구성했다.

Prometheus는 여러 서버의 메트릭을 중앙에서 관리하는 역할을 하며, 수집한 데이터를 Grafana 대시보드에서 시각화하여 한눈에 서비스의 건강 상태를 확인할 수 있게 했다.


이런식으로 Grafana에서 로그와 서버의 상태를 한 눈에 확인하고 관리할 수 있게 되었다.

알람 시스템 구축

더 나아가 Grafana는 Alert(경보) 시스템도 제공한다. 이를 활용하면 특정 조건에 맞는 이상 징후가 감지되었을 때 자동으로 알림을 받을 수 있어, 빠른 대응이 가능하다. 예를 들어, 오류 로그가 급증하거나 서버 CPU 사용률이 일정 수준을 넘으면 즉시 알림을 보내 운영자가 즉각 문제를 인지하고 대응할 수 있도록 돕는다. 또한 이러한 알람들을 설정해서 특정 조건이 만족되면 슬랙으로 메세지를 보내도록 구성도 가능하다.

이렇게 Rule들을 설정해두고, 우리가 설정한 임계치를 초과하면 Slack으로 자동으로 알람이 전송되도록 설정하여, 문제 발생 시 즉각적인 대응이 가능해지도록 하였다.

'Etc' 카테고리의 다른 글

메시징 패턴 (feat. Pub/Sub, Queue, Event Stream)  (0) 2025.09.10
Flyway 도입기  (0) 2025.08.19
서킷 브레이커(Circuit Breaker) 알아보기  (0) 2025.07.23
캐시(Cache) 전략  (0) 2025.05.03
'Etc' 카테고리의 다른 글
  • 메시징 패턴 (feat. Pub/Sub, Queue, Event Stream)
  • Flyway 도입기
  • 서킷 브레이커(Circuit Breaker) 알아보기
  • 캐시(Cache) 전략
wing1008
wing1008
휘발을 막기 위한 기록
  • wing1008
    차곡차곡
    wing1008
  • 전체
    오늘
    어제
    • 분류 전체보기 (69) N
      • Spring (26)
      • JPA (11)
      • JAVA (2)
      • 데이터베이스 (9)
      • 운영체제 (2)
      • 네트워크 (3)
      • 자료구조&알고리즘 (5)
      • AI (1) N
      • Etc (5)
      • 끄적끄적 (5)
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
wing1008
모니터링 시스템 구축기
상단으로

티스토리툴바