Skip to content
PПромтбук
RUEN
04Производительность

Observability: метрики, логи, трейсы

Что и где собирать, как соединять три пилара, какой бюджет на cardinality и хранение.

Спроектируй observability для {{stack}}. Масштаб: {{scale}}.

Главное различие — monitoring vs observability. Monitoring отвечает на известные вопросы ("CPU > 80%?"). Observability — на новые ("почему вчера в 15:42 latency для tenant X выросла в 3 раза только на /search?"). Цель — система, в которой можно расследовать то, чего ты не предусмотрел.

Три пилара и их назначение

ПиларОтвечает наСилаСлабость
MetricsЧто? Сколько? Куда тренд?Дёшево хранить, быстрые запросы, alertsНизкая cardinality, без контекста
LogsЧто именно случилось с этим запросом?Богатый контекст, поиск по текстуОбъём, дорого, сложно агрегировать
TracesГде время / ошибка в цепочке сервисов?End-to-end видимость, причинно-следственнаяSampling нужен, инструментирование на каждом hop

Используй все три, но осознанно: каждое событие — это не каждый сразу в три места.

1. Метрики: что собирать

Golden signals (USE / RED)

RED для сервисов:

  • Rate — requests/sec по endpoint
  • Errors — error rate (5xx, 4xx отдельно)
  • Duration — гистограмма latency (p50, p95, p99)

USE для ресурсов:

  • Utilization — CPU, memory, disk %
  • Saturation — очереди (run queue, queue depth)
  • Errors — counter ошибок

Business metrics

Технические метрики не достаточны. Добавь:

  • Конверсия ключевых flow (signup, checkout)
  • Заказов / минуту
  • Активных юзеров
  • Cost / request (если важно)

Падение бизнес-метрики при зелёных техническом — самый частый incident.

Cardinality — главный враг

Метрика http_requests_total{endpoint, status} — ок (десятки endpoint × ~10 status кодов). Метрика http_requests_total{endpoint, status, user_id} — катастрофа: 1M юзеров × 100 endpoint = 100M time series. Бюджет Prometheus / Datadog взорвётся.

Правила:

  • High-cardinality (user_id, request_id, session_id) — никогда в метриках. Они идут в logs/traces
  • Bounded sets (env, region, plan, tier) — ок
  • Перед добавлением label — оцени кардинальность

2. Логи: что и как

Структурированные

JSON, не printf. Без структуры — невозможно фильтровать.

{
  "ts": "2026-05-17T10:11:12.345Z",
  "level": "error",
  "service": "billing",
  "trace_id": "abc123...",
  "span_id": "def456...",
  "user_id": "u_42",
  "tenant_id": "t_7",
  "request_id": "req_99",
  "msg": "charge failed",
  "error": { "code": "card_declined", "provider_ref": "..." },
  "amount_cents": 1999,
  "duration_ms": 432
}

Уровни — дисциплинированно

  • DEBUG — детальная отладка, выключено в prod (или sample)
  • INFO — заметные бизнес-события (заказ создан, юзер зашёл)
  • WARN — нештатно, но не баг (retry сработал, fallback использован)
  • ERROR — что-то не сработало, нужно посмотреть
  • FATAL — процесс умирает

Если в prod логи на INFO — > 90% объёма, у тебя проблема: пишешь шум.

Что НЕ логировать

  • PII (email, телефон) без хеширования / маскирования
  • Полные payload (могут содержать секреты)
  • Каждый успешный SQL-запрос (это для tracing)
  • Тонна одинаковых строк в цикле (sample)

Контекст

Каждая лог-запись должна иметь:

  • trace_id и span_id (для связи с трейсом)
  • request_id (если нет трейсинга)
  • user / tenant / env

Это делается через middleware один раз, не вручную в каждом лог-вызове.

3. Трейсы: что и как

Что инструментировать

  • HTTP входы/выходы
  • DB queries
  • External API calls
  • Queue publish / consume
  • Дорогие внутренние операции (рендеринг, вычисление)

OpenTelemetry — стандарт. Большинство фреймворков имеет auto-instrumentation.

Span атрибуты

  • HTTP: method, url, status, duration
  • DB: db.system, db.statement (без значений!), table
  • Custom: business-relevant (order_id, items_count)

Sampling

100% трейсов — слишком дорого. Стратегии:

  • Head sampling — решение на старте (1%, 10%) — простое, дешёвое, но теряет редкие ошибки
  • Tail sampling — собрать весь trace, решить сохранять ли (всегда сохраняй errors / slow) — лучше, но требует сборщика
  • Always sample errors + slow + sample regular at 1-10% — практичный компромисс

