티스토리 뷰

반응형

분산 트레이싱은 언제부터 붙여야 할까? OpenTelemetry로 요청 흐름을 끝까지 추적하는 방법 — FastAPI · Spring Boot · Node.js

로그를 열심히 남겼고, 메트릭도 붙였는데도 답답한 순간이 옵니다.
“느린 건 보이는데 어디서 느린지 모르겠다”는 순간이요.

예를 들어 이런 상황이죠.

  • API 응답이 2.8초나 걸린다
  • DB는 100ms 정도다
  • 외부 결제 API도 가끔 느리다
  • 큐 등록도 들어간다
  • 그런데 정확히 어디가 병목인지 한눈에 안 보인다

이때 필요한 게 분산 트레이싱(distributed tracing) 입니다.
OpenTelemetry는 벤더 중립 관측 프레임워크이고, 코드 기반 계측과 제로코드 계측을 모두 지원합니다. 또 context propagation을 통해 서로 다른 서비스에서 생성된 신호를 연결할 수 있게 해줍니다. (OpenTelemetry)

이번 글에서는 이걸 FastAPI, Spring Boot, Node.js 기준으로 풀어보겠습니다.


분산 트레이싱이란?

분산 트레이싱은 하나의 요청이 여러 서비스와 컴포넌트를 지나갈 때 그 흐름을 하나로 묶어 보는 방법입니다.
OpenTelemetry 문서는 관측 가능하려면 traces, metrics, logs 같은 신호를 내보내도록 계측되어야 하고, context propagation 덕분에 서로 다른 위치에서 생성된 신호를 연관 지을 수 있다고 설명합니다. (OpenTelemetry)

쉽게 말하면 이런 겁니다.

  • 사용자가 /orders 요청
  • API 서버가 인증 확인
  • DB 조회
  • 외부 결제 서비스 호출
  • 메시지 큐 등록
  • 응답 반환

로그만 보면 각각 따로 보이고, 메트릭만 보면 평균값만 보입니다.
트레이싱은 이 전체를 한 개의 trace로 묶어 보여줍니다. (OpenTelemetry)


trace와 span은 어떻게 다를까

이건 처음에 조금 헷갈리는데, 이렇게 보면 쉽습니다.

  • trace: 요청 전체 이야기
  • span: 그 이야기 안의 한 구간

예를 들면:

  • trace: POST /payments
    • span: controller 진입
    • span: DB 사용자 조회
    • span: 외부 결제 API 호출
    • span: 결제 저장
    • span: 응답 반환

그래서 트레이싱을 붙이면 “느렸다”가 아니라
“외부 결제 호출 span이 1.9초를 먹고 있었다” 같은 식으로 보입니다. 이게 진짜 큽니다.


로그와 메트릭이 있는데도 트레이싱이 필요한 이유

저는 이걸 보통 이렇게 구분합니다.

  • 로그: 무슨 일이 있었는지
  • 메트릭: 얼마나 많이, 얼마나 자주 느린지
  • 트레이싱: 어느 경로에서 느린지

OpenTelemetry 문서도 code-based instrumentation은 애플리케이션 내부에서 더 깊고 풍부한 telemetry를 주고, zero-code instrumentation은 애플리케이션 가장자리에서 일어나는 일을 잘 보여준다고 설명합니다. 둘을 같이 쓸 수도 있고요. (OpenTelemetry)

즉 트레이싱은 로그나 메트릭의 대체가 아니라,
그 둘 사이를 연결해주는 느낌에 가깝습니다.


OpenTelemetry는 자동 계측과 수동 계측이 있다

이 구분은 꼭 알아두면 좋습니다.

자동 계측

코드를 거의 안 바꾸고 프레임워크/라이브러리 호출을 자동으로 계측합니다.
OpenTelemetry는 Python과 JavaScript 모두 제로코드 계측을 지원하고, Python은 opentelemetry-distro와 opentelemetry-instrument, JavaScript는 @opentelemetry/auto-instrumentations-node/register 방식으로 시작할 수 있다고 설명합니다. (OpenTelemetry)

수동 계측

