awesome-everything EN
↑ Обратно к восхождению

Наблюдаемость

Архитектура OTel: один SDK, четыре сигнала, один wire-формат

Суть Как OpenTelemetry унифицирует логи, метрики, трейсы и профили через единый collector-пайплайн — и как trace-id становится join-ключом, позволяющим всем четырём сигналам отвечать на один запрос.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

До OpenTelemetry подключение нового сервиса к observability-стеку означало четыре отдельных SDK, четыре конфига collector’а и четыре языка запросов. Смена вендора требовала повторной инструментации всего кода. OTel свернул все четыре типа сигналов в один SDK и один wire-протокол. Теперь переключение бэкенда — это изменение конфига, а не отдельный проект.

Полная стековая архитектура

OpenTelemetry-based production-стек выглядит одинаково в 2026 году вне зависимости от вендора.

Слой приложения. Каждый сервис запускает один OTel SDK (или OTel auto-instrumentation), который эмитирует четыре сигнала:

  • Логи — высококардинальные записи событий с полем trace-id.
  • Метрики — низкокардинальные счётчики и гистограммы; exemplar’ы гистограмм несут trace-id репрезентативного запроса.
  • Трейсы — причинно-следственные графы на запрос в виде OTLP span-батчей.
  • Профили — функциональные CPU- и allocation-сэмплы; каждый сэмпл несёт trace-id активного запроса.

Каждый сигнал несёт один и тот же trace-id (когда применимо), поэтому cross-signal join’ы возможны во время запроса.

Слой Collector’а. Локальный агент OTel Collector (DaemonSet на каждом узле или sidecar в каждом pod’е) принимает все четыре типа сигналов через OTLP gRPC (localhost:4317). Он батчует и отправляет в gateway-ярус. Gateway выполняет:

  • Tail sampling для трейсов — буферизирует spans до закрытия трейса, затем сохраняет 100% ошибок и медленных трейсов плюс небольшой случайный baseline.
  • Агрегацию метрик.
  • Опциональную PII-зачистку в полях логов и фильтрацию символов профилей.
  • Маршрутизацию сигналов в один или несколько бэкендов.

Слой бэкенда. Любая комбинация: Tempo (трейсы), Prometheus / Mimir (метрики), Loki (логи), Pyroscope (профили) для self-hosted Grafana-стека; или Datadog, Honeycomb, New Relic — для vendor-managed. OTLP принимается всеми крупными бэкендами начиная с 2024–2026. Переключение бэкенда — изменение конфига exporter’а; код приложения не меняется.

СигналКардинальностьПаттерн запросаТипичный бэкенд
ЛогиВысокая”error contains X”Loki, OpenSearch
МетрикиНизкаяДашборды + алертыPrometheus, Mimir
ТрейсыСредняяDrill-down по запросуTempo, Jaeger, Honeycomb
ПрофилиСредняяDrill-down по flame graphPyroscope, Parca

Конкретный конфиг OTel Collector’а

Сервис checkout (Node) отправляет все четыре сигнала через единый Collector:

# otel-collector.yaml (DaemonSet на каждом узле)
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
processors:
  batch:
    send_batch_size: 512
    timeout: 10s
  tail_sampling:
    policies:
      - { name: errors, type: status_code, status_code: { status_codes: [ERROR] } }
      - { name: slow,   type: latency,     latency: { threshold_ms: 2000 } }
      - { name: rest,   type: probabilistic, probabilistic: { sampling_percentage: 5 } }
