옵저버빌리티 스택 도입 PRD

배경 (Background)

stock-application은 하이브리드 모노레포다. 요청 한 건이 frontend(Next.js) → aggregator(Spring BFF) → backend(Spring) → ml(FastAPI)의 4개 서비스를 거치고, Toss Open API 같은 외부 호출까지 동반한다. 그러나 현재 운영 가시성은 다음과 같이 비어 있다.

  • 계측 기반 전무 — backend·ml·aggregator·frontend 어디에도 Micrometer/Actuator/OpenTelemetry/Prometheus가 없다. 어떤 메트릭도 노출되지 않는다.
  • 분산 추적 부재 — 요청이 여러 서비스를 거치지만 하나의 trace로 엮이지 않는다. 느린 요청의 병목이 어느 서비스·어느 span인지 알 수 없다.
  • 인프라 메트릭 부재 — MySQL(Docker, :3308)만 실재하고, Kafka·Redis는 아직 도입 전이라 메트릭 수집 대상조차 없다.

장애·지연 분석을 로그 grep과 추측에 의존하는 상태다. Datadog 수준의 “요청 단위 trace + span + latency + 메트릭”을 단일 UI에서 보는 옵저버빌리티 기반이 필요하다.

목표

  1. 모든 분산 시스템(frontend·aggregator·backend·ml + Kafka consume)을 하나의 trace로 연결해 요청 단위로 span·latency를 UI에서 추적한다.
  2. application(Spring 2종·Python 1종)의 전 메트릭(JVM/HTTP/DB 풀/처리량·에러율·지연)을 수집·시각화한다.
  3. infrastructure(MySQL·Kafka·Redis) 3종을 모두 도입하고 각 exporter로 전 메트릭을 수집·시각화한다.
  4. 동일 텔레메트리를 SigNoz와 Grafana LGTM 두 스택에 동시 전송해 PoC로 비교하고, 평가 결과를 ADR로 확정해 운영 스택 1개를 선택한다.

요구사항

ID요구사항우선순위
R-01frontend·aggregator·backend·ml의 요청 경로가 단일 trace로 연결되어 UI에서 span·latency를 본다P0
R-02Kafka produce→consume 경로가 동일 trace에 span으로 표시된다 (message consume 추적)P0
R-03Spring(backend·aggregator) 전 메트릭(JVM·HTTP server/client·HikariCP·GC)을 수집한다P0
R-04Python(ml/FastAPI) 전 메트릭(요청 처리량·지연·에러율·외부 호출)을 수집한다P0
R-05MySQL·Kafka·Redis 인프라 메트릭을 exporter로 수집한다P0
R-06계측은 벤더 중립(OpenTelemetry/OTLP)으로 통일해 백엔드 스택 교체에 코드 변경이 없도록 한다P0
R-07동일 텔레메트리를 SigNoz·Grafana 두 스택에 동시 전송해 같은 조건으로 비교한다P0
R-08두 스택을 평가 축으로 비교한 결과를 산출하고 운영 스택을 ADR로 결정한다P0
R-09frontend(Next.js) 서버 런타임에서 요청이 trace에 합류한다P1
R-10임계치 위반 시 Discord webhook으로 알림을 보낸다P1
R-11전체 스택이 로컬 docker-compose 한 번으로 기동된다P1
R-12dev에서 이미 쓰는 Grafana Loki와의 로그 연속성을 비교 축에 포함한다P2

사용자 시나리오

시나리오 1: 느린 요청의 병목 찾기

  1. 사용자가 추천 목록을 요청하면 frontend → aggregator → (backend 손익 + ml 예측 병렬) → 응답이 발생한다.
  2. 운영자는 옵저버빌리티 UI에서 해당 trace 하나를 연다.
  3. 각 서비스의 span과 latency를 보고 ml 예측 span이 6초로 병목임을 즉시 식별한다.

시나리오 2: 인프라 메트릭 점검

  1. 운영자가 대시보드에서 MySQL 커넥션 수·Kafka consumer lag·Redis 메모리 사용량을 한 화면에서 본다.
  2. 임계치 초과 시 Discord로 알림을 받는다.

시나리오 3: 스택 비교(PoC)

  1. 동일 요청 부하를 발생시켜 SigNoz와 Grafana 양쪽에 동일 텔레메트리가 들어간다.
  2. 운영자는 평가 축(단일 UI 경험·trace 연결 품질·계측 호환성·exporter 커버리지·로컬 메모리·생태계 성숙도·Loki 연속성)으로 양쪽을 비교한다.
  3. 비교표를 근거로 운영 스택 1개를 ADR로 확정한다.

세부 정책

정책 1: 계측 표준은 OpenTelemetry로 통일

모든 서비스는 OTLP로만 텔레메트리를 내보낸다. 벤더 종속 에이전트(Datadog agent 등)를 쓰지 않는다. 백엔드 스택을 SigNoz↔Grafana로 바꿔도 서비스 코드·설정은 OTLP 엔드포인트만 바뀐다.

정책 2: 동일 텔레메트리 fan-out으로 공정 비교

서비스는 단일 OpenTelemetry Collector로만 전송하고, Collector가 SigNoz와 Grafana 양쪽으로 fan-out한다. 서비스가 두 백엔드를 직접 알지 않게 해, 두 스택이 완전히 동일한 입력을 받도록 보장한다.

정책 3: Kafka·Redis 신규 도입

모니터링 대상 3종을 모두 갖추기 위해 Kafka·Redis 컨테이너를 도입한다. 단 도메인 코드가 아직 Kafka를 쓰지 않으므로, message-consume 추적은 최소 샘플 produce→consume 경로로 검증한다(실제 도메인 Kafka 사용은 본 과제 범위 밖).

정책 4: 민감 정보·포트 기존 관례 준수

Discord webhook URL 등 민감 정보는 ~/.zshrc 환경변수로만 주입한다. 신규 컨테이너 포트는 기존 점유(3306/3307/3308 등)와 충돌하지 않게 배정한다.

범위 외

  • 도메인 기능에 Kafka를 실제로 적용하는 작업 (이벤트 기반 아키텍처 전환)
  • 프로덕션(원격 서버) 옵저버빌리티 배포 — 본 과제는 로컬 docker-compose 한정
  • 브라우저(클라이언트) RUM(Real User Monitoring) 풀 계측 — frontend는 서버 런타임 trace 합류까지만
  • 로그 장기 보존·비용 최적화 정책

관련 문서