직접 span이나 observation을 만들어 비즈니스 구간을 더 자세히 찍습니다.
OpenTelemetry는 code-based instrumentation이 애플리케이션 내부에 더 깊은 인사이트를 준다고 설명합니다. Spring Boot도 ObservationRegistry로 커스텀 observation을 만드는 예제를 공식 문서에 제공합니다. (OpenTelemetry)

제 경험상 초반엔 이렇게 가는 게 제일 좋았습니다.

  1. 자동 계측 먼저
  2. 병목이 잘 안 보이는 핵심 비즈니스 구간만 수동 계측 추가

그럼 언제부터 붙이면 좋을까

저는 아래 셋 중 하나면 붙일 가치가 있다고 봅니다.

  • 서비스가 2개 이상으로 나뉘기 시작했다
  • 외부 API 호출이 2개 이상 엮인다
  • “느린 건 보이는데 정확한 병목이 안 보인다”가 반복된다

반대로 아주 작은 CRUD 앱이고, 외부 의존성도 거의 없으면
로그 + 메트릭만으로도 한동안 충분할 수 있습니다.


1) FastAPI에서 OpenTelemetry 시작하기

OpenTelemetry Python 문서는 Python에서 자동 계측을 위해 opentelemetry-distro와 opentelemetry-exporter-otlp를 설치하고, opentelemetry-bootstrap -a install 후 opentelemetry-instrument로 앱을 실행하는 방식을 안내합니다. 또 FastAPI 같은 프레임워크도 지원 대상이라고 설명합니다. (OpenTelemetry)

가장 빠른 시작: 자동 계측

설치

pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install

실행

OTEL_SERVICE_NAME=fastapi-order-api \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=console \
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4317 \
opentelemetry-instrument uvicorn main:app --reload

위 방식은 OpenTelemetry Python 제로코드 문서에서 안내하는 기본 흐름입니다. opentelemetry-distro가 API, SDK, bootstrap, instrument 도구를 제공하고, 환경변수로 service name과 exporter endpoint를 지정할 수 있습니다. (OpenTelemetry)

FastAPI 예제 코드

# main.py
from fastapi import FastAPI
import time

app = FastAPI()

@app.get("/health")
def health():
    return {"ok": True}

@app.get("/api/orders/{order_id}")
def get_order(order_id: str):
    # 예제용 느린 구간
    time.sleep(0.15)
    return {"order_id": order_id, "status": "paid"}

이 상태에서도 FastAPI 프레임워크 호출, HTTP 서버 처리 같은 기본 구간은 자동 계측으로 잡을 수 있습니다. (OpenTelemetry)

수동 계측은 언제?

자동 계측만으로는 “비즈니스 핵심 단계”가 잘 안 보일 수 있습니다.
예를 들면 할인 계산, 재고 예약, 결제 승인처럼 프레임워크 바깥의 도메인 로직이요.

이때는 수동 계측을 덧붙이는 게 좋습니다. OpenTelemetry는 code-based instrumentation이 애플리케이션 내부에 더 깊은 인사이트를 준다고 설명합니다. (OpenTelemetry)


2) Spring Boot에서 OpenTelemetry 시작하기

반응형

Spring Boot는 이 부분이 정말 잘 되어 있습니다.
Actuator가 Micrometer Tracing의 dependency management와 auto-configuration을 제공하고, 공식 지원 tracer로 OpenTelemetry with OTLP를 안내합니다. 또 Spring 팀은 OpenTelemetry를 공식적으로 Micrometer와 OTLP exporter를 통해 지원한다고 설명합니다. (Home)

의존성

Spring Boot tracing 문서는 OpenTelemetry + OTLP를 위해 org.springframework.boot:spring-boot-starter-opentelemetry를 사용하라고 안내합니다. (Home)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-opentelemetry'
}

설정

Spring Boot 공통 프로퍼티 문서는 management.opentelemetry.tracing.export.otlp.endpoint가 OTel collector HTTP API URL이라고 설명합니다. tracing 문서는 management.tracing.sampling.probability로 샘플링 비율을 조정할 수 있고, 기본은 10%라고 설명합니다. (Home)

spring:
  application:
    name: spring-payment-api

