«Четыре золотых сигнала» Google SRE — latency, traffic, errors, saturation — обязательный baseline на любом архитектурном интервью. На практике их перечисляют по памяти и ставят галочку, а через год инцидент-постмортем показывает, что ни один из четырёх в проде не ловил того, что должен был.
Что каждый сигнал на самом деле ловит
Latency. Не average — average маскирует tail. Только p95 / p99. Запрос, который раз в десять отдают пять секунд, в average не виден; пользователь, которому не повезло, уходит. Разделять latency успехов и latency ошибок: 500 за 50 мс и 200 за 5 секунд означают разные пожары.
Traffic. Не «сколько RPS», а — куда они уходят. Per-target imbalance на балансировщике больше 40 % означает скрытую деградацию: одна нода превращается в цифровую чёрную дыру, 99 % трафика обрабатывается, 1 % висит без алертов. Slowness хуже падения — retention падает молча.
Errors. Явные 5xx — половина картины. Implicit-ошибки — таймауты, отвалившиеся upstream'ы, ретраи, «успешно» завершившиеся шестой попыткой — в стандартный счётчик 5xx не попадают. Error budget строится по success-rate, не по 5xx.
Saturation. Самая обманчивая метрика. I/O-bound сервис (ждёт БД или внешний API) при p99 latency 8 секунд показывает CPU 12 %. Поды не нагружены — они ждут. HPA autoscaling/v2 по CPU/memory целиком слепо к этой ситуации; для autoscaler'а она выглядит как «система без трафика», и он масштабирует вниз. Saturation мерят через request rate, queue depth, SLO burn rate — то есть через KEDA, не через нативный HPA.
Причинно-следственная цепочка отказа: traffic↑ → saturation↑ → latency↑ → errors↑. Отслеживая её, проблему ловят до пользовательского impact'а. Перечисление сигналов по памяти этого не даёт.
Почему стек — VictoriaMetrics + Loki
Prometheus как референсная реализация Four Golden Signals до сих пор стандарт. В production-проде 2026 года чаще выбирают VictoriaMetrics: 10× плотность хранения, 10× больше активных серий, MetricsQL как надмножество PromQL, встроенный long-term storage без отдельного Thanos/Cortex. vmagent легче Prometheus'а как скрейпер, vmauth закрывает multi-tenancy.
Логи — Loki. Не потому, что лучше OpenSearch, а потому, что full-text индексация дорога и редко нужна. Loki индексирует только labels, тело лога хранит дёшево. Корреляция метрики и лога — через общий trace_id или request_id, не через full-text join. Promtail ушёл в maintenance-режим: на свежих кластерах ставят Grafana Alloy — единый pipeline-коллектор на River language, заменяющий Promtail + node-exporter + OTel Collector одним DaemonSet'ом.
Объяснение «у нас мониторинг» через имена инструментов — слабый сигнал. Сильный — через data flow:
Application → OTel SDK / OBI
→ Collection (vmagent / Alloy)
→ Storage (VictoriaMetrics / Loki)
→ Visualization (Grafana)
→ Alerting (Alertmanager)
Схема работает при замене узлов: Loki на OpenSearch, VictoriaMetrics на Datadog — структура та же. Архитектор объясняет flow и trade-offs на каждом узле; инженер — перечисляет tool names.
Три ловушки «у нас мониторинг есть»
Мониторят producer, не output. ALB target group зелёная четыре дня, пока sitemap.xml — stale, потому что фоновый сервис, его генерирующий, потерял alias. Health-check producer'а не ловит этого никогда. Каждый externally-consumed артефакт получает отдельную freshness-проверку — probe на возраст по Last-Modified. Мониторят output, не только producer.
Cardinality explosion в labels. user_id, session_id, request_id, pod_uid, path без нормализации — мгновенная смерть TSDB через несколько недель. Эти метки запрещают на code-review для метрик так же строго, как ревьюят prod-код. Высококардинальные данные живут в trace attributes (sampled) и в log fields, не в metric labels.
Local alerting на тот же кластер. Падает кластер — падают и алерты, которые должны были предупредить о падении. Control plane observability — отдельный кластер, managed-сервис, либо внешний receiver. Push, не pull. Если наблюдаемый кластер падает, наблюдатель видит тишину как сигнал, а не как отсутствие данных.
Минимум, который реально стоит за «у нас мониторинг»
Не 50 алертов, а 5–8 actionable. Каждый алерт — runbook_url в annotations. Каждый critical-алерт — SLO burn rate с multi-window, не threshold flap. Каждый сервис — структурные JSON-логи с trace_id, service, team, env. И раз в квартал — disaster-visibility test: симуляция падения наблюдаемого кластера. Если алерты не доходят, а дашборды чёрные — observability отстаёт на стадию-две, и реальный инцидент это покажет дороже, чем учебный.