Observability (наблюдаемость) — это свойство системы, при котором по ее внешним данным — метрикам, логам и трассировкам — можно понять, что происходит внутри, и найти причину сбоя, для которого заранее не настроили ни проверку, ни дашборд. Мониторинг решает более узкую задачу: следит за известными показателями и сообщает, что что-то пошло не так.
Содержание
- Чем наблюдаемость (observability) отличается от мониторинга
- Три вида телеметрии: метрики, логи и трассировки
- Как сигналы связываются между собой
- OpenTelemetry: единый способ собирать телеметрию
- Сэмплирование трассировок: head, tail и адаптивное
- Хранение телеметрии: как не утонуть в данных
- Выводы
- Где применяется на практике
- FAQ
Ниже — сравнение с мониторингом, три вида телеметрии, OpenTelemetry, сэмплирование и хранение. Статья опирается на живые разборы преподавателей Otus, ближайшие из них — в расписании открытых уроков. Три термина, которые встретятся дальше:
- Телеметрия — данные, которые система отдает о себе. Отдельный вид телеметрии (метрики, логи, трассировки) в OpenTelemetry называют сигналом.
- Инструментирование — то, что добавляют в код или окружение, чтобы телеметрия появилась: библиотеку, SDK или агента.
- Бэкенд хранения — система, где телеметрия лежит и где по ней ищут.
Чем наблюдаемость (observability) отличается от мониторинга
Системы мониторинга вроде Zabbix, Nagios и Prometheus собирают результаты проверок, рисуют графики и шлют оповещения. Устроены они по-разному: Prometheus хранит метрики как временные ряды, а Nagios Core передает данные производительности внешним программам. Мониторинг отвечает на вопросы, сформулированные заранее: CPU выше 90%, доля ответов 5xx выше порога, сервис недоступен.
Наблюдаемость нужна, когда сбой новый. Например, медленно отвечает только часть запросов — от одной версии мобильного приложения к одному методу API. На графике средней задержки этого почти не видно: нужно разрезать данные по произвольным атрибутам и пройти путь конкретного запроса.
| Мониторинг | Наблюдаемость | |
|---|---|---|
| Главный вопрос | Что сломалось и когда | Почему и где именно, даже в непредусмотренных сценариях |
| Как спрашивают | Пороги, алерты, готовые дашборды | Произвольные срезы, переход от симптома к конкретному запросу |
| Данные | Метрики и проверки доступности | Метрики, логи и трассировки, связанные общими идентификаторами |
| Результат | Алерт «ошибок 5xx больше порога» | Найдены сервис, версия и шаг запроса, где растет задержка |
Подходы не конкурируют: без мониторинга никто не узнает, что пора разбираться, а мониторинг без связанной телеметрии оставляет только график с пиком. Граница условная, поэтому наблюдаемость удобнее считать степенью: насколько быстро по имеющимся данным можно ответить на новый вопрос.
Три вида телеметрии: метрики, логи и трассировки
Метрики — числовые значения во времени: число запросов, длительность ответа, занятая память. Они компактны и подходят для алертов и трендов. Prometheus сам опрашивает источники, а экспортеры отдают ему метрики систем.
Что собирать первым, подсказывают наборы RED (Rate, Errors, Duration) для сервисов, USE (Utilization, Saturation, Errors) для ресурсов и четыре золотых сигнала SRE: задержка, трафик, ошибки, насыщение. Слабость метрик — агрегация: рост задержки виден, а виновный запрос нет.
Логи — записи о событиях: что произошло, когда и с какими параметрами. Это самый подробный и самый объемный сигнал. Структурированные логи (JSON с полями) искать проще, чем свободный текст. Слабость — порядок событий: если часы серверов расходятся даже на сотни миллисекунд, записи с разных машин могут встать не в том порядке. Поэтому синхронизация времени — обязательная часть инфраструктуры.
Трассировка (trace) — путь одного запроса через компоненты системы с общим trace ID. Спан (span) — один шаг этого маршрута: вызов сервиса, запрос к базе, обращение к внешнему API, со своим span ID, ссылкой на родителя, длительностью и статусом.
Если заказ проходит через витрину, корзину и оплату, трассировка покажет все шаги одной диаграммой, и видно, какой шаг занял 2 секунды из 2,3. Слабость — нужно инструментирование и передача идентификатора запроса между сервисами (для HTTP обычно заголовком traceparent по стандарту W3C Trace Context).
Все чаще к трем сигналам добавляют четвертый — профилирование: сколько процессорного времени занимают функции в работающей системе. Его часто собирают через eBPF на уровне ядра Linux, не меняя код.
| Сигнал | На что отвечает | Объем (как правило) | Где обычно хранят |
|---|---|---|---|
| Метрики | Сколько, как быстро, есть ли отклонение | Небольшой, растет с числом меток | Prometheus, VictoriaMetrics, Mimir, Thanos |
| Логи | Что именно произошло в момент сбоя | Наибольший | Loki, OpenSearch, Elasticsearch, VictoriaLogs, ClickHouse |
| Трассировки | На каком шаге цепочки задержка или ошибка | Средний, регулируют сэмплированием | Tempo, Jaeger, OpenSearch, ClickHouse |
Как сигналы связываются между собой
Исторически сигналы собирали раздельно: свой агент, свой бэкенд и своя модель данных для каждого. Логи с трассировками еще можно сопоставить через correlation ID, а с метриками их часто объединяет только имя сервиса.
Переходить от сигнала к сигналу помогают общие ключи. Это полезно и монолиту, а между сервисами особенно важно. Обычно используют два ключа:
- контекст запроса — в каждую запись лога пишут trace ID и span ID, и от проблемного трейса можно перейти к логам ровно этого запроса;
- атрибуты ресурса — все сигналы несут одинаковое описание источника: имя сервиса, версию, окружение.
Запись лога, связанная с трассировкой, может выглядеть так (имена полей зависят от библиотеки логирования):
{"timestamp": "2026-10-21T10:15:02.481Z", "severity": "ERROR", "service.name": "checkout", "service.version": "1.42.0", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "span_id": "00f067aa0ba902b7", "message": "payment provider timeout after 3000 ms"}
Типичный разбор: алерт по метрике показывает симптом — выросла доля ошибок. Трейсы с ошибкой указывают узкое место — вызов платежного провайдера. Логи этого trace ID объясняют причину — таймаут. Удобно, когда все открывается в одном интерфейсе (например, Grafana поверх Loki, Prometheus и Tempo), но решают общие идентификаторы.
OpenTelemetry: единый способ собирать телеметрию
OpenTelemetry — открытый проект Cloud Native Computing Foundation (CNCF): стандарт и инструменты, чтобы создавать, собирать и передавать метрики, логи и трассировки. Он не привязан к вендору и не хранит данные сам: телеметрия уходит в выбранный бэкенд, и его можно сменить без повторного инструментирования кода. Проект состоит из пяти частей:
- API и SDK — создают спаны, метрики и записи логов в коде;
- автоинструментация — перехватывает вызовы популярных фреймворков и клиентов баз данных без правки бизнес-кода;
- OTLP — открытый протокол передачи телеметрии поверх gRPC или HTTP, его принимают и многие сторонние агенты и бэкенды;
- Collector — отдельный процесс, который принимает, обрабатывает и отправляет телеметрию;
- семантические соглашения — общие имена атрибутов вроде
service.nameиhttp.response.status_code.
Автоинструментация сама проставляет спанам статус. Серверный HTTP-спан получает Error при ответе 5xx, а 4xx не помечается: это проблема вызывающей стороны. Клиентским спанам Error обычно рекомендуют ставить при 4xx и 5xx, но это зависит от контекста.
Collector похож на ETL-инструмент вроде Logstash или Vector: receivers принимают данные, processors собирают их в пакеты, ограничивают память и фильтруют, exporters отправляют дальше. Связывают их в конвейеры (pipelines) по сигналам.
В маленькой системе SDK может писать прямо в бэкенд, но в рабочих обычно ставят Collector посередине: он буферизует и повторяет отправку и позволяет сменить хранилище, не трогая приложения.
Сами коллекторы тоже надо мониторить. Растущая очередь показывает отставание экспорта, поэтому следят за ее заполнением и счетчиками отказов: при переполнении или окончательной неудаче отправки данные могут потеряться.
В SDK популярных языков трассировки и метрики в основном стабильны, а зрелость логов разная — перед выбором сверьтесь с таблицей статусов на opentelemetry.io. Для логов обычно оставляют привычную библиотеку и подключают к ней мост, который добавляет trace ID и передает записи в OpenTelemetry. Инструментирование сервисов и настройку Collector на реальном стенде проходят на курсе «Observability: мониторинг, логирование, трассировка».
Сэмплирование трассировок: head, tail и адаптивное
Хранить каждый трейс нагруженного сервиса дорого, поэтому сохраняют часть.
| Способ | Где решается | Плюс | Минус |
|---|---|---|---|
| Head | В начале запроса, обычно в SDK | Дешево и просто | Не знает исхода: редкие ошибки и медленные запросы теряются |
| Tail | После ожидания спанов, в Collector | Отбирает трейсы с ошибками и большой задержкой | Спаны ждут в памяти, весь трейс должен попасть на один экземпляр |
| Адаптивное | Динамически, по нагрузке | Объем не взлетает при пиках | Доля сохраненных трейсов меняется, это искажает статистику |
При head-сэмплировании обычно сохраняют от 1 до 10% трейсов, и для разбора сбоев этого часто мало. Распространенная схема — tail: оставить трейсы с ошибкой и медленнее порога, плюс небольшую долю успешных для сравнения с нормой. Для сервисов, приносящих основную выручку, долю поднимают. Минимальная конфигурация (процессор tail_sampling есть в сборке otelcol-contrib, в базовой его нет; синтаксис проверен командой otelcol-contrib validate на версии 0.163.1):
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 80
spike_limit_percentage: 20
tail_sampling:
decision_wait: 10s
policies:
- name: errors
type: status_code
status_code:
status_codes: [ERROR]
- name: slow
type: latency
latency:
threshold_ms: 500
- name: baseline
type: probabilistic
probabilistic:
sampling_percentage: 5
batch: {}
exporters:
otlp:
endpoint: tempo:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, tail_sampling, batch]
exporters: [otlp]
Коллектор принимает OTLP на портах 4317 (gRPC) и 4318 (HTTP). Через 10 секунд после первого спана (decision_wait) он сохраняет трейс, если подошла хотя бы одна политика: есть ошибка, длительность больше 500 мс или трейс попал в случайные 5%. Остальные отбрасываются, сохраненные уходят в Tempo.
decision_wait задает момент решения, а не гарантию полноты: трейс с ошибкой попадет в выборку, если нужные спаны пришли до решения и буфер не переполнен. tls.insecure годится только для учебного стенда. Если коллекторов несколько, перед ними нужна балансировка по trace ID, иначе части трейса разойдутся по разным экземплярам.
Хранение телеметрии: как не утонуть в данных
Больше всего места занимают логи, а их хранилища устроены по-разному:
- инвертированный индекс (OpenSearch, Elasticsearch) — быстрый полнотекстовый поиск, но индекс сам занимает место; OpenSearch сжимает данные по умолчанию, а другой кодек меняет баланс между размером хранилища и скоростью записи и поиска;
- индекс по меткам и сжатые блоки (Loki) — дешево хранить, медленнее искать по произвольному тексту;
- колоночное хранение (ClickHouse, VictoriaLogs) — обычно сильное сжатие из коробки и поиск по полям.
Сжатие зависит от структуры данных, поэтому хранилище выбирают не по чужим сравнениям, а тестом на части своих логов: сравнить место и скорость типичных запросов. Сократить объем помогают отказ от логов debug и trace в рабочей среде, сэмплирование однотипных access-логов, дедупликация, отбрасывание лишних полей в Collector и разные сроки хранения по сигналам.
Главная ловушка метрик — высокая кардинальность: каждая уникальная комбинация меток создает отдельный временной ряд. Метрика http_requests_total с метками route и status при десятке маршрутов и паре-тройке статусов дает несколько десятков рядов.
С меткой user_id количество рядов умножится на число пользователей. Идентификаторам пользователя, заказа или запроса место в логах и атрибутах спанов, а не в метках метрик.
Выводы
Главное из статьи:
- Observability — способность по метрикам, логам и трассировкам найти причину сбоя, которого не ждали. Мониторинг отвечает, что сломалось, наблюдаемость — почему.
- Переходить от метрик к трейсам и логам помогают общие ключи: trace ID в логах и одинаковые атрибуты сервиса. Это полезно и монолиту, а между сервисами особенно важно.
- OpenTelemetry стандартизирует сбор и передачу телеметрии по открытому протоколу OTLP, но не хранит данные; зрелость поддержки логов в SDK зависит от языка.
- Head-сэмплирование дешевое, но теряет редкие ошибки; tail отбирает трейсы с ошибками и задержкой, если спаны пришли до решения, ценой памяти коллектора и сборки трейса на одном экземпляре.
- Хранилище логов выбирают тестом на своих данных, а уникальные идентификаторы не кладут в метки метрик.
Где применяется на практике
Наблюдаемость полезна любой системе в рабочей среде, а с ростом числа сервисов без нее разбирать сбои все труднее. Повседневные задачи — разбор инцидентов, проверка релизов, контроль задержки при оплате. Собрать такой стек — типовая задача DevOps- и SRE-инженера, а все чаще и бэкенд-разработчика.
Системно пройти путь от метрик Prometheus до трассировок и OpenTelemetry можно на курсе «Observability: мониторинг, логирование, трассировка». Посмотреть разбор конфигураций вживую и задать вопросы преподавателю можно на открытых уроках Otus.
Смежные темы: Логи: что это, зачем нужны, уровни и виды логирования, NTP: как работает протокол сетевого времени и как настроить синхронизацию, Что такое DevOps: методология, практики и инструменты простыми словами.
FAQ
Нужна ли наблюдаемость монолиту?
Да, хотя и в меньшем объеме: метрики и структурированные логи нужны всегда, а трассировка внутри одного процесса покажет, сколько времени заняли запросы к базе и внешним сервисам.
Чем OpenTelemetry отличается от Prometheus?
У них разные роли: OpenTelemetry создает и доставляет телеметрию, а Prometheus хранит метрики и выполняет запросы к ним. Их часто используют вместе: Collector отправляет метрики в Prometheus или совместимое хранилище.
Замедляет ли инструментирование приложение?
Накладные расходы есть всегда и растут с числом спанов и атрибутов. Их стоит измерить под нагрузкой на своем сервисе, а снизить помогают сэмплирование и отказ от лишних атрибутов.

