объединить трейсы, метрики и логи через масштабируемый уровень Collector

OpenTelemetry Collector промышленного уровня: единый конвейер для трейсов, метрик и логов

14 минут

Три отдельных стека — Jaeger, Prometheus и Fluentd — утраивают операционную нагрузку и мешают корреляции сигналов. В материале — агент и шлюз Collector с лимитами памяти, отложенной выборкой трейсов, очередями экспорта и развёртыванием через Helm в Kubernetes.

Почему три стека агентов ломают корреляцию и растут вместе с нагрузкой

Во многих средах за трейсы отвечают Jaeger или Zipkin, за метрики — Prometheus или StatsD, за логи — Fluentd или Vector. У каждого стека свой жизненный цикл конфигурации, профиль ресурсов и характерный сбой. Когда трафик удваивается, операционная работа часто утраивается. Связать медленный трейс со всплеском задержки и записью об ошибке в логе по-прежнему значит вручную переключаться между панелями мониторинга — сигналы не получают общий контекст уже на этапе приёма. Архитектурный выход — вендорно-нейтральный канал телеметрии: приложения отправляют OTLP, коллекторы обрабатывают и маршрутизируют данные централизованно, а системы хранения становятся взаимозаменяемыми.

Модель конвейера Collector: приёмники, процессоры, экспортёры и соединители

OpenTelemetry Collector — один исполняемый модуль со составным конвейером для каждого типа сигнала. Приёмники принимают OTLP, сбор Prometheus, filelog или устаревшие форматы. Процессоры изменяют, фильтруют, прореживают или пакетируют данные. Экспортёры отправляют их в Tempo, Prometheus remote write, Loki или сторонние системы. Соединители связывают конвейеры между собой: например, spanmetrics превращает трейсы в метрики без отдельного пути инструментирования. Типичная схема для продакшена: агент на каждом узле для локального приёма и лёгкого пакетирования плюс центральный шлюз для отложенной выборки трейсов, обогащения атрибутов и рассылки в несколько хранилищ. Используйте дистрибутив contrib, если не уверены, что базовых OTLP-компонентов будет достаточно.

Уровень агента: локальный приём, лимиты памяти, пересылка на шлюз

Разворачивайте агент как DaemonSet Kubernetes или сайдкар рядом с приложением. Он принимает OTLP от SDK приложения или автоинструментирования, первым ставит процессор memory_limiter, затем batch и пересылает данные на шлюз по TLS. Агент не является долговременным буфером: очереди по умолчанию живут в памяти, а при перегрузке экспортёров обратное давление распространяется к источникам выше по цепочке. Держите поды агента скромными по ресурсам и не размещайте на этом уровне тяжёлые процессоры.

YAML · конфигурация агента OpenTelemetry Collector
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 400
    spike_limit_mib: 100
  batch:
    timeout: 5s
    send_batch_size: 8192
  resource:
    attributes:
      - key: collector.tier
        value: agent
        action: upsert

exporters:
  otlp/gateway:
    endpoint: otel-gateway.observability.svc:4317
    tls:
      insecure: false
    sending_queue:
      enabled: true
      queue_size: 4096
    retry_on_failure:
      enabled: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, resource, batch]
      exporters: [otlp/gateway]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, resource, batch]
      exporters: [otlp/gateway]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, resource, batch]
      exporters: [otlp/gateway]

Уровень шлюза: отложенная выборка, обогащение и экспорт в несколько систем

Коллекторы-шлюзы работают как Deployment с большим объёмом памяти и CPU. Отложенная выборка трейсов (tail sampling) размещается здесь, чтобы решения принимались по полным цепочкам между сервисами. Перечисленные политики срабатывают по логике «или»: сохраняются ошибки, медленные запросы и небольшая случайная доля остального трафика. Процессор memory_limiter ставьте до выборки, обогащайте атрибуты окружения и команды, затем рассылайте сигналы в хранилища трейсов, метрик и логов. Для отладки во время инцидента включайте расширения health_check и zpages.

YAML · конфигурация шлюза OpenTelemetry Collector
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 2048
    spike_limit_mib: 512
  tail_sampling:
    decision_wait: 10s
    num_traces: 100000
    expected_new_traces_per_sec: 2000
    policies:
      - name: errors
        type: status_code
        status_code: { status_codes: [ERROR] }
      - name: slow-requests
        type: latency
        latency: { threshold_ms: 1000 }
      - name: sample-remainder
        type: probabilistic
        probabilistic: { sampling_percentage: 5 }
  attributes:
    actions:
      - key: deployment.environment
        action: upsert
        value: production
      - key: team
        action: upsert
        value: platform
  batch:
    timeout: 10s
    send_batch_size: 16384

exporters:
  otlp/tempo:
    endpoint: tempo.observability.svc:4317
    tls:
      insecure: true
    sending_queue:
      enabled: true
      queue_size: 8192
    retry_on_failure:
      enabled: true
  prometheusremotewrite:
    endpoint: https://mimir.example.com/api/v1/push
  loki:
    endpoint: http://loki.observability.svc:3100/loki/api/v1/push

