5. SLA, SLO, SLI

От инженерных метрик к бизнес-надежности

«Если поставить себе цель 100% надежности, вы никогда больше не выпустите в свет ничего нового».
— Бен Трейнор (основатель Site Reliability Engineering в Google)

В предыдущих статьях мы подробно изучили, как измерять поведение системы: научились настраивать Counter, собирать перцентили через Histogram и фильтровать измерения лейблами. Но здесь инженера подстерегает опасная иллюзия: легко увешать экран десятками графиков CPU, IOPS и свободной памяти, забыв о главном вопросе: «А доволен ли пользователь сервиса?».

Процессор может быть загружен всего на 2%, память свободна на 90%, а база данных рапортует об идеальном состоянии. Но если при этом упал ingress-контроллер или шлюз платежной системы, и ни один покупатель не может оформить заказ — ваша система на 100% мертва для бизнеса.

Чтобы перекинуть надежный мост между техническими датчиками (железом, рантаймом Go) и реальной ценностью для пользователей, инженеры Google в рамках практики Site Reliability Engineering (SRE) разработали стройный математический фреймворк: SLI, SLO и SLA.


Иерархия надежности

Три этих акронима образуют строгую восходящую пирамиду понятий:

flowchart TD
    A["SLI<br>Service Level Indicator"] -->|"Измеряет"| B["Что происходит?<br>(Фактическая метрика)"]
    C["SLO<br>Service Level Objective"] -->|"Цель"| D["Что мы обещаем?<br>(Инженерная норма)"]
    E["SLA<br>Service Level Agreement"] -->|"Контракт"| F["Что будет,<br>если нарушим?<br>(Юридические последствия)"]

    A --> C
    C --> E

    style A fill:#1e293b,stroke:#38bdf8,stroke-width:2px,color:#fff
    style C fill:#312e81,stroke:#818cf8,stroke-width:2px,color:#fff
    style E fill:#78350f,stroke:#f59e0b,stroke-width:2px,color:#fff
  

1. SLI (Service Level Indicator) — Индикатор

Это метрика, которая непосредственно отражает поведение системы с точки зрения пользователя.
SLI должен отвечать на вопрос: «Было ли обслуживание успешным?».

В качестве SLI выбираются не абстрактные аппаратные ресурсы, а пользовательский опыт:

  • Доступность (Availability): Доля успешных ответов (HTTP 200) от общего числа запросов.
  • Задержка (Latency): Доля запросов, обработанных быстрее порогового значения (например, 100мс).
  • Пропускная способность: Количество запросов в секунду.

2. SLO (Service Level Objective) — Цель

Это целевое значение для SLI. Это договоренность внутри команды и с бизнесом о том, что считается «нормальной работой».

  • Пример: «99.9% запросов должны возвращаться успешно за месяц».
  • Пример: «99% запросов должны обрабатываться быстрее 200мс».

SLO — это инструмент управления ожиданиями. Если SLO выполняется, пользователи счастливы. Если нет — нужно звать на помощь.

Критически важно понимать: SLO никогда не должен быть равен 100%. 100% надежности в реальном мире не существует — падают кабели под океанами, сбоит память серверов, пользователи выходят в метро и теряют связь. Попытка добиться 100% доступности стоит экспоненциально дорого и намертво останавливает разработку новых фич.

3. SLA (Service Level Agreement) — Соглашение

Это формальный контракт с клиентом (часто финансовый), описывающий последствия нарушения SLO.

  • «Если доступность упадет ниже 99.9%, мы вернем 10% стоимости подписки».

Error Budget (Бюджет ошибок)

Самая мощная концепция, вытекающая из SLO — Error Budget.
Если ваша цель (SLO) — 99.9% доступности, то у вас есть 0.1% «бюджета» на ошибки.

Физическая аналогия: бюджет на отпуск или бензобак автомобиля. Вы можете тратить бензин на быстрые обгоны (деплои и рискованные архитектурные эксперименты), пока в баке есть топливо. Но если стрелка на нуле — автомобиль обязан снизить скорость и двигаться только на станцию техобслуживания.

Зачем это нужно?

  1. Скорость разработки vs Стабильность: Если бюджет полон (ошибок мало) — можно смело деплоить новые фичи, рисковать, проводить рефакторинг. Если бюджет исчерпан (вы на грани нарушения SLO) — разработка замораживается, команда занимается только баг-фиксами и стабильностью.
  2. Объективные решения: Больше не нужно спорить «можно ли деплоить в пятницу?». Смотрим на Error Budget. Если он есть — можно. Если нет — нельзя.

