opentelemetry에 대한 이해

OpenTelemetry는 다양한 백엔드와 호환되어 소프트웨어의 성능 분석 및 관측성을 향상시킵니다.

opentelemetry에 대한 이해
Photo by Tobias Tullius / Unsplash

1. OpenTelemetry란?

OpenTelemetry (OTel)은 CNCF에서 인큐베이팅 중인 관측성 프레임워크로, 도구, API, SDK 모음으로 구성되어 있습니다. OTel은 소프트웨어 성능과 동작을 분석하고 이해하기 위해 원격 측정 데이터를 생성, 수집, 관리 및 내보내는 표준을 정의하고 있습니다.

여기서 원격 측정 데이터는 추적(traces), 메트릭(metrics) 및 로그(logs), 즉 "관측성의 세 가지 축"을 포함합니다. OpenTelemetry는 OpenTracing과 OpenCensus 기술을 병합한 결과입니다.

2. OpenTelemetry를 사용하는 이유

OpenTelemetry는 특정 벤더나 도구에 종속되지 않습니다. 즉, 벤더 종속에서 벗어나 Prometheus, Jaeger, Dynatrace 등 다양한 관측성 백엔드와 함께 사용할 수 있습니다. 또한 현재의 Observability의 중요성이 대두되며 애플리케이션을 쉽게 관측하기 위한 방법들이 필요했으며 이는 인프라, 런타임 환경에 관계없이 통합되어 동작하는 OpenTelemetry가 도입되는데 충분한 환경으로 구성되었습니다.

3. 아키텍쳐

Notion Image

OTel은 원격 측정 데이터를 생성하기 위해 애플리케이션을 계측하는 API와 SDK를 제공(Application level)하며, 이 데이터는 otel-config.yaml에서 제공하는 구성에 따라 데이터를 수집, 처리 및 백엔드로 내보내는 수집기(Collector level)로 전송됩니다. 모든 전송은 OpenTelemetry 프로토콜(OTLP)을 사용하여 수행됩니다.

이 프로토콜에 대한 자세한 내용은 OpenTelemetry Protocol (OTLP) 와 Specification Status Summary를 통해 확인할 수 있습니다 .

4. OpenTelemetry 테스트

앞선 내용들을 바탕으로 실제 OTel 데모 환경을 구축해보고자 합니다. 여러 언어로 생성된 애플리케이션 데모가 존재하며 각 데모는 아래 링크를 통해 확인할 수 있으며, Github에서 데모 애플리케이션을 클론합니다.

git clone https://github.com/open-telemetry/opentelemetry-demo.git

해당 Repository에서 원격 측정 데이터(telemetry data)가 처리되는 방식을 정의하는 설정 파일src/otelcollector/otelcol-config.yml을 살펴보겠습니다. 해당 파일은 OpenTelemetry를 구성하는 핵심 파일로 자세하게 파고 들어가본다면 내부 구조를 쉽게 이해할 수 있습니다.

# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

