SLO и бюджет ошибок: как измерить надёжность

SLO и бюджет ошибок: как измерить надёжность

Логи, метрики и трейсы отвечают на вопрос «что происходит». Остаётся вопрос, на который они сами не отвечают: достаточно ли хорошо работает сервис.

Без числа этот спор бесконечен. Продукт говорит «пользователи жалуются», разработка говорит «у нас всё зелёное», и оба правы, потому что меряют разное. SLO превращает надёжность в договорённость с конкретной цифрой - и, что важнее, даёт объективное правило, когда останавливать релизы.

SLI / SLO / SLA - основа измерений

Пирамида SLI, SLO, SLA: чем выше уровень, тем строже цель и тем меньше места для ошибки

  • SLI (Service Level Indicator) - конкретная метрика. «Доля запросов, обработанных быстрее 200ms».
  • SLO (Service Level Objective) - внутренняя цель. «99.9% запросов за 200ms».
  • SLA (Service Level Agreement) - договорное обязательство перед клиентом, обычно мягче SLO. «99.5%».
SLI: rate(http_requests_total{le="0.2"}) / rate(http_requests_total)
     текущее значение: 99.2%

SLO: 99.9%
Бюджет ошибок (error budget): 100% - 99.9% = 0.1%
                             = 43 минуты простоя в месяц

Концепция error budget от Google SRE: если бюджет не исчерпан, можно деплоить новые фичи; если исчерпан - фокус на надёжности. Это объективный механизм торможения релизов без drama.

Почему 100% - неправильная цель

Соблазн поставить SLO 100% и «просто не падать» проходит после первой попытки это посчитать. Каждая девятка стоит примерно на порядок дороже предыдущей:

SLOДопустимый простой в месяцЧто для этого нужно
99%7 часов 18 минутодин сервер, дежурство в рабочие часы
99.9%43 минутырезервирование, автоматический откат, дежурство 24/7
99.99%4 минуты 20 секунднесколько зон доступности, автоматическое переключение
99.999%26 секундчеловек физически не успевает вмешаться

На последней строке дежурный уже не помогает: пока он читает уведомление, бюджет месяца исчерпан. Всё должно чиниться само, а это другой порядок сложности и стоимости системы.

Отсюда практическое правило: SLO выбирают чуть выше того, что пользователь замечает, и чуть ниже того, что вы можете обеспечить без героизма. Если пользователи не жалуются при 99.5%, ставить 99.99% - значит тратить кварталы инженерного времени на то, чего никто не заметит.

Цель надёжности - продуктовое решение, а не техническое. Инженер может сказать, сколько будет стоить каждая девятка; решать, стоит ли она того, должен тот, кто отвечает за продукт. Иначе SLO превращается в число, которое никто не готов защищать, когда оно потребует отменить релиз.

SLO в коде

Концепция «error budget burn rate» - насколько быстро мы тратим бюджет ошибок. Алерт на быстрый burn срабатывает, когда за 1 час потрачено 2% месячного бюджета - это тревожный сигнал ещё до полного исчерпания.

# 1h burn rate = errors_per_hour / monthly_budget
1h_error_rate / (1 - 0.999)

Error budget policy: что происходит, когда бюджет кончился

Бюджет ошибок бесполезен, пока заранее не записано, что делать при его исчерпании. Иначе разговор каждый раз начинается с нуля и заканчивается тем, что релиз всё-таки выкатывают.

Работающая политика выглядит примерно так:

  • бюджет израсходован меньше чем на половину - выкатываем как обычно;
  • израсходовано больше половины - рискованные изменения едут с флагом функциональности и планом отката, миграции схемы - только в тихое время;
  • бюджет исчерпан - заморозка новых функций, вся команда работает над надёжностью, пока бюджет не восстановится в следующем периоде;
  • бюджет исчерпан второй период подряд - это уже не инцидент, а системная проблема: пересматриваем либо архитектуру, либо сам SLO.

Ключевое здесь - что правило записано до инцидента и одинаково для всех. Тогда заморозка релизов перестаёт быть чьим-то волевым решением и становится следствием цифры, с которой все согласились заранее.

Multi-window multi-burn-rate alerts

Простой алерт «error rate > 1% за 5 минут» имеет проблемы: на маленьком RPS вы либо ловите false positives при единичных ошибках, либо пропускаете медленное сжигание SLO. Google SRE Workbook предлагает решение - алерты по нескольким окнам с разными burn rate.

Burn rate - насколько быстрее, чем заложено в SLO, тратится бюджет ошибок. Если SLO 99.9%, бюджет 0.1%. Текущий error rate 0.5% = burn rate 5× (тратим бюджет в 5 раз быстрее, исчерпаем за 30/5 = 6 дней вместо 30).

groups:
  - name: slo-burn-rate
    rules:
      # Быстрое сжигание: пейджер
  - alert: ErrorBudgetBurnFast
    expr: |
      (
        job:error_rate:ratio5m{job="api"} > (14.4 * 0.001)
        and
        job:error_rate:ratio1h{job="api"} > (14.4 * 0.001)
      )
    for: 2m
    labels: {severity: critical}
    annotations:
      summary: "SLO budget burns at 14.4× rate (1h window)"

      # Медленное сжигание: тикет
  - alert: ErrorBudgetBurnSlow
    expr: |
      (
        job:error_rate:ratio30m{job="api"} > (6 * 0.001)
        and
        job:error_rate:ratio6h{job="api"} > (6 * 0.001)
      )
    for: 15m
    labels: {severity: warning}
    annotations:
      summary: "SLO budget burns at 6× rate (6h window)"

Конкретные коэффициенты из SRE Workbook: 14.4× за 1h (page) - означает «при таком burn 2% бюджета будет потрачено за 1 час»; 6× за 6h (ticket) - «5% за 6 часов». Условие AND с коротким окном фильтрует point-in-time всплески: если за 5 минут плохо, но за 1 час всё ОК - это, скорее всего, шум.

Как выбрать SLI, который что-то значит

Метрика для SLI должна отражать опыт пользователя, а не удобство измерения. Загрузка процессора - плохой SLI: пользователю всё равно, сколько у вас CPU, пока страницы открываются. Доля успешных ответов быстрее порога - хороший: именно это человек и чувствует.

Три вопроса, которые отсеивают неподходящие метрики:

  1. Заметит ли пользователь ухудшение этой метрики? Если нет, это метрика для диагностики, а не для SLO. Ей место на дашборде, а не в цели.
  2. Можно ли на неё повлиять? SLI, зависящий целиком от внешнего сервиса, превращает бюджет ошибок в лотерею: команда тратит его на чужие сбои и ничего не может сделать.
  3. Однозначно ли считается граница? «Быстро» надо перевести в число. Порог обычно берут из наблюдений: смотрят, при какой задержке пользователи начинают уходить или жаловаться, и ставят SLO чуть строже.

Для типичного HTTP-сервиса рабочий набор - два SLI: доступность (доля ответов не-5xx) и задержка (доля ответов быстрее порога). Добавлять третий стоит только тогда, когда есть отдельный сценарий, который эти два не покрывают, - например, свежесть данных для отчёта, который строится асинхронно.

«99.9% времени сервис был доступен» и «99.9% запросов были успешными» - разные числа. Пятиминутный сбой в три часа ночи почти не тронет второй показатель и заметно испортит первый; сбой в час пик - наоборот. Пользователь приходит с запросом, а не с секундомером, поэтому SLI обычно считают по запросам.

Итоги

  • ✅ Различать SLI (что меряем), SLO (наша цель) и SLA (обещание клиенту)
  • ✅ Считать бюджет ошибок и понимать, сколько минут он даёт
  • ✅ Выбирать реалистичный SLO, а не максимальный
  • ✅ Настраивать алерты по скорости сжигания бюджета, а не по мгновенному проценту ошибок

Мини-практика

Возьми любой свой HTTP-сервис и сформулируй для него один SLI и один SLO. Посчитай бюджет ошибок в минутах на месяц. Затем напиши recording rule для этого SLI и два алерта по burn rate - быстрый и медленный, по образцу из этого урока.

Дальше - алерты, дежурство и разбор инцидентов.

Зарегистрируйтесь бесплатно, чтобы пройти квиз, вести прогресс.