7분 읽기

사이드 프로젝트에 관측성 더하기

이 글은 사이드 프로젝트의 관측성 설계·운영 기록을 바탕으로 정리했습니다. 계정, 토큰, 내부 인스턴스 식별자는 제외했습니다.

홈 서버를 운영 경로에 추가하기 전에 먼저 답해야 할 질문이 있었다. “홈 서버가 동작하는가?”가 아니라 **“문제가 생겼을 때 어디서, 어떤 신호로, 얼마나 빨리 알 수 있는가?”**였다.

관측성은 서비스 밖에서 내부 상태를 이해할 수 있게 만드는 방법이다. Grafana, Prometheus, OpenTelemetry는 모두 관측성에 쓰이지만 역할은 서로 다르다. 이 프로젝트에서는 신호가 만들어지고 수집되고 저장된 뒤 화면에 보이는 순서를 먼저 나눴다. 메트릭부터 시작하고 트레이스와 로그는 나중에 추가하기로 했다.

메트릭, 트레이스, 로그는 무엇이 다를까?

신호주로 답하는 질문사이드 프로젝트에서의 예
메트릭언제부터, 얼마나 자주 문제가 생겼는가?HTTP 5xx 비율, p95 지연, JVM heap, 디스크 사용률
트레이스요청 한 건이 정확히 어디에서 느려졌는가?API → DB → 객체 저장소로 이어지는 요청 구간
로그그 시점에 어떤 예외와 맥락이 있었는가?배포·기동 메시지, DB 연결 실패, 예외가 발생한 호출 경로

세 신호는 서로 대체재가 아니다. 5xx 비율 증가라는 메트릭으로 이상 구간을 찾고, 같은 시간대의 트레이스로 병목 구간을 좁힌 뒤, 연결된 로그에서 구체적인 예외를 읽는 흐름을 목표로 했다.

flowchart LR
  A["애플리케이션 · JVM · 서버"] --> B["수집·가공\nPrometheus · Alloy"]
  B --> C["저장\nMimir · Tempo · Loki"]
  C --> D["대시보드 · 탐색 · 알림"]
  D --> E["장애 감지와 원인 분석"]

이미 있던 모니터링 구성 활용하기

사이드 프로젝트 백엔드에는 이미 Spring Boot Actuator, Micrometer, Prometheus registry가 있었다. Prometheus는 Actuator가 공개한 메트릭 주소를 주기적으로 읽어 수집한다. 이 기존 구성을 새 도구로 바꾸지 않고 첫 번째 수집 경로로 유지했다. Spring Boot의 Metrics 문서가 이 구성의 출발점이다.

구성요소맡긴 역할이번 선택
Actuator + Micrometer애플리케이션과 JVM 메트릭 생성·노출유지
Prometheus메트릭 주소를 주기적으로 수집하고 로컬에 보관유지하고 remote_write로 Cloud 전송 추가
Grafana여러 데이터 저장소의 조회와 시각화로컬 화면은 유지, Cloud 화면은 외부 관제에 사용
Grafana Cloud외부 저장소, 대시보드, 알림, 외부 상태 확인메트릭과 외부 가용성부터 도입
OpenTelemetry Java Agent + Grafana Alloy트레이스·로그 수집과 가공개인정보 처리 규칙 검증 뒤 도입

Prometheus와 Grafana가 겹쳐 보이지만 역할은 다르다. 전자는 메트릭을 수집·저장하는 엔진이고, 후자는 Prometheus를 포함한 저장소를 조회해 대시보드와 알림을 제공하는 UI·운영 계층이다. 이 구분을 해 두면 “Grafana를 설치했으니 메트릭이 저장된다” 같은 착각을 피할 수 있다.

메트릭부터 시작한 이유

첫 번째 목표는 홈 서버가 운영 경로에 들어오기 전, 클라우드와 홈 서버를 같은 화면에서 비교하는 것이었다. 기존 Prometheus가 이미 애플리케이션·JVM·호스트 메트릭을 수집하고 있었으므로 다음 경로가 가장 작은 변경이었다.

flowchart LR
  A["Spring Boot\nMicrometer · Actuator"] <-->|"scrape"| P["Prometheus"]
  N["node exporter"] <-->|"scrape"| P
  P -->|"remote_write"| G["Grafana Cloud metrics"]
  G --> D["Dashboard · Alert"]