extensions:
  health_check:
    endpoint: 0.0.0.0:13133
  zpages:
    endpoint: 0.0.0.0:55679

service:
  extensions: [health_check, zpages]
  telemetry:
    metrics:
      level: detailed
      readers:
        - pull:
            exporter:
              prometheus:
                host: 0.0.0.0
                port: 8888
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, tail_sampling, attributes, batch]
      exporters: [otlp/tempo]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, attributes, batch]
      exporters: [prometheusremotewrite]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, attributes, batch]
      exporters: [loki]

Развёртывание в Kubernetes через Helm-чарт OpenTelemetry

Устанавливайте релизы агента и шлюза из официального Helm-чарта. Фиксируйте тег образа contrib и проверяйте конфигурацию командой otelcol validate в CI. Конфигурацию шлюза монтируйте из ConfigMap или задавайте через values-файл чарта. Масштабируйте шлюз горизонтально; при росте числа агентов добавьте балансировщик нагрузки или экспортёр loadbalancing для OTLP.

Bash · установка агента DaemonSet и шлюза Deployment через Helm
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update

helm upgrade --install otel-agent open-telemetry/opentelemetry-collector \
  --namespace observability --create-namespace \
  --set mode=daemonset \
  --set image.repository=otel/opentelemetry-collector-contrib \
  --set image.tag=0.106.1 \
  -f values/agent.yaml

helm upgrade --install otel-gateway open-telemetry/opentelemetry-collector \
  --namespace observability \
  --set mode=deployment \
  --set replicaCount=3 \
  --set image.repository=otel/opentelemetry-collector-contrib \
  --set image.tag=0.106.1 \
  -f values/gateway.yaml

Эталонный шлюз: самомониторинг, конвейер логов и защита экспорта

Конфигурация ниже показывает полный путь для трейсов и метрик: самосбор метрик коллектора, обогащение ресурсов из входящих атрибутов и очереди у экспортёров. Конвейер для логов добавляйте по той же схеме, когда приложения шлют OTLP-логи. Инструментируйте код через OpenTelemetry SDK, чтобы trace_id и span_id попадали в структурированные логи — именно корреляция делает единую телеметрию полезной, а не просто сокращение числа демонов.

YAML · шлюз с отложенной выборкой и самомониторингом
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
  prometheus:
    config:
      scrape_configs:
        - job_name: otelcol-self
          scrape_interval: 15s
          static_configs:
            - targets: ['127.0.0.1:8888']

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 2048
    spike_limit_mib: 512
  tail_sampling:
    decision_wait: 10s
    num_traces: 200000
    policies:
      - name: error-policy
        type: status_code
        status_code: { status_codes: [ERROR] }
      - name: slow-requests
        type: latency
        latency: { threshold_ms: 2000 }
      - name: sample-5pct
        type: probabilistic
        probabilistic: { sampling_percentage: 5 }
  resource:
    attributes:
      - key: deployment.region
        value: eu-west-1
        action: upsert
      - key: service.version
        from_attribute: git.commit.sha
        action: upsert
  batch:
    timeout: 10s
    send_batch_size: 16384

exporters:
  otlp/tempo:
    endpoint: tempo.observability.svc:4317
    tls:
      insecure: true
    sending_queue:
      enabled: true
    retry_on_failure:
      enabled: true
  prometheusremotewrite:
    endpoint: https://mimir.observability.svc/api/v1/push
  debug:
    verbosity: basic

extensions:
  health_check:
    endpoint: 0.0.0.0:13133
  zpages:
    endpoint: 0.0.0.0:55679
  pprof:
    endpoint: 0.0.0.0:1777

service:
  extensions: [health_check, zpages, pprof]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, tail_sampling, resource, batch]
      exporters: [otlp/tempo, debug]
    metrics:
      receivers: [otlp, prometheus]
      processors: [memory_limiter, resource, batch]
      exporters: [prometheusremotewrite]

Операционные практики для промышленного парка коллекторов

Ставьте memory_limiter первым в каждом конвейере и задавайте limit_mib примерно на семьдесят–восемьдесят процентов лимита памяти пода. Отложенную выборку и переписывание атрибутов оставляйте на шлюзе, не на агенте. Следите за метриками otelcol_exporter_send_failed_spans, otelcol_exporter_queue_size и otelcol_processor_refused_spans — потери на коллекторе означают слепые зоны ниже по цепочке. Фиксируйте тег образа, прогоняйте otelcol validate при изменении конфигурации и тестируйте обновления на staging: схема конфигурации меняется между минорными версиями. Разделяйте запросы ресурсов: агент остаётся лёгким, шлюзу нужен запас под буферы выборки. Подключайте процессоры resourcedetection и k8sattributes, когда на каждом сигнале нужны метаданные узла, пода и пространства имён. Единый уровень Collector сокращает зоопарк агентов и делает корреляцию трейсов, логов и метрик достижимой, если в коде приложения настроена передача контекста через SDK.

Начните с полезных сигналов и гигиены алертов из базового гайда по наблюдаемости для небольших платформенных команд.

Решения по выборке и хранению данных должны учитывать бюджет надёжности из практик SLO, SLI и error budget для платформенных команд.