Связь с логами и метриками

Trace_id в каждой лог-записи и в exemplar'ах метрик (Prometheus + OTel поддерживает) — переход метрика → trace → лог в один клик.

4. Связывание трёх пиларов

Алерт: "p99 latency на /checkout > 2s"
       ↓ метрика → exemplar trace_id
Trace: видим что 80% времени в DB query
       ↓ trace span links
Logs:  фильтруем по trace_id → видим конкретный запрос с user_id
       ↓ user_id
Logs:  ищем все запросы user'а → видим pattern (retry storm)

Без trace_id в логах и exemplars в метриках — каждый incident это ручное соединение точек.

5. Алертинг

Симптом, не причина. Алёрти на то, что реально влияет на пользователя:

  • SLO violation (error budget burn rate)
  • High p99 latency
  • Бизнес-метрика упала
  • DLQ inflow

Не алёрти на:

  • "CPU > 80%" сам по себе (это симптом, не проблема — может быть нормально)
  • Каждый 5xx (шум) — алёрти на rate
  • Disk space на 1% за день вперёд (есть время, не P1)

Каждый алерт имеет:

  • Runbook (что делать)
  • Severity (P0/P1/P2 с разными каналами)
  • Owner

6. SLI / SLO

Service Level Indicator — измеримая метрика качества (% успешных запросов под 200ms). Service Level Objective — цель (99.9% за 30 дней). Error budget — что осталось до нарушения (10 min downtime в месяц при 99.97%).

Burn rate alert: тревожить не "у нас 0.5% ошибок", а "при текущем темпе бюджет кончится через 4 часа".

7. Бюджет и retention

Observability стоит реальных денег. Распределяй:

ТипVolumeRetentionСтоимость
High-resolution metrics (1s)малый1-7 днейсредне
Standard metrics (1min)средний90-400 днейдёшево
Logs (info+)большой7-30 дней горячеедорого
Logs (debug)очень большойsample 1-10% или off в prod
Tracesсредний (sampled)7-14 днейсредне
Audit logsмалыйгодыдёшево, но обязательно

Tip: дешёвый "холодный" storage (S3 + Athena) для долгой ретенции; горячий — только для оперативного дебага.

8. Стек

  • Metrics: Prometheus + Grafana (open), Datadog / New Relic / Honeycomb (SaaS), CloudWatch (AWS)
  • Logs: Loki, ELK, Datadog, CloudWatch Logs, OpenSearch
  • Traces: Jaeger, Tempo, Datadog APM, Honeycomb
  • Standard: OpenTelemetry на стороне приложения, backends свободно меняешь

Не вендор-локись через проприетарные SDK; пиши через OTel.

9. Health checks vs metrics

  • Liveness probe — "процесс жив?". Простой. Failure → restart
  • Readiness probe — "готов принимать трафик?" (deps ok, warm cache). Failure → удаляем из LB
  • Startup probe — для медленного старта (миграции). Не путать с liveness

Health check — это не observability, это управление трафиком. Метрики и логи нужны отдельно.

10. Чек-лист зрелости

  • Каждый сервис экспортирует RED-метрики
  • Логи структурированные с trace_id
  • OTel инструментация на HTTP / DB / queue
  • SLO определены для top-3 user-facing flow
  • Алерты — по SLO burn rate, не по симптомам
  • У каждого алерта есть runbook и owner
  • Дашборд "один сервис" с RED + ресурсами в шаблоне
  • Sampling настроен (errors всегда, остальное %)
  • Cardinality budget описан
  • Cost monitoring самой observability

Анти-паттерны

  • Логировать "на всякий случай" каждое поле в DEBUG в prod — счёт за хранение взорвётся
  • Метрика с user_id в label — cardinality bomb
  • Trace без context propagation — каждый сервис делает свой root span
  • Алерт на каждую ошибку — alert fatigue, важное теряется
  • "У нас же есть Datadog" — но никто не смотрит до incident
  • 99.999% SLO без обоснования — недостижимо и дорого, перепланируешь архитектуру под нереальное требование
  • Логи без trace_id, метрики без exemplars — три пилара становятся тремя островами

В конце

  • Карта: какие сервисы и что инструментировано
  • RED для каждого критичного flow
  • SLO и burn rate alerts для top-N flow
  • Логирование conventions (формат, уровни, что нельзя)
  • Sampling-стратегия для трейсов
  • Cardinality budget по сервисам
  • Бюджет $$ на observability и retention policy
  • Runbook каждого алерта
Похожие промты