이 결정에는 두 가지 이유가 있었다.

  1. 기존 로컬 대시보드와 PromQL 질의를 깨지 않고, 외부 관제만 추가할 수 있다.
  2. 홈 서버와 클라우드 서버에 같은 라벨 규칙을 적용해 project, service, instance, environment, role 기준으로 나눠 볼 수 있다.

같은 이름의 메트릭이라도 서버를 구분하는 라벨이 없으면 어느 서버가 요청을 처리했는지 알 수 없다. 반대로 요청 ID나 사용자 ID처럼 값의 종류가 계속 늘어나는 정보를 라벨로 넣으면 저장할 데이터와 비용이 크게 늘어난다. 이 프로젝트에서는 운영에 꼭 필요한 구분값만 라벨로 사용했다.

트레이스와 로그를 나중에 추가한 이유

OpenTelemetry는 계측 API와 OTLP 같은 표준을 제공하고, Grafana Alloy는 Prometheus scrape와 OpenTelemetry 수신·가공을 함께 수행할 수 있는 수집기다. 둘은 경쟁 관계가 아니라 표준과 그 표준을 사용하는 수집기 구현에 가깝다. OpenTelemetry 문서Grafana Alloy 문서를 함께 읽으면 이 역할 분담이 더 분명해진다.

하지만 자동으로 데이터를 수집할 수 있다고 바로 운영에 적용해도 안전한 것은 아니다. URL의 쿼리 문자열, SQL 문장, 예외 메시지, 객체 저장소 경로, 인증 정보가 트레이스의 상세 값이나 로그에 섞일 수 있다. 사용자 데이터를 다루는 사이드 프로젝트에서는 이 위험이 특히 컸다.

따라서 순서를 바꿨다.

  1. 메트릭과 외부 상태 확인으로 서비스 가용성과 자원 상태를 먼저 감시한다.
  2. 원본 로그에 민감한 정보가 있는지 점검하고, 불필요한 수집 옵션을 끈다.
  3. Alloy의 필터와 변환 단계에서 민감한 값을 한 번 더 제거한다.
  4. 필요한 트레이스부터 일부만 골라 수집한다.
  5. 로그는 개인정보, 토큰, 서명된 임시 URL이 제거되는지 확인한 뒤 전송한다.

이 순서는 데이터를 더 많이 모으는 것보다 안전하게 설명 가능한 데이터만 모으는 것을 우선한다.

알림이 실제로 오는지 시험하기

대시보드에 그래프가 나온다고 알림까지 정상이라는 뜻은 아니다. 이 프로젝트에서는 서버 메트릭 수집 중단, 외부 API 상태 확인 실패, 디스크 사용률, JVM 메모리, HTTP 5xx·지연, DB 연결 풀 같은 조건을 알림 규칙으로 만들었다. 임시 조건으로 실제 알림을 발생시켜 메일 수신을 확인한 다음, 운영 기준값과 알림 대기 시간을 복원했다.

이 과정에서 얻은 기준은 단순하다.

검증 대상확인해야 할 것
데이터 수집remote_write 전송 실패가 없고, 애플리케이션·서버 시계열이 모두 보이는가
외부 가용성서비스 바깥의 probe가 공개 API와 홈페이지를 확인하는가
알림 전달문제 발생과 해결 알림이 모두 운영자에게 도달하는가
전환 검증주 서버와 예비 서버의 요청·서버 메트릭이 같은 대시보드에서 구분되는가

특히 외부 상태 확인(synthetic check)은 애플리케이션 내부의 상태 확인과 다르다. 서버 내부 상태가 UP이어도 DNS, TLS, 프록시, 네트워크 문제로 사용자는 접속하지 못할 수 있다. 그래서 실제 사용자처럼 외부에서 접속하는 확인 절차를 별도로 두었다.

핵심 정리

이 사이드 프로젝트에서 관측성은 “Grafana Cloud를 설치했다”로 끝나는 작업이 아니었다. 기존 메트릭 경로를 보존한 채 외부 관제와 알림을 먼저 만들고, 홈 서버 전환의 성공·실패를 인스턴스별 신호로 확인할 수 있게 하는 작업이었다.

다음 단계의 과제도 남아 있다. trace는 필요한 구간부터 샘플링과 개인정보 제거 규칙을 검증하며 활성화해야 하고, 로그 전송은 더 엄격한 검토가 필요하다. 그러나 이 순서를 지키면 새로운 신호를 추가해도 기존 운영 경로를 잃지 않고, “문제가 없다”가 아니라 “문제가 없음을 어떤 데이터로 확인했는가”를 설명할 수 있다.

참고 자료