Прямой ответ
SLO без дашборда — абстракция: «цель 99.9%» живёт в вики, решения принимаются по ощущениям (SLO-основы — error budget не расходуется осознанно — релизы «на удачу»); рабочий SLO-дашборд (Grafana — дашборд-практика) состоит из пяти панелей: (1) SLI сейчас (доступность/латентность за час — большое число с цветовой границей — «что происходит прямо сейчас» — gauge 98–100%); (2) SLI за окно SLO (30 дней rolling — против целевой линии — «держим ли цель» — главный график — гистограммы-источник — запрос: 1 - (sum(increase(http_errors_total[30d])) / sum(increase(http_requests_total[30d])))); (3) error budget (остаток бюджета — 100% × (1 − израсходовано/допущено) — «потратили 40% бюджета за неделю» — визуализация: stat с порогом/бар — решение «можно ли рисковать» — данные, не мнения — ёмкость-решения); (4) burn rate (скорость сжигания — «текущий темп ×N от допустимого» — 1x = идем впритык к цели, 14x = бюджет сгорит за 2 дня — метрики-логика — самый действенный график — психологически «14x» понятнее «99.83%»); (5) инциденты на таймлайне (аннотации — деплои/инциденты поверх SLI-графика — деплой-аннотации — «бюджет сгорел вот здесь, после этого релиза» — причинность видна — Grafana annotations из Alertmanager/CI-webhook (вебхук-механика); SLI-запросы (ядро — два типа SLI): доступность (доля успешных: 5xx/таймауты — ошибки; «успех» — определение из SLO-практики — 4xx клиента — не наша ошибка — спорное — фиксировать решение — ADR), латентность (доля запросов быстрее порога: sum(rate(http_request_duration_seconds_bucket{le="0.3"}[5m])) / sum(rate(http_request_duration_seconds_count[5m])) — гистограммный расчёт — процентилям — порог 300 мс — SLO «95% быстрее 300 мс»); multiwindow alerting (алерты по burn rate, не по SLI — Google-паттерн: 14.4x за 1h+5m (страница немедленно — бюджет сгорит за 2 дня), 6x за 6h+30m (страница), 1x за 3d (тикет — медленное сгорание — алерты-практика) — «SLI < 99.9%» как алерт — ложные срабатывания/запаздывание — burn rate решает — Alertmanager-маршруты); хранение истории: SLO-окна 30 дней+ — retention Prometheus (Mimir для долгой истории — «бюджет за квартал» — нужен архив — retention); recording rules для тяжёлых 30d-запросов (дашборд не пересчитывает месяц на каждое открытие — предагрегаты — recording rules — дашборд открывается за секунды — Grafana-UX); процесс вокруг дашборда (без него панели — обои): еженедельный обзор (10 минут на стендапе — бюджет/burn — «риск-решения» — релизы/эксперименты планируются от бюджета — релиз-ритм), политика бюджета (бюджет <25% — фичи-фриз/фокус на надёжность — техдолг-баланс — правило записано — выполняется — «SLO-театр» — когда правило есть, а решений нет — антипаттерн), постмортемы с бюджет-влиянием (инцидент-практика — «инцидент стоил 8% бюджета» — валюта разговора с бизнесом).
Практика: от SLI-определения до живого дашборда
Пошагово (API-сервис, SLO «99.9% успеха, 95% < 300 мс», окно 30 дней): (1) инструментация (метрики — http_requests_total{route,status}, гистограмма duration с бакетами вокруг 300 мс — 0.1/0.2/0.3/0.5 — бакеты-дизайн — кардинальность-контроль — route-шаблоны); (2) recording rules (job:sli_error:ratio_rate5m, job:sli_latency_fast:ratio_rate5m + оконные агрегаты — recording-практика — дашборд-запросы — лёгкие); (3) панели (пять из первого раздела — переменные job/route (Grafana — SLO per-сервис — один шаблон дашборда на парк — шаблонизация — provisioned dashboards в git — IaC — «дашборд как код» — ревью изменений — ревью); (4) алерты (burn rate-правила — multiwindow — PromQL: (error_ratio_1h > 14.4 * (1-0.999)) and (error_ratio_5m > 14.4 * (1-0.999)) — пара окон против flapping — алерт-дизайн); (5) проверка боем (chaos-инъекция — 5% ошибок на 10 минут (chaos) — дашборд показал burn 50x, алерт 14.4x сработал на 6-й минуте, бюджет уменьшился на 0.8% — «дашборд врёт?» — нет, работает — тест-кейс SLO-системы — тесты — «не проверенный мониторинг не существует» — метрики-тестирование); (6) процесс (обзор на стендапе, политика фичи-фриза при 25%, постмортемы с бюджет-цифрами — incident); типичные ошибки внедрения: SLI по внутренним метрикам вместо пользовательских («CPU 50% — значит хорошо» — пользователь видит ошибки — SLI — от запросов/пользователя — SLO-определение), SLO 100% («ноль ошибок» — бюджет нулевой — любой чих — «фриз навсегда» — 99.9/99.95 — реалистичные цели — цели-дизайн), окно «с начала месяца» вместо rolling 30d (1-го числа бюджет сбрасывается — «месячная амнезия» — инцидент 29-го прощён — rolling-окно честно), дашборд без алертов (или наоборот — алерты без дашборда — «страница пришла, контекста нет» — пара обязательна — oncall-культура).
Практический сценарий: error budget разрешил спор «релизы против стабильности»
Контекст: продуктовая команда (SaaS) — конфликт месяцев: продакт «релизы каждую неделю», SRE «стабильность, релизы реже» — аргументы-ощущения, эскалации до CTO; решение — SLO-система (2 спринта): SLO 99.9% успеха rolling-30d (исторические данные: факт 99.82–99.97% — цель реалистична — SLO-выбор), дашборд (5 панелей — практика выше — Grafana), политика (бюджет >50% — релизы свободно + эксперименты (canary/флаги — риск осознанный), 25–50% — релизы с усиленным ревью (ревью-чеклист), <25% — только фиксы надёжности (техдолг-фокус), сгорел — фичи-стоп до восстановления — правило подписано продактом и CTO — ADR); первые три месяца жизни системы: месяц 1 — бюджет 62% (два инцидента — 22%+16% — постмортемы — релизы шли — правило соблюдено — доверие к цифрам росло); месяц 2 — релиз-волна при бюджете 80% — canary-эксперимент сгорел за час (burn 20x — алерт — откат — стратегии) — бюджет −9% — «рисковали осознанно, потеряли измеримо» — продакт впервые увидел цену риска в цифрах; месяц 3 — бюджет 12% (устаревший cron-инцидент — блокировки) — фичи-фриз сработал (2 недели — надёжность — бюджет восстановился до 45% — «фриз» не стал катастрофой — план сработал); итоги полугода: релизы — 4–6/мес (было «или 8 хаотичных, или 2 под давлением» — ритм стабилен), инциденты −40% (бюджет-дисциплина + алерты), спор «релизы против стабильности» исчез (решает не громкость мнения, а остаток бюджета — данные вместо политики — SRE-культура); главный вывод: ценность дашборда — не графики, а общая валюта разговора (продакт/SRE/CTO смотрят на одно число — решения принимаются от него — observability-зрелость (три столпа) достигает продуктового уровня).
FAQ
Как считать error budget, если сервисов много? Варианты по зрелости: per-сервис SLO (каждый сервис — свой дашборд-шаблон с переменными (Grafana) — владельцы отвечают за своё — норма для 5+ сервисов — микросервисы); journey-SLO (пользовательский путь — «checkout: 99.9% успеха» — метрики ключевых шагов — бизнес-уровень — «покупка проходит» важнее «сервис A жив» — SLO-иерархия); компонентные (БД/очередь — SLO инфраструктуры — ёмкость — внутренние — для инженеров); практика: 1–3 journey-SLO (бизнес видит) + per-сервис (команды видят) — дашборд-иерархия (обзорный → детальный — Grafana-links — drill-down кликом); хранение: долгая история в Mimir (квартальные отчёты бюджета — retention); антипаттерн: «средний SLO по всем сервисам» (агрегат скрывает — один сервис горит — среднее зелёное — гистограммы-урок — средние врут — распределение/по-сервисно).
Почему алертить по burn rate, а не по значению SLI?
Проблема SLI-алерта (SLI < 99.9% → page): пороговая хрупкость (SLI колеблется у границы — flapping — страница-тишина-страница — alert fatigue), запаздывание (30d-окно — инцидент «уже сгорел», алерт — когда средний просел — поздно), ложность (мелкий всплеск в 30d-окне не двигает SLI — а бюджет горит — «SLI зелёный, бюджет −20%»); burn rate решает: скорость вместо уровня («сжигаем в 14 раз быстрее нормы» — инцидент виден за минуты независимо от окна), multiwindow (1h+5m — быстро и без flapping — пара окон фильтрует шум — алерт-дизайн), градация (14.4x — page, 6x — page, 1x — ticket — серьёзность от скорости — Alertmanager-маршруты — Google SRE-таблица — стандарт); SLI-значение — для дашборда (контекст/тренд), burn rate — для алертов — разделение ролей — метрики-дисциплина.
Как связать SLO-дашборд с трейсами и логами? Связки: аннотации инцидентов/деплоев на SLI-графике (Grafana annotations — webhook из CI (вебхуки) / Alertmanager-события — «бюджет сгорел после этого релиза» — визуальная причинность — сценарий выше); exemplars на графиках (метрики с exemplar-ссылками на трейсы (Tempo/Jaeger — клик с графика ошибок → пример трейса — процентилям — «ошибка → конкретный запрос» — расследование без ручного поиска); drill-down-ссылки (панель SLI → дашборд сервиса → Loki-запрос по ошибочным логам окна — Alloy-пайплайн — единые метки service/env — структура-меток — переходы работают); runbook-ссылки в алертах (burn-алерт → runbook-страница (incident — дежурный не ищет «что делать» — oncall); полный путь инцидента: алерт burn → дашборд SLO (что/когда) → трейсы (где) → логи (почему) → профиль (Pyroscope — глубоко) — минуты вместо часов — observability-стек окупается в инцидентах — SRE.
Error budget сгорел — что конкретно делать? Политика (записанная заранее — иначе каждый раз спор): фичи-фриз (только надёжность — техдолг — «бюджет — валюта риска» — нет бюджета — нет релизов — правило, не наказание), фокус-работы (постмортемы сгоревшего (incident) — топ-причины — фикс-волна — планирование — «сгорело от трёх причин — чиним три»), проверка цели (регулярно сгораем до конца — SLO амбициознее возможностей — пересмотр цели/инвестиции в надёжность — честный разговор с бизнесом (SLO-дизайн — цель — договор, не догма); что НЕ делать: «игнорировать и релизить» (политика мертва — SLO-театр — доверие к метрикам падает — техдолг-культура), «снизить цель задним числом» (бюджет «восстановлен» манипуляцией — обман себя — пересмотр — только плановый/прозрачный — ADR), «наказать команду» (бюджет — инструмент решений, не KPI-кнут — иначе метрики начнут рисовать — Goodhart-эффект — аналогия — метрика-цель перестаёт быть метрикой); восстановление бюджета — rolling-окно само «залечит» старые инциденты за 30 дней при чистой работе — механика, не магия — SLO-практика.
Источники: Google SRE Workbook (implementing SLOs, alerting on SLOs), Grafana docs — ссылки в шапке.