management:
  tracing:
    sampling:
      probability: 1.0
  opentelemetry:
    tracing:
      export:
        otlp:
          endpoint: "http://localhost:4318/v1/traces"

간단한 코드

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @GetMapping("/api/orders/{orderId}")
    public Object getOrder(@PathVariable String orderId) throws Exception {
        Thread.sleep(150);
        return java.util.Map.of(
                "orderId", orderId,
                "status", "paid"
        );
    }
}

이 상태만으로도 Spring MVC 요청 흐름과 기본 trace 생성이 잡히고, auto-configured builder를 쓰면 네트워크를 넘는 trace propagation도 자동으로 연결됩니다. Spring Boot 문서는 RestTemplateBuilder, RestClient.Builder, WebClient.Builder를 사용해야 자동 propagation이 동작한다고 명시합니다. 직접 클라이언트를 만들면 자동 trace propagation이 안 된다고도 설명합니다. (Home)

수동 계측 예제

Spring Boot tracing 문서는 ObservationRegistry를 주입받아 커스텀 observation을 만들 수 있다고 설명합니다. (Home)

import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.stereotype.Service;

@Service
public class PricingService {

    private final ObservationRegistry observationRegistry;

    public PricingService(ObservationRegistry observationRegistry) {
        this.observationRegistry = observationRegistry;
    }

    public int calculatePrice(int price) {
        return Observation.createNotStarted("price-calculation", observationRegistry)
                .lowCardinalityKeyValue("module", "pricing")
                .observe(() -> price - 1000);
    }
}

이 방식이 좋은 건,
도메인 로직의 중요한 경계를 span처럼 남길 수 있다는 점입니다.


3) Node.js에서 OpenTelemetry 시작하기

OpenTelemetry JavaScript 문서는 Node.js getting started와 zero-code instrumentation 문서를 따로 제공합니다. Node.js에서는 traces와 metrics를 계측할 수 있고, 제로코드 계측으로 많은 프레임워크와 라이브러리를 소스 수정 없이 잡을 수 있다고 설명합니다. 다만 Node.js OTel logging 라이브러리는 아직 개발 중이라 logs 예제는 제공하지 않는다고 안내합니다. (OpenTelemetry)

가장 빠른 시작: 제로코드 계측

설치

npm install --save @opentelemetry/api
npm install --save @opentelemetry/auto-instrumentations-node

실행

export OTEL_TRACES_EXPORTER="otlp"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_SERVICE_NAME="node-order-api"
export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
node app.js

위 방식은 OpenTelemetry JavaScript 제로코드 문서가 안내하는 공식 시작 방식입니다. OTEL_NODE_RESOURCE_DETECTORS나 OTEL_LOG_LEVEL 같은 환경변수도 함께 설정할 수 있습니다. (OpenTelemetry)

Express 예제 코드

// app.js
import express from "express";

const app = express();

app.get("/health", (req, res) => {
  res.json({ ok: true });
});

app.get("/api/orders/:orderId", async (req, res) => {
  await new Promise((resolve) => setTimeout(resolve, 150));
  res.json({
    orderId: req.params.orderId,
    status: "paid",
  });
});

app.listen(3000, () => {
  console.log("server running on http://localhost:3000");
});

이 정도만으로도 Express 요청 흐름 같은 기본 span은 자동 계측으로 잡을 수 있습니다. OpenTelemetry JS 문서도 Express 같은 프레임워크를 포함해 많은 라이브러리가 지원 대상이라고 설명합니다. (OpenTelemetry)

Node.js에서 꼭 기억할 점

OpenTelemetry JS 문서는 현재 Node.js 쪽 OTel logging 라이브러리는 아직 개발 중이라고 안내합니다. 그래서 지금 시점에 Node.js에선 우선 trace와 metrics 중심으로 시작하는 게 현실적입니다. 로그는 기존 Pino 같은 구조화 로그와 같이 가져가는 편이 더 낫습니다. (OpenTelemetry)


자동 계측만으로 충분할까

처음엔 꽤 충분합니다.
특히 이런 건 자동 계측으로 효과가 바로 납니다.

  • HTTP 서버 요청
  • HTTP 클라이언트 호출
  • 프레임워크 레벨 처리
  • 일부 DB/라이브러리 호출