receivers: # 데이터를 수집하는 방식을 정의합니다.
  otlp:
    protocols:
      grpc:
        endpoint: ${env:OTEL_COLLECTOR_HOST}:${env:OTEL_COLLECTOR_PORT_GRPC}
      http:
        endpoint: ${env:OTEL_COLLECTOR_HOST}:${env:OTEL_COLLECTOR_PORT_HTTP}
        cors:
          allowed_origins:
            - "http://*"
            - "https://*"
  httpcheck/frontend-proxy:
    targets:
      - endpoint: http://frontend-proxy:${env:ENVOY_PORT}
  docker_stats:
    endpoint: unix:///var/run/docker.sock
  redis:
    endpoint: "valkey-cart:6379"
    username: "valkey"
    collection_interval: 10s
  # Host metrics
  hostmetrics:
    root_path: /hostfs
    scrapers:
      cpu:
        metrics:
          system.cpu.utilization:
            enabled: true
      disk:
      load:
      filesystem:
        exclude_mount_points:
          mount_points:
            - /dev/*
            - /proc/*
            - /sys/*
            - /run/k3s/containerd/*
            - /var/lib/docker/*
            - /var/lib/kubelet/*
            - /snap/*
          match_type: regexp
        exclude_fs_types:
          fs_types:
            - autofs
            - binfmt_misc
            - bpf
            - cgroup2
            - configfs
            - debugfs
            - devpts
            - devtmpfs
            - fusectl
            - hugetlbfs
            - iso9660
            - mqueue
            - nsfs
            - overlay
            - proc
            - procfs
            - pstore
            - rpc_pipefs
            - securityfs
            - selinuxfs
            - squashfs
            - sysfs
            - tracefs
          match_type: strict
      memory:
        metrics:
          system.memory.utilization:
            enabled: true
      network:
      paging:
      processes:
      process:
        mute_process_exe_error: true
        mute_process_io_error: true
        mute_process_user_error: true
  # Collector metrics
  prometheus:
    config:
      scrape_configs:
        - job_name: 'otel-collector'
          scrape_interval: 10s
          static_configs:
            - targets: ['0.0.0.0:8888']

exporters: # 수집된 데이터를 내보내는 방식을 정의합니다.
  debug:
  otlp:
    endpoint: "jaeger:4317"
    tls:
      insecure: true
  otlphttp/prometheus:
    endpoint: "http://prometheus:9090/api/v1/otlp"
    tls:
      insecure: true
  opensearch:
    logs_index: otel
    http:
      endpoint: "http://opensearch:9200"
      tls:
        insecure: true

processors: # 수집된 데이터를 변환하거나 필터링하는 방법을 정의합니다.
  batch:
  transform:
    error_mode: ignore
    trace_statements:
      - context: span
        statements:
          # could be removed when https://github.com/vercel/next.js/pull/64852 is fixed upstream
          - replace_pattern(name, "\\?.*", "")
          - replace_match(name, "GET /api/products/*", "GET /api/products/{productId}")

connectors: # 다른 시스템과 연결하는 방법을 정의합니다.
  spanmetrics:

service: # 위에서 정의한 구성 요소들을 연결하여 데이터 파이프라인을 구성합니다.
  pipelines:
    traces:
      receivers: [otlp]
      processors: [transform, batch]
      exporters: [otlp, debug, spanmetrics]
    metrics:
      receivers: [hostmetrics, docker_stats, httpcheck/frontend-proxy, otlp, prometheus, redis, spanmetrics]
      processors: [batch]
      exporters: [otlphttp/prometheus, debug]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [opensearch, debug]

OpenTelemetry가 traces, metrics, logs를 생성한다는 것을 알고 있으며 위 Config 파일을 통해 확인하였습니다. service 섹션은 각 유형의 원격 측정 데이터(telemetry data)가 기본적으로 receivers, processors, exporters를 통해 어떻게 처리될지를 결정하는 파이프라인을 정의하는 곳이며 receivers, processors, exporters에서 반드시 각각의 섹션이 정의되어야 파이프라인에서 참조될 수 있습니다.

따라서 Pipeline을 확인해보면 Config에서 [소스] → [처리 방식] → [타겟]을 확인할 수 있으며, 이는 Otel을 한눈에 파악하는데 도움을 줍니다.

Example:

이제 레포지토리를 클론했으니, 배포될 내용을 확인하기 위해 docker-compose.yml 파일을 살펴보겠습니다. 배포되는 서비스는 4가지 카테고리로 나눌 수 있습니다.

  1. 핵심 데모 서비스 (Core Demo Services): 다양한 언어로 작성된 애플리케이션 서비스입니다.
  2. 의존 서비스 (Dependent Services): 애플리케이션 서비스가 의존하는 서비스 (예: Redis, Kafka 등)입니다.
  3. 텔레메트리 구성 요소 (Telemetry Components): 위 서비스에서 생성된 텔레메트리 데이터를 처리하는 구성 요소 (예: Collector, Prometheus, Grafana, OpenSearch, Jaeger)입니다.
  4. 테스트 (Tests): 테스트 관련 서비스입니다.

이제 다음과 같이 코드를 실행할 수 있습니다.

docker compose up --force-recreate --remove-orphans --detach

또한 컨테이너가 실행되면, 서비스에 접근 가능합니다.

Jaeger를 통해 현재 시스템 아키텍쳐를 한 눈에 파악할 수 있습니다.

Notion Image

Trace를 확인하여 어떤 구조로 호출이 발생하는지 또한 확인할 수 있습니다.

Notion Image

자동 계측되는 지표 또한 확인할 수 있으며 해당 지표를 확인할 수 있습니다.

테스트 환경에선 지속적으로 데이터를 확인하기 위해 Locust를 사용하여 사용자 트래픽을 시뮬레이션하고 Docker가 구성되자마자 기본적으로 로드를 생성합니다. Jaeger UI에서 각 추적이 기록되는 것을 확인하고 보고 싶다면 로드를 중지하는 것이 좋습니다.

Notion Image

아래 데모 서비스를 확인하고 각 요청별 추적이 정상적으로 생성하는 것을 확인할 수 있습니다.

Notion Image

Grafana에서도 확인 가능합니다.

Notion Image
Notion Image
Notion Image
Notion Image

Reference

OpenTelemetry 심화

  • OpenTelemetry Protocol (OTLP)
  • Semantic Conventions
  • Auto-instrumentation vs. Manual instrumentation
  • Sampling, Context Propagation

7. OpenTelemetry와 다른 기술의 통합

  • Kubernetes 환경에서의 OpenTelemetry
  • 서비스 메시 (Service Mesh)와의 통합
  • CI/CD 파이프라인과의 통합