Observability: что это и чем наблюдаемость отличается от мониторинга

Observability (наблюдаемость) — это свойство системы, при котором по ее внешним данным — метрикам, логам и трассировкам — можно понять, что происходит внутри, и найти причину сбоя, для которого заранее не настроили ни проверку, ни дашборд. Мониторинг решает более узкую задачу: следит за известными показателями и сообщает, что что-то пошло не так.

Ниже — сравнение с мониторингом, три вида телеметрии, 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 или совместимое хранилище.

Замедляет ли инструментирование приложение?
Накладные расходы есть всегда и растут с числом спанов и атрибутов. Их стоит измерить под нагрузкой на своем сервисе, а снизить помогают сэмплирование и отказ от лишних атрибутов.

OTUS Журнал
Распродажа ноябрьских курсов (поп-ап)
Бесплатные открытые уроки (поп-ап)