Мониторинг и observability: метрики, журналы, трассировки и оповещения
Как построить наблюдаемость приложения: метрики, структурированные журналы и трассировка на OpenTelemetry, методы RED и USE, оповещения по симптомам, SLO и бюджет ошибок, RUM и синтетические проверки, выбор стека.
О сбое в продакшене можно узнать тремя способами: от системы мониторинга за минуту до того, как пользователи заметят проблему; от пользователей через поддержку через полчаса; или от руководителя, который прочитал отзыв, на следующее утро. Разница между этими вариантами — не везение, а наблюдаемость: способность по внешним сигналам системы понять, что в ней происходит и почему. Это руководство о том, как построить наблюдаемость веб-приложения и инфраструктуры: чем мониторинг отличается от observability, как работают метрики, журналы и трассировка, что измерять, как настроить оповещения, которые не превращаются в шум, что такое SLO и бюджет ошибок, как наблюдать за реальными пользователями и какой стек выбрать в российских условиях. Мониторинг и observability Мониторинг отвечает на заранее известные вопросы: работает ли сервис, не превышена ли загрузка процессора, не растёт ли число ошибок. Он хорош для известных сценариев отказа. Observability позволяет разобраться в проблемах, которые никто не предвидел: почему у пользователей из одного региона медленно оформляется заказ только с определённым способом оплаты. Для этого нужны данные с достаточной детализацией и связанные между собой. Мониторинг — часть наблюдаемости. На практике система зрелая, когда оповещения сообщают о проблеме, а метрики, журналы и трассировки позволяют быстро найти её причину. Три типа сигналов Метрики Числовые значения во времени: число запросов, доля ошибок, время ответа, загрузка ресурсов, длина очереди, число заказов. Дёшевы в хранении, быстро агрегируются и идеально подходят для дашбордов и оповещений. Счётчики только растут: число запросов, ошибок, отправленных писем. Датчики меняются в обе стороны: использование памяти, число активных подключений. Гистограммы распределяют значения по интервалам: время ответа. Позволяют считать процентили — например, время, в которое укладываются 95% запросов. Среднее время ответа почти бесполезно: оно скрывает медленные запросы, которые и видят недовольные пользователи. Смотрите на процентили. import client from 'prom-client'; const httpDuration = new client.Histogram({ name: 'http_request_duration_seconds', help: 'Время обработки HTTP-запросов', labelNames: ['method', 'route', 'status'], buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5], }); app.use((req, res, next) = { const end = httpDuration.startTimer(); res.on('finish', () = { end({ method: req.method, route: req.route?.path ?? 'unknown', status: res.statusCode }); }); next(); }); app.get('/metrics', async (_req, res) = { res.set('Content-Type', client.register.contentType); res.end(await client.register.metrics()); }); Важно следить за кардинальностью меток. Метка с идентификатором пользователя или полным адресом запроса создаёт отдельный временной ряд для каждого значения и быстро перегружает систему хранения метрик. В метках — маршрут-шаблон, а не конкретный адрес. Журналы Записи о событиях с деталями: что произошло, с какими параметрами, с каким результатом. Незаменимы для разбора конкретного случая. import pino from 'pino'; const logger = pino({ level: process.env.LOG_LEVEL ?? 'info' }); logger.info( { orderId, userId, amount, provider: 'sbp', durationMs, traceId }, 'payment completed', ); Структурированный формат — JSON с полями, а не произвольный текст: по полям можно искать и агрегировать. Идентификатор трассировки в каждой записи связывает журналы с трассировками и между сервисами. Уровни — ошибки, предупреждения, информационные события, отладка. Отладочный уровень в продакшене включается временно. Без секретов и лишних персональных данных: пароли, токены, полные номера карт и паспортные данные не пишутся в журналы. Централизация: в контейнерах приложение пишет в стандартный вывод, сборщик отправляет журналы в хранилище. Трассировки Путь одного запроса через все сервисы и компоненты: сколько времени занял каждый шаг, где возникла ошибка. Без трассировки в распределённой системе на вопрос «почему этот запрос выполнялся восемь секунд» приходится отвечать сопоставлением журналов десятка сервисов. Стандартом стал OpenTelemetry — открытый набор спецификаций, библиотек и сборщиков для метрик, журналов и трассировок, не привязанный к конкретному поставщику. Данные передаются по протоколу OTLP в любую совместимую систему хранения. // tracing.js — подключается до запуска приложения import { NodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; const sdk = new NodeSDK({ serviceName: 'orders-api', traceExporter: new OTLPTraceExporter({ url: 'http://otel-collector:4318/v1/traces' }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); Автоматическая инструментация перехватывает HTTP-запросы, обращения к базам данных и очередям без изменения кода; ключевые бизнес-операции дополняют собственными участками трассировки. Что измерять Для сервисов: метод RED Rate — число запросов в секунду; Errors — доля ошибочных запросов; Duration — распределение времени ответа. Для ресурсов: метод USE Utilization — загрузка: процессор, память, диск, сеть; Saturation — насыщение: очереди, ожидающие потоки, исчерпание пулов подключений; Errors — ошибки ресурса. Четыре золотых сигнала В книге Google по SRE сформулирован близкий набор: задержка, трафик, ошибки и насыщение. Если нет времени на большее, начните с них для каждого пользовательского сервиса. Бизнес-метрики Технически сервис может отвечать без ошибок, а заказы при этом не создаются — например, из-за сбоя интеграции с платёжным провайдером. Метрики бизнес-процессов — число заказов, успешных оплат, регистраций, отправленных заявок — часто замечают проблему раньше технических и напрямую показывают её цену. Оповещения, которым доверяют Худший результат мониторинга — оповещения, которые приходят так часто, что их перестают читать. Правила: Оповещать о симптомах, а не о причинах. «Доля ошибок при оформлении заказа выше порога» важнее, чем «загрузка процессора 85%». Высокая загрузка без влияния на пользователей — не повод будить человека ночью. Каждое оповещение требует действия. Если на оповещение нечего сделать, это не оповещение, а строка на дашборде. Разные уровни срочности. Срочные — немедленно дежурному, несрочные — в рабочий чат или задачу. Задержка перед срабатыванием отсекает кратковременные всплески. Инструкция к оповещению: что проверить в первую очередь, ссылка на дашборд и порядок действий. Регулярный пересмотр: оповещения, которые срабатывали без реальной проблемы, настраиваются или удаляются. groups: - name: orders-api rules: - alert: CheckoutErrorRateHigh expr: | sum(rate(http_request_duration_seconds_count{route="/api/checkout", status=~"5.."}[5m])) / sum(rate(http_request_duration_seconds_count{route="/api/checkout"}[5m])) 0.02 for: 5m labels: { severity: page } annotations: summary: "Более 2% ошибок при оформлении заказа" runbook: "https://wiki.example.ru/runbooks/checkout-errors" SLI, SLO и бюджет ошибок SLI — показатель уровня сервиса: например, доля запросов к оформлению заказа, выполненных успешно быстрее одной секунды. SLO — цель для этого показателя за период: например, 99,5% таких запросов за 30 дней. Бюджет ошибок — допустимая доля неудачных запросов, которая остаётся до нарушения цели. При цели 99,5% это 0,5% запросов за период. SLO переводят разговор о надёжности из «должно работать всегда» в конкретные договорённости. Пока бюджет ошибок не исчерпан, команда может выкладывать изменения и экспериментировать. Когда бюджет расходуется быстро, приоритет смещается на стабильность. Оповещения по скорости расходования бюджета точнее простых порогов: они реагируют на проблемы, которые действительно угрожают цели. Цель не должна быть выше, чем нужно пользователям и бизнесу: каждая дополнительная девятка доступности кратно дороже. Как доступность связана с процессами выкладки и восстановления, — в статье о DevOps и time-to-market . Наблюдение за реальными пользователями RUM — сбор данных из браузеров и мобильных приложений реальных пользователей: время загрузки, Core Web Vitals, ошибки JavaScript, медленные действия. Показывает то, чего не видно на сервере: медленные устройства, плохие сети, ошибки в конкретных браузерах. Отслеживание ошибок клиента — сбор исключений со стеками и контекстом, группировка одинаковых ошибок, привязка к версии приложения. Синтетические проверки — автоматические сценарии, которые регулярно проходят ключевые пути из разных точек: открыть главную, найти товар, дойти до оплаты. Замечают проблему даже ночью, когда реальных пользователей мало. import { onLCP, onINP, onCLS } from 'web-vitals'; function send(metric) { navigator.sendBeacon('/rum', JSON.stringify({ name: metric.name, value: metric.value, rating: metric.rating, page: location.pathname, })); } onLCP(send); onINP(send); onCLS(send); Как улучшать эти показатели, — в статье о performance optimization . Проверки здоровья Проверка жизнеспособности отвечает, жив ли процесс, и не зависит от внешних систем. Проверка готовности отвечает, может ли экземпляр обслуживать запросы: подключена ли база данных, прогреты ли кэши. Смешивание этих проверок приводит к каскадным перезапускам: база данных недоступна — оркестратор перезапускает все экземпляры приложения, и восстановление затягивается. Подробно — в статье о Docker и Kubernetes . Стек наблюдаемости Открытые решения Prometheus — сбор и хранение метрик, язык запросов PromQL, правила оповещений; Grafana — дашборды и визуализация всех типов данных; Loki или OpenSearch и Elasticsearch — хранение и поиск журналов; Tempo или Jaeger — хранение и анализ трассировок; OpenTelemetry Collector — единый приёмник, обработка и маршрутизация всех сигналов; Alertmanager — группировка, подавление и маршрутизация оповещений. Такой стек не зависит от поставщика и может быть развёрнут в собственной инфраструктуре или у российского облачного провайдера. Цена — эксплуатация: хранилища журналов и трассировок требуют ресурсов и внимания. Облачные сервисы Российские облачные провайдеры предлагают сервисы мониторинга и журналирования, интегрированные с их инфраструктурой. Зарубежные APM-платформы функционально развиты, но их доступность, условия оплаты и передача телеметрии за рубеж для российских компаний — вопросы, которые нужно решить до выбора. Телеметрия нередко содержит персональные данные — идентификаторы пользователей, IP-адреса, фрагменты запросов, — и на неё распространяются требования к их обработке. Стоимость Журналы и трассировки — самая дорогая часть наблюдаемости по объёму хранения. Управляют стоимостью через уровни журналирования, выборку трассировок — например, сохранять все трассировки с ошибками и медленные, а успешные быстрые — частично, — и разные сроки хранения для разных данных. С чего начать Централизованные журналы в структурированном формате с идентификатором запроса. Метрики RED для каждого пользовательского сервиса и базовые метрики инфраструктуры. Отслеживание ошибок на сервере и в клиенте. Несколько оповещений по симптомам для ключевых сценариев: главная, вход, оформление заказа, оплата. Синтетическая проверка критического пути пользователя. Трассировка через OpenTelemetry , когда сервисов становится больше одного-двух. SLO для ключевых сервисов и оповещения по бюджету ошибок. Разбор инцидентов с вопросом «как мы могли узнать об этом раньше» и доработкой наблюдаемости по итогам. Архитектурные вопросы отказоустойчивости облачных систем разобраны в статье о cloud-native архитектуре . Наблюдаемость, оповещения и эксплуатацию продуктов мы настраиваем в рамках автоматизации и поддержки проектов веб-разработки . Частые вопросы Нужна ли observability небольшому проекту? Базовый уровень — да: централизованные журналы, отслеживание ошибок, проверка доступности и несколько оповещений. Это недорого и защищает от ситуации, когда о сбое сообщают клиенты. Полный стек с трассировкой и SLO нужен по мере роста сложности системы. Что лучше: журналы или метрики? Это разные инструменты. Ме