Наблюдаемость
Что такое OpenTelemetry: API, SDK, Collector, OTLP
Компания переходит на другой observability-backend ради экономии. При vendor-SDK, зашитом в каждый сервис, оценка миграции — четыре инженер-недели. С OTel — один день: меняешь exporter-блок в конфиге Collector’а, перезапускаешь его. Всё.
Четыре части
До OTel каждый observability-вендор поставлял проприетарный агент — dd-trace Datadog, агент New Relic, Java-agent AppDynamics — и смена вендора означала переписывание инструментации во всех сервисах. Ответ CNCF — OpenTelemetry: четыре части, наслоенные так, что каждая заменима и каждая говорит стабильный контракт.
API — per-language публичные интерфейсы (Java io.opentelemetry.api, Python opentelemetry.trace, Go go.opentelemetry.io/otel). Это то, к чему обращается код приложения и third-party-библиотеки. Намеренно лёгкий: дефолтная реализация — no-op. Код приложения никогда не импортирует vendor-библиотеку — он импортирует OTel API.
SDK — runtime-кусок, превращающий вызовы API в записи телеметрии. SDK владеет sampling-решениями (какие трейсы оставлять), батчингом (когда флашить в exporter) и сериализацией (OTLP wire-формат). Устанавливает application owner, не library author.
Collector — standalone-процесс (бинарь или контейнер), принимающий OTLP, прогоняющий конфигурируемые processor’ы и экспортящий в один или несколько backend’ов. Это policy-слой: tail sampling, redaction, multi-backend routing — всё в YAML, вне приложения.
OTLP — wire-формат. Protobuf-кодированные сообщения по gRPC или HTTP, определены в OTel-спеке и стабильны через версии. Любая пара OTel-aware компонентов общается по OTLP.
| Часть | Где живёт | Роль | Заменима? |
|---|---|---|---|
| API | Код приложения | Стабильный публичный интерфейс; no-op по умолчанию | Стабилен — не меняется |
| SDK | Runtime приложения | Строит записи, семплирует, батчит, сериализует | Да — заменяешь SDK, не трогая код |
| Collector | Sidecar / gateway | Обрабатывает, маршрутизирует, экспортит телеметрию | Да — меняешь конфиг, не код |
| OTLP | Wire-формат | Переносит span’ы/метрики/логи между частями | Стабилен — все части говорят его |
Почтовая метафора
Представь национальную почтовую систему. API — это почтовый ящик у дома: бросаешь письмо, не знаешь, как оно сортируется. SDK — персонал местного отделения, забирающий письмо, взвешивающий, штампующий, кладущий в нужный исходящий мешок. Collector — региональный сортировочный депо, где письма со множества домов встречаются, батчатся, фильтруются и маршрутизируются по адресу. OTLP — стандартный конверт и адресный формат, понятный каждому депо. Меняешь страну назначения (vendor backend)? Тот же конверт, другая таблица маршрутизации.
История с портабельностью
Антон platform-инженер слышит: компания переезжает с Datadog на Honeycomb ради экономии. Паникует: «Нам что, переписывать каждый сервис?» Дима backend-разработчик успокаивает: «Мы на OTel — код приложения вызывает только OTel API, SDK эмитит OTLP в Collector, Collector экспортит туда, куда указывает конфиг. Меняем один блок в Collector YAML — exporter, endpoint, API-ключ — и редеплоим. Никаких code-changes». Через два дня миграция готова.
Почему это работает
Разделение API/SDK решает проблему third-party-библиотек. До OTel библиотека, желавшая эмитить телеметрию, имела два плохих варианта: выбрать конкретного вендора (залочив пользователей) или построить собственную абстракцию. С OTel библиотека зависит только от пакета OTel API — маленький набор интерфейсов с no-op-дефолтом — и может эмитить span’ы без навязывания пользователям конкретного SDK. Application owner устанавливает тот SDK, который выбирает сам, заменяемый. Именно это делает «инструментируй однажды, маршрутизируй куда угодно» архитектурно обоснованным.
Какие четыре части составляют архитектуру OTel?
У команды 50 микросервисов на OTel, и они хотят добавить новый tracing-backend. Где они вносят изменение?
Расставь путь одного span'а от кода приложения до backend'а:
- 1 Код приложения вызывает tracer.start_span() (OTel API)
- 2 OTel SDK собирает span-record (start_time, attributes, trace-context)
- 3 Когда span заканчивается, SDK передаёт его batch span processor'у
- 4 Processor батчит span'ы и отдаёт exporter'у
- 5 Exporter отправляет OTLP-данные по gRPC или HTTP в Collector
- 6 Collector принимает, применяет processor'ы (tail sampling, redaction), батчит
- 7 Collector экспортит в один или несколько backend'ов (Datadog, Honeycomb, Tempo, ...)
Заполни пропуск: _______ — стандартный конверт и адресный формат, понятный любому OTel-aware куску. Меняешь получателя — конверт остаётся.
- 01В двух предложениях — в чём разница между OTel API и OTel SDK?
- 02Зачем OTel разделяет API и SDK, и какую конкретную проблему это решает?
- 03В одном предложении — какой контракт обеспечивает vendor-нейтральность?
OpenTelemetry — четыре части в стеке: API (что импортирует код — стабильный, vendor-free интерфейс), SDK (runtime, превращающий вызовы API в записи телеметрии, батчащий их и экспортящий OTLP), Collector (standalone-процесс, принимающий OTLP, прогоняющий конфигурируемые processor’ы — tail sampling, redaction — и экспортящий в любой backend), и OTLP (protobuf wire-формат, который говорят все части). В 2026 каждый крупный вендор принимает OTLP — Datadog, Honeycomb, Grafana Cloud, Elastic, Splunk, New Relic. Контракт портабельности: эмитируй OTLP на edge, меняй backend’ы в YAML Collector’а, никогда не переписывай инструментацию.
встречается в40
- Federation и lookahead: батчинг за пределами DataLoadermiddle
- Senior GraphQL API: scheduling-контракт, изоляция арендаторов, наблюдаемостьsenior
- Инвалидация, dirty-биты и containmiddle
- Слои композитора: продвижение, перекрытие и память GPUmiddle
- Observability в проде: LoAF, INP и полная поверхность атакиsenior
- Hidden classes, деревья переходов и расположение в памятиmiddle
- V8 в production: Isolates, сжатие указателей и реальные аварииsenior
- Что такое воркеры и зачем они нужныjunior
- Механика web workers: dedicated, shared и OffscreenCanvasmiddle
- Structured clone и transferablesmiddle
- SharedArrayBuffer, Atomics и cross-origin isolationsenior
- Пулы воркеров, Comlink и наблюдаемость в продакшенеsenior
- Восемь слоёв трассировки: от service worker до второй навигацииmiddle
- Пять канонических поломок: где производство стабильно ломаетсяsenior
- Метод трёх треков: чтение трасс и построение системы мониторингаsenior
- Лок и single-flight: ограничение параллельных rebuildmiddle
- Stale-while-revalidate и CDN request coalescingmiddle
- Детектирование stampede и дизайн TTL для продакшенаmiddle
- Метастабильный сбой, fencing-токены и production-постмортемыsenior
- Что такое отношение: таблицы, строки, ключи и ограниченияjunior
- Ограничения, ключи и типы данных Postgresmiddle
- JSONB, массивы и когда side table побеждаетmiddle
- Целостность схемы: deferral, версионирование и сбои в продакшнеsenior
- Где происходит data fetching — и почему это решает LCPjunior
- React Server Components и Suspense streamingmiddle
- Senior internals: RSC payload, слои кэша и production паденияsenior
- Конверт IPjunior
- Читаем IP-заголовокmiddle
- Что делает TLS и зачем он нуженjunior
- Расписание ключей, SNI, ALPN и расширенияsenior
- Защита 0-RTT, ECH, гибридный PQ и продакшн TLSsenior
- Двенадцать слоёв: один URL, семь действующих лицjunior
- Устойчивость: каскадные повторы, circuit breakers и error budgetsenior
- At-most-once, at-least-once, exactly-once: три контракта доставкиjunior
- Consumer-side dedup: самый дешёвый путь к exactly-once processingmiddle
- Exactly-once в production: impossibility-доказательство, гибридные паттерны и реальные инцидентыsenior
- Что такое OAuth и почему пароли — не ответjunior
- Authorization code flow с PKCEmiddle
- Sender-constrained токены: DPoP и mTLSsenior
- OAuth в production: audience атаки, observability и реальные провалыsenior