Расчет бюджета:
Для SLO 99.9% за 30 дней:
$$ 30 \times 24 \times 60 \times 60 \times 0.001 \approx 43.2 \text{ минуты простоя в месяц} $$
Это значит, что все сбои в сумме не должны превышать 43 минуты в месяц.

Для трех девяток с половиной (99.95%) бюджет составляет всего 21.6 минуты, а для четырех девяток (99.99%) — жалкие 4.3 минуты за целый месяц!


Реализация SLO в Prometheus

Как превратить эти абстрактные цифры в работающие алерты?

SLI: Доступность (Availability)

Мы используем Counter'ы успешных и неуспешных запросов.

PROMQL
# SLI: Доля успешных запросов (HTTP 2xx, 3xx) за последние 7 дней
sum(rate(http_requests_total{status!~"5.."}[7d])) 
/ 
sum(rate(http_requests_total[7d]))

SLO: Проверка цели

Если мы хотим узнать, соблюдается ли SLO 99.9%, мы сравниваем SLI с константой.

PROMQL
# Возвращает 1, если SLO соблюдается, 0, если нарушен
(sum(rate(http_requests_total{status!~"5.."}[7d])) / sum(rate(http_requests_total[7d]))) >= 0.999

Alerting: Burn Rate (Скорость сжигания бюджета)

Стандартный алерт rate(errors) > X плох тем, что он шумный. Методология SLO предлагает использовать Burn Rate (Скорость сжигания бюджета ошибок).

Burn Rate = 1 означает, что вы тратите бюджет ошибок ровно с той скоростью, при которой он иссякнет ровно к концу отчетного периода (за 30 дней).
Burn Rate = 14.4 означает, что 100% месячного бюджета сгорит всего за 2 дня (5% бюджета сгорает за 1 час).

Мы создаем алерты, которые срабатывают, если мы тратим бюджет слишком быстро. Если бюджет на месяц — 43 минуты, то потратить его за 1 час — это катастрофа, а потратить за 29 дней — это норма.

Для этого используется библиотека slo-libsonnet в Jsonnet или готовые рекурсии в Grafana, но принцип один: сравниваем короткое окно (fast burn) с длинным (slow burn).

Если быстрый burn rate подтверждается длинным окном — мы будим дежурного инженера среди ночи (Page alert). Если burn rate низкий — заводим тикет на утро (Ticket alert).


Mechanical Sympathy: Точность измерений

При измерении Latency как SLI важно помнить о природе времени в Go.
Использование time.Since(start) включает:

  1. Время выполнения бизнес-логики.
  2. Время работы GC (Garbage Collector).
  3. Время на планирование (если горутина долго ждала процессор).

Если вы используете Histogram в Prometheus, вы получаете агрегированные данные. Но выбор бакетов (Buckets) критичен.

  • Если ваш SLO — 100мс, у вас обязан быть бакет 0.1.
  • Если бакетов нет рядом с SLO, вы не сможете точно посчитать, сколько запросов попало в норму.

Вспомним, как Prometheus выполняет функцию histogram_quantile: внутри корзины он делает линейную интерполяцию. Если у вас есть корзины 0.05 и 0.5, а порог SLO равен 0.2, Prometheus предположит равномерное распределение между 50 мс и 500 мс, что приведет к чудовищной математической погрешности!

Go
// Правильный выбор бакетов под SLO 200ms
Buckets: []float64{.01, .05, .1, .2, .5, 1} // Бакет .2 (200ms) критически важен

Четкое попадание границы корзины в целевой порог SLO позволяет вычислять SLI задержки простой арифметической операцией без вызова тяжелой интерполяции:
$$\text{Latency SLI} = \frac{\text{rate}(http\_request\_duration\_seconds\_bucket\{le="0.2"\}[5m])}{\text{rate}(http\_request\_duration\_seconds\_count[5m])}$$


Итог

  1. SLI — это измерение (метрика).
  2. SLO — это цель (бизнес-требование).
  3. SLA — это последствия (контракт).
  4. Error Budget — это инструмент балансировки между скоростью разработки и стабильностью.

Переход от «мониторинга железа» (CPU/RAM) к «мониторингу пользовательского опыта» (SLI/SLO) — это маркер зрелости Senior-инженера.

Раздел метрик завершен. Мы переходим к следующему столпу Observability — Логированию. В следующей статье мы разберем, почему современные системы требуют структурированного подхода: 1. Structured logging.