Автор: Oleborn
Дата: 23 февраля 2026 г.
Проект: OrderHub
До появления OpenTelemetry (OTel) мир наблюдаемости был фрагментирован. Каждый вендор (Datadog, New Relic, Dynatrace) предлагал свои проприетарные агенты и SDK. Это приводило к "Vendor Lock-in": переезд на другую платформу мониторинга требовал переписывания кода инструментирования во всем приложении.
OpenTelemetry — это проект CNCF (Cloud Native Computing Foundation), который ставит своей целью создание единого, вендор-нейтрального стандарта для сбора трех столпов наблюдаемости: Трассировок (Traces), Метрик (Metrics) и Логов (Logs).
Ключевая концепция: OpenTelemetry — это не бэкенд для хранения данных (как Prometheus или Jaeger). Это стандарт и набор инструментов для генерации, сбора и экспорта данных в любой бэкенд.
Архитектура OTel состоит из нескольких ключевых компонентов, которые работают вместе для обеспечения полного цикла жизни телеметрии.
Это "сердце" проекта. Она определяет:
- API: Как разработчик пишет код для создания спанов или метрик.
- SDK: Реализация API на конкретном языке (Java, Go, Python и т.д.).
- OTLP (OpenTelemetry Protocol): Протокол передачи данных.
- Semantic Conventions: Стандартные имена для атрибутов (например,
http.method,db.statement).
Существует два подхода к внедрению OTel в приложение:
- Автоматическая инструментация (Zero-code): В Java это реализуется через
javaagent. Он "на лету" модифицирует байт-код популярных библиотек (Spring, JDBC, Kafka) и начинает генерировать телеметрию без изменения исходного кода. - Ручная инструментация (Manual): Использование SDK напрямую для создания кастомных спанов или метрик, специфичных для бизнес-логики.
Это промежуточный сервис, который выступает в роли "швейцарского ножа" для телеметрии. Он может принимать данные, обрабатывать их и отправлять в несколько мест одновременно.
Collector — это самый мощный компонент системы. Его работа строится на базе Пайплайнов (Pipelines).
Пайплайн состоит из трех этапов:
- Receivers (Приемники): Слушают порты и принимают данные в разных форматах (OTLP, Jaeger, Prometheus, Zipkin).
- Processors (Процессоры): Самая интересная часть. Они могут:
- Batch: Группировать данные для эффективной отправки.
- Memory Limiter: Предотвращать падение коллектора по OOM.
- Attributes/Resource: Добавлять, удалять или изменять теги (например, добавить
env: productionко всем данным). - Sampling: Фильтровать трассировки (например, оставлять только 10% успешных запросов и 100% ошибок).
- Exporters (Экспортеры): Отправляют обработанные данные в бэкенды (Prometheus, Jaeger, Elasticsearch, OTLP).
receivers:
otlp:
protocols:
grpc:
http:
processors:
batch:
memory_limiter:
check_interval: 1s
limit_mib: 1024
resourcedetection:
detectors: [env, system]
exporters:
prometheus:
endpoint: "0.0.0.0:8889"
otlp/jaeger:
endpoint: "jaeger:4317"
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, resourcedetection]
exporters: [otlp/jaeger]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheus]Пайплайны — это то, где происходит "магия" обработки данных. Рассмотрим продвинутые техники.
OpenTelemetry Transformation Language (OTTF) позволяет менять данные "на лету" без написания кода на Go.
processors:
transform:
error_mode: ignore
trace_statements:
- context: span
statements:
# Удаляем чувствительные данные из тегов
- delete_key(attributes, "http.request.header.authorization")
# Добавляем префикс к именам сервисов
- set(resource.attributes["service.name"], Concat(["prod", resource.attributes["service.name"]], "-"))Обычное сэмплирование (Head-based) принимает решение в начале запроса. Tail-based Sampling принимает решение в конце, когда мы уже знаем результат.
- Кейс: Мы хотим сохранять 100% запросов с ошибками (HTTP 500) и только 1% успешных (HTTP 200).
- Реализация: Коллектор буферизирует все спаны одного
traceId, ждет завершения всей трассы, анализирует её и решает — сохранять или дропнуть.
Этот процессор автоматически обогащает телеметрию данными об окружении.
processors:
resourcedetection:
detectors: [env, system, gcp, ecs, ec2, azure]
timeout: 2s
override: falseЕсли ваше приложение запущено в AWS EC2, коллектор сам добавит теги cloud.region, host.id, instance.type ко всем метрикам и трассам.
OTLP (OpenTelemetry Protocol) — это современный протокол, разработанный специально для высокой производительности.
В отличие от JSON, который используется в Zipkin, OTLP использует Protocol Buffers (Protobuf).
- Бинарный формат: Данные передаются в сжатом виде, что экономит до 70% трафика.
- Строгая типизация: Ошибки в структуре данных отлавливаются на этапе компиляции, а не в рантайме.
- Быстрый парсинг: Десериализация Protobuf в 5-10 раз быстрее, чем JSON, что критично для коллекторов, обрабатывающих миллионы спанов в секунду.
OpenTelemetry поддерживает оба варианта, но у каждого свои задачи:
- gRPC (Порт 4317):
- Преимущества: Двунаправленный стриминг, мультиплексирование запросов в одном соединении, встроенное сжатие.
- Использование: Внутренние сети, общение между коллекторами, высоконагруженные сервисы.
- HTTP/JSON (Порт 4318):
- Преимущества: Проходит через любые Firewall и Proxy, не требует специальных библиотек (можно отправить
curl). - Использование: Браузерные приложения (JS), мобильные устройства, среды с ограниченной поддержкой gRPC.
- Преимущества: Проходит через любые Firewall и Proxy, не требует специальных библиотек (можно отправить
Одна из главных проблем мониторинга — разные имена для одних и тех же вещей. Один разработчик пишет user_id, другой uid, третий customer.id.
OpenTelemetry вводит Semantic Conventions — жесткий стандарт именования.
http.status_code— всегда код ответа.db.system— тип БД (mysql, postgresql).net.peer.name— адрес удаленного узла.
Зачем это нужно? Это позволяет инструментам визуализации (Grafana) строить универсальные дашборды, которые будут работать для любого приложения, независимо от того, кто его писал.
В K8s существует три основных способа развертывания Collector:
- Sidecar: Коллектор запускается как контейнер внутри каждого Pod'а.
- Плюсы: Минимальная задержка, изоляция.
- Минусы: Огромный расход ресурсов (CPU/RAM) на тысячи контейнеров.
- DaemonSet: Один коллектор на каждую ноду кластера.
- Плюсы: Оптимальный баланс ресурсов.
- Минусы: Если коллектор упадет, вся нода "ослепнет".
- Gateway (Deployment): Отдельный кластер коллекторов за балансировщиком.
- Плюсы: Централизованное управление, агрегация данных, сложная фильтрация.
- Минусы: Дополнительный сетевой прыжок (hop).
Spring Boot 3 полностью перешел на Micrometer Tracing, который является фасадом над OpenTelemetry.
- Приложение использует Micrometer API.
- В рантайме подключается OpenTelemetry Bridge.
- Данные экспортируются по протоколу OTLP в Collector.
- Collector распределяет их: метрики в Prometheus, трассы в Jaeger.
Это дает нам "святой грааль" наблюдаемости: Correlation. Мы можем найти медленный запрос в Jaeger, увидеть его traceId и по этому же ID найти все логи этого запроса в Elasticsearch и метрики нагрузки на CPU в этот момент.
Главная ценность OpenTelemetry — это Context Propagation.
OTel использует стандарт W3C Trace Context, который состоит из двух заголовков:
traceparent: СодержитtraceIdиspanId.tracestate: Содержит вендор-специфичную информацию.
Baggage — это механизм передачи произвольных пар "ключ-значение" через всю цепочку вызовов.
- Пример: Вы можете положить
customer_idв Baggage в первом сервисе, и он автоматически "пролетит" через 10 микросервисов, став доступным в логах и трассах последнего сервиса без явной передачи в аргументах функций.
- Используйте Collector всегда. Даже если вы отправляете данные в один бэкенд. Коллектор снимает нагрузку с приложения (очереди, ретраи, сжатие) и позволяет менять бэкенд без перезапуска приложения.
- Настраивайте Batch Processor. Без него каждый спан будет отправляться отдельным сетевым запросом, что создаст огромный оверхед.
- Следите за Cardinality. Не добавляйте динамические данные (например,
user_id) в имена метрик. Используйте для этого атрибуты (теги). - Используйте Semantic Conventions. Не придумывайте свои имена для стандартных вещей. Это позволит вам использовать готовые дашборды из Grafana Marketplace.
- Настраивайте Health Check. Коллектор должен иметь эндпоинт
/health, чтобы Kubernetes мог перезапустить его в случае зависания.