exporters:
  otlphttp/tempo:         { endpoint: http://tempo:4318 }
  prometheusremotewrite:  { endpoint: http://prometheus:9090/api/v1/write }
  loki:                   { endpoint: http://loki:3100/loki/api/v1/push }
  otlphttp/pyroscope:     { endpoint: http://pyroscope:4040/ingest }
service:
  pipelines:
    traces:   { receivers: [otlp], processors: [tail_sampling, batch], exporters: [otlphttp/tempo] }
    metrics:  { receivers: [otlp], processors: [batch], exporters: [prometheusremotewrite] }
    logs:     { receivers: [otlp], processors: [batch], exporters: [loki] }
    profiles: { receivers: [otlp], processors: [batch], exporters: [otlphttp/pyroscope] }

Переключение с этого self-hosted Grafana-стека на Datadog означает изменение четырёх endpoint-URL’ов exporter’ов. Код сервиса не меняется.

Почему tail sampling требует отдельного процессора

Head sampling принимает решение в начале трейса — сохранить или нет. Если он сохраняет только 5% случайно, то 95% ошибочных и медленных трейсов отбрасываются — именно тогда, когда они нужны.

Tail sampling буферизирует все spans в памяти до закрытия трейса (или до истечения decision window ~10 секунд), а затем принимает решение. Канонический production-policy:

  • Сохранять 100% трейсов с любым ERROR-span’ом.
  • Сохранять 100% трейсов с суммарной длительностью выше порога медленного трейса (например, 2 с).
  • Сохранять случайные 5% baseline всего остального.

Это сокращает объём трейсов на 90%+ при сохранении каждого интересного трейса.

Почему это работает

Head + tail вместе: SDK делает head-sampling при 100% (все spans создаются и эмитируются), а processor tail_sampling в collector’е — единственный, кто отбрасывает. Это защищает от сценария, когда трейс, сэмплированный прочь на head-этапе, позже становится ошибкой — если spans никогда не были эмитированы, их нельзя восстановить постфактум.

Trace-id как несущий join-ключ

Trace-id — идентификатор, который делает четырёхсигнальный стек единым инструментом, а не четырьмя разрозненными системами.

  • Логи эмитируют его как структурированное поле (trace_id: "abc123").
  • Метрики эмитируют его как exemplar’ы гистограмм (конкретный trace-id, прикреплённый к сэмплу бакета).
  • Трейсы нативно индексируются по нему.
  • Профили прикрепляют его к каждому стеку-сэмплу.

При последовательной propagation trace-id (W3C traceparent через каждый вызов сервиса) запрос «всё, что связано с этим конкретным запросом» возвращает записи логов, exemplar’ы метрик, полное дерево трейса и сэмплы профилей — все объединены одной hex-строкой. Без этого четыре сигнала — четыре изолированных хранилища, и инженер вручную коррелирует по временной метке + имени сервиса + догадкам.

Случайность 128 бит обеспечивает глобальную уникальность. Стандартизация W3C гарантирует выживание при смене вендора и языка. OTel SDK’и обрабатывают propagation автоматически через HTTP, gRPC, очереди и асинхронные вызовы.

Расставь шаги по порядку

Упорядочи поток данных OTel для одного HTTP-запроса через один сервис:

  1. 1 Браузерный fetch генерирует traceparent и отправляет его вместе с запросом
  2. 2 Сервис получает запрос; OTel SDK извлекает traceparent, создаёт span
  3. 3 Атрибуты span'а заполняются (http.route, http.response.status_code, кастомные атрибуты)
  4. 4 SDK эмитирует span в локальный Collector через OTLP gRPC
  5. 5 Collector батчует spans, применяет tail sampling, отправляет в бэкенд
  6. 6 Срабатывает profile-сэмпл; SDK прикрепляет текущий trace-id к стеку-сэмплу
  7. 7 Счётчики метрик увеличиваются; гистограмма записывает длительность; exemplar прикрепляет trace-id
Викторина

Какой сигнал несёт trace-id, позволяющий логам, метрикам, трейсам и профилям объединяться во время запроса?

Викторина

Зачем нужен processor tail_sampling помимо head sampling на уровне SDK?

OTel-стек: типичные production-параметры
Типичный head + tail sampling в production
5% baseline + 100% ошибок / медленных
Decision window tail sampling
10–30 секунд
Сокращение объёма трейсов при tail sampling
90%+
Статус OTel profile-сигнала (2026)
Release candidate (Q1 2026)
Сокращение объёма логов (зрелые orgs, 5 лет)
40–60%
Модель Collector DaemonSet
1 на узел, 4 пайплайна
Вспомните перед уходом
  1. 01
    Объясни, почему trace-id является несущим идентификатором для всех четырёх observability-сигналов.
  2. 02
    Какова роль processor'а tail_sampling в OTel Collector'е, и каков канонический production-policy?
  3. 03
    Как работает смена вендора observability в OTel-first-сетапе по сравнению с pre-OTel-подходом?
Итог

Production-стек на OpenTelemetry — это три слоя: код приложения, эмитирующий четыре сигнала через один OTel SDK; локальный агент Collector, применяющий tail sampling и маршрутизацию; и взаимозаменяемые бэкенды, принимающие OTLP. Trace-id, propagated W3C traceparent header’ом, — join-ключ, позволяющий всем четырём сигналам отвечать на один запрос; без него стек — четыре разрозненных хранилища. Tail sampling требует буферизации spans до закрытия трейса, чтобы сохранить 100% ошибок и медленных трейсов, отбросив 90%+ baseline; head sampling в одиночку отбрасывает интересные трейсы ещё до того, как узнаёт, что они интересны. К 2026 году OTel profile-сигнал достиг release candidate, завершив четырёхсигнальную историю и сделав профилирование таким же переносимым, как метрики или трейсы. Смена бэкенда в OTel-first-сетапе — изменение конфига collector’а, а не проект по повторной инструментации.

Связанные уроки
встречается в202
Продолжить восхождение ↑Экономия на observability: удерживаем затраты в пределах 5% infra
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.