OpenTelemetry는 제로코드 계측이 애플리케이션 가장자리에서 일어나는 일을 빨리 보여주는 데 좋다고 설명합니다. (OpenTelemetry)

그런데 이런 건 자동 계측만으론 부족할 수 있습니다.

  • 할인 규칙 계산
  • 재고 예약
  • 결제 승인 핵심 단계
  • 큐 등록 후 비즈니스 분기
  • “정말 이 단계가 느린지” 확인하고 싶은 도메인 로직

이때는 수동 계측을 섞는 게 맞습니다.


context propagation이 중요한 이유

트레이싱의 진짜 맛은 여기 있습니다.

서비스 A에서 시작한 요청이 서비스 B, C로 넘어가도
같은 trace로 이어져야 의미가 있거든요.

OpenTelemetry 문서는 context propagation이 built-in이라 서로 다른 위치에서 생성된 신호를 연관 지을 수 있다고 설명합니다. Spring Boot는 auto-configured RestTemplateBuilder, RestClient.Builder, WebClient.Builder를 써야 자동 propagation이 된다고 명시합니다. (OpenTelemetry)

즉 단일 서버 안에서만 trace가 끊기지 않게 보는 게 아니라,
네트워크를 건너도 이어지게 하는 것이 핵심입니다.


sampling은 어떻게 생각해야 할까

이건 운영에 들어가면 꼭 마주칩니다.

모든 요청을 100% 다 trace로 보내면 보기엔 좋지만,
트래픽이 많아지면 비용과 저장량이 커집니다.

Spring Boot는 기본적으로 10%만 샘플링한다고 설명하고, management.tracing.sampling.probability로 조절할 수 있다고 안내합니다. OpenTelemetry 쪽 샘플러도 always-on, always-off, trace-id-ratio, parent-based-* 등으로 조절할 수 있습니다. (Home)

초반엔 보통 이렇게 생각하면 좋습니다.

  • 개발/테스트: 100%
  • 운영 초반: 높게
  • 운영 트래픽 증가 후: 필요한 수준으로 낮추기

로그와 트레이싱은 같이 가야 한다

이건 꼭 같이 말하고 싶어요.

Spring Boot tracing 문서는 correlation ID가 기본적으로 traceId와 spanId로 만들어지고, 로그에 자동 포함될 수 있다고 설명합니다. logging.pattern.correlation로 포맷도 바꿀 수 있고요. (Home)

이게 중요한 이유는,
로그 한 줄과 trace 화면을 연결할 수 있기 때문입니다.

즉 앞으로 운영에선 이런 식이 훨씬 좋아집니다.

  • 로그에서 traceId 찾기
  • 그 traceId로 트레이싱 화면 열기
  • 느린 span 확인
  • 해당 구간 코드나 외부 API 병목 파악

로그, 메트릭, 트레이싱이 여기서 진짜 하나로 붙습니다.


실무에서 자주 하는 실수

1. 처음부터 수동 계측을 너무 많이 넣는다

OpenTelemetry 문서가 말하듯, 제로코드 계측과 코드 기반 계측은 같이 쓸 수 있습니다. 초반엔 자동 계측 먼저가 훨씬 현실적입니다. (OpenTelemetry)

2. trace는 붙였는데 propagation이 끊긴다

Spring Boot 문서는 auto-configured HTTP client builder를 쓰지 않으면 자동 trace propagation이 안 된다고 분명히 말합니다. 이건 진짜 자주 놓칩니다. (Home)

3. 샘플링을 무조건 100%로 둔다

개발에선 괜찮지만 운영 트래픽이 커지면 비용과 저장량이 금방 불어납니다. Spring Boot도 기본 10% 샘플링을 두는 이유가 있습니다. (Home)

4. 로그와 trace를 따로 생각한다

traceId가 로그에 안 남으면, 막상 장애 때 연결이 잘 안 됩니다. Spring은 correlation ID를 기본 지원하니 이런 감각을 같이 가져가는 게 좋습니다. (Home)

5. Node.js에서 logs까지 OTel로 한 번에 하려 든다

현재 Node.js OTel logging 라이브러리는 아직 개발 중이라고 공식 문서가 안내하므로, 지금은 traces/metrics 먼저가 현실적입니다. (OpenTelemetry)


FAQ

Q. 분산 트레이싱은 작은 서비스에도 필요할까요?

작은 CRUD 앱 하나라면 꼭 필요하진 않을 수 있습니다. 하지만 외부 API가 여러 개 붙거나 서비스가 둘 이상으로 나뉘면 가치가 빠르게 커집니다. 병목 위치를 보는 데 로그+메트릭만으로 부족해지는 순간이 오거든요.

Q. OpenTelemetry는 자동 계측만 써도 되나요?

처음엔 아주 좋습니다. OpenTelemetry도 제로코드 계측을 빠른 시작점으로 설명합니다. 다만 비즈니스 핵심 구간은 수동 계측을 섞는 편이 더 깊은 인사이트를 줍니다. (OpenTelemetry)

Q. Spring Boot에서는 어떤 의존성부터 넣으면 되나요?

공식 문서 기준 OpenTelemetry + OTLP 시작점은 spring-boot-starter-opentelemetry 입니다. OTLP export는 management.opentelemetry.tracing.export.otlp.* 프로퍼티로 설정합니다. (Home)

Q. FastAPI에서는 수동 계측보다 자동 계측이 먼저인가요?

보통 그렇습니다. OpenTelemetry Python 문서도 제로코드 계측을 먼저 설명하고, FastAPI 같은 프레임워크도 지원 대상이라고 안내합니다. (OpenTelemetry)

Q. Node.js는 OpenTelemetry를 바로 써도 괜찮나요?

네. JavaScript 문서는 제로코드 계측으로 Node.js 애플리케이션을 소스 수정 없이 계측할 수 있다고 설명합니다. 다만 logs는 아직 traces/metrics만큼 성숙하지 않으니, trace/metrics 중심으로 시작하는 편이 좋습니다. (OpenTelemetry)


핵심 요약

  • 분산 트레이싱은 “느리다”를 “어디서 느린지”로 바꿔줍니다.
  • OpenTelemetry는 제로코드 계측과 코드 기반 계측을 모두 지원하고, context propagation으로 여러 서비스의 신호를 연결합니다. (OpenTelemetry)
  • FastAPI와 Node.js는 자동 계측으로 빠르게 시작하고, Spring Boot는 spring-boot-starter-opentelemetry와 OTLP 설정으로 공식 지원 흐름을 타는 게 좋습니다. (OpenTelemetry)
  • Spring Boot는 correlation ID와 자동 propagation 지원이 강해서, 로그·메트릭·트레이싱을 같이 가져가기에 좋습니다. (Home)
  • 검색에 잘 걸리는 기술 글은 질문형 제목, 초반 정답, 정의 문장, 바로 실행 가능한 코드, FAQ 구조가 강합니다.

출처

  • OpenTelemetry 공식 문서 — Documentation overview. (OpenTelemetry)
  • OpenTelemetry 공식 문서 — Instrumentation concepts, code-based vs zero-code, context propagation. (OpenTelemetry)
  • OpenTelemetry 공식 문서 — Python getting started by example. (OpenTelemetry)
  • OpenTelemetry 공식 문서 — Python zero-code instrumentation. (OpenTelemetry)
  • OpenTelemetry 공식 문서 — Node.js getting started. (OpenTelemetry)
  • OpenTelemetry 공식 문서 — JavaScript zero-code instrumentation. (OpenTelemetry)
  • Spring Boot 공식 문서 — Observability / OpenTelemetry support. (Home)
  • Spring Boot 공식 문서 — Tracing, supported tracers, sampling, custom observations. (Home)
  • Spring Boot 공식 문서 — correlation IDs and automatic propagation with builders. (Home)
  • Spring Boot 공식 문서 — OTLP tracing properties. (Home)

백엔드개발, FastAPI, SpringBoot, Nodejs, Express, 분산트레이싱, OpenTelemetry, OTLP, Observability, 백엔드시리즈

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함
반응형