С чего начать Первые шаги трек · 15 ступеней
Linux Labs

SLI и SLO — доля хороших запросов и бюджет ошибок

12 мин Ubuntu 24.04 · nginx 1.24 · GNU awk 5.2

SLI — измеренная доля хороших запросов за окно времени, SLO — цель для неё; разница между целью и 100 % — бюджет ошибок.

Шпаргалка

6 команд Версия для печати
  • combined + $request_time $msec: код $9, время $(NF-1), unix-время $NF
  • строки за последний час
  • awk -v f="$(date -d '1 hour ago' +%s)" '$NF >= f' access.log > w.log
  • SLI доступности: доля ответов без 5xx
  • awk '$9 >= 500 {b++} END {printf "%.2f\n", 100*(NR-b)/NR}' w.log
  • p95 времени ответа: ближайший ранг ⌈0,95 × N⌉
  • awk '{print $(NF-1)}' w.log | sort -n > /tmp/t
  • k=$(( ($(wc -l < /tmp/t) * 95 + 99) / 100 )); sed -n "${k}p" /tmp/t
  • бюджет ошибок: SLO 99,5 % при 400000 запросов за окно
  • awk 'BEGIN {print 400000 * (1 - 0.995)}' 2000 плохих можно
  • скорость расхода: 7 % ошибок при SLO 99,5 %
  • awk 'BEGIN {print 0.07 / (1 - 0.995)}' 14

Обзор

ping проходит, curl / отвечает 200, а пользователи видят ошибки: часть запросов падает или идёт секундами. Проверка «жив ли сервер» этого не видит. Видит журнал запросов, если сосчитать, сколько запросов прошло хорошо и как быстро.

SLI (service level indicator, показатель уровня обслуживания) — измеренная доля хороших событий: хороших ответов из всех, быстрых ответов из всех. SLO (service level objective, цель уровня обслуживания) — какой SLI считается нормой за окно времени: «99,5 % ответов без 5xx за 30 дней». Разница между целью и 100 % — бюджет ошибок: сколько плохих запросов цель ещё допускает.

SLI: доля хороших запросов

SLI = хорошие ÷ все. Что считать хорошим, решают заранее по тому, что видит пользователь, и записывают рядом с SLO:

Ответ Для SLI доступности
2xx, 3xx хороший
4xx обычно хороший: ошибся клиент, сервис ответил верно
5xx плохой: не справился сервер
499 в nginx клиент закрыл соединение, не дождавшись ответа

Код 499 пишет только nginx. Если клиенты уходят из-за медленного сервера, 499 — тоже плохой ответ; если это обрывы сети у клиентов — его не считают вовсе.

Два частых SLI:

  • доступность — доля ответов без 5xx;
  • задержка — доля ответов быстрее порога («быстрее 300 мс») или перцентиль времени ответа («p95 не больше 1 с», ниже).

Считают по журналу того, кто стоит первым на пути запроса: nginx или балансировщика перед приложением. Он видит и те запросы, до которых приложение не дошло: 502 и 504 — ответы самого nginx, в журнале приложения их нет (nginx).

Окно времени

SLI всегда считают за период: час, сутки, 30 дней. Сто ошибок — это 7 % за час, в котором было 1400 запросов, и 0,01 % за месяц с тем же потоком. Окно задают двумя метками времени: начало включительно, конец нет. Тогда соседние окна не считают одну строку дважды.

Время в формате combined — $time_local вида [22/Oct/2026:10:03:58 +0000]: месяц словом, такие метки как текст не сравнить. Для окна в конец строки журнала добавляют $msec — секунды unix-времени с миллисекундами, число:

text
… "GET /api HTTP/1.1" 500 21 "-" "curl/8.5.0" 0.004 1792677901.123

Здесь 0.004 — $request_time, время ответа в секундах, а 1792677901.123 — $msec. Номера полей awk считают от конца строки, $(NF-1) и $NF: user-agent с пробелами сдвигает номера от начала. Как задать такой формат — nginx. Окно — сравнение числом: $NF >= начало && $NF < конец, а начало и конец даёт date -d '…' +%s.

Перцентиль: p50, p95, p99

Среднее время ответа прячет хвост. 95 ответов по 0,05 с и 5 ответов по 10 с дают в среднем 0,55 с, хотя каждый двадцатый ждал 10 секунд.

Перцентиль p95 — время, за которое уложились 95 % ответов. p50 — медиана, p99 — граница худшего процента. Считают так: времена сортируют по возрастанию и берут значение с номером ⌈0,95 × N⌉, округлённым вверх (метод ближайшего ранга). Из 100 значений это 95-е, из 1400 — 1330-е, из 7 — 7-е.

Другие программы считают с интерполяцией между соседними значениями: так делает histogram_quantile в promql. На малой выборке результаты расходятся, поэтому метод записывают вместе с SLO.

SLO и SLA

SLO — цель для SLI за окно: «99,5 % ответов без 5xx за 30 дней», «95 % ответов быстрее 1 с за сутки». Цель ставят ниже 100 %: каждая выкладка, перезапуск и сбой сети тратят её часть.

SLA (service level agreement) — договор с клиентом, где за нарушение есть последствия: возврат денег, штраф. В SLA ставят цифру мягче своего SLO, чтобы команда узнала о проблеме до нарушения договора.

Сколько простоя допускает цель:

SLO За 30 дней За сутки
99 % 7 ч 12 мин 14 мин 24 с
99,5 % 3 ч 36 мин 7 мин 12 с
99,9 % 43 мин 12 с 1 мин 26 с
99,95 % 21 мин 36 с 43 с
99,99 % 4 мин 19 с 9 с

Минуты простоя — упрощение: оно верно, если в сбой падают все запросы, а нагрузка ровная. По журналу бюджет считают в запросах.

Бюджет ошибок

text
допустимо = (1 − SLO) × всего запросов за окно
потрачено = плохих запросов за окно
осталось  = допустимо − потрачено   (в % — осталось ÷ допустимо)

При SLO 99,5 % и 400 000 запросах за 30 дней можно 2000 плохих. Вчерашний сбой дал 1400 ответов 5xx: потрачено 70 %, осталось 600 запросов, 30 % бюджета. Сколько запросов придёт до конца окна, ещё неизвестно: берут ожидаемое число по прошлым окнам или сравнивают доли — долю плохих за окно с 1 − SLO.

Бюджет — правило для решений. Остался — можно выкатывать и рисковать. Кончился — рискованные изменения ждут, команда чинит то, что его тратит. Правило записывают заранее (политика бюджета ошибок), во время сбоя его не обсуждают.

Скорость расхода

Скорость расхода (burn rate) — во сколько раз доля плохих запросов больше допустимой: доля плохих за последнее окно ÷ (1 − SLO).

  • 1 — бюджет кончится ровно к концу 30 дней;
  • 2 — за 15 дней;
  • 14 — сбой с 7 % ошибок при SLO 99,5 % (0,07 ÷ 0,005): бюджет 30 дней уйдёт за два дня, час сбоя съедает 2 % бюджета.

На скорость расхода ставят алерты. Быстрый — скорость выше 14,4 за последний час: за час ушло 2 % бюджета, нужен дежурный. Медленный — выше 6 за 6 часов: ушло 5 %, задача на рабочий день. Как пишут правило — prometheus, доля 5xx на PromQL — promql.

Рецепты

4

Строки за окно времени

Журнал с $msec в конце строки:

bash
f=$(date -d '2026-10-22 10:00' +%s)
t=$(date -d '2026-10-22 11:00' +%s)
awk -v f="$f" -v t="$t" '$NF >= f && $NF < t' access.log > w.log
head -n 1 w.log; tail -n 1 w.log     # границы попали в окно?

Повёрнутые части читаются вместе с текущей: zcat -f access.log.2.gz access.log.1 access.log | awk … (-f пропускает несжатые файлы как есть). Окно задают в том же поясе, что пишет журнал; на учебной машине это UTC (+0000).

Без $msec, в чистом combined, время переводит в число mktime (в Ubuntu 24.04 awk — это GNU awk):

bash
awk -v f="$f" -v t="$t" '
  { split($4, d, /[[\/:]/)
    m = (index("JanFebMarAprMayJunJulAugSepOctNovDec", d[3]) + 2) / 3
    s = mktime(d[4] " " m " " d[2] " " d[5] " " d[6] " " d[7])
    if (s >= f && s < t) print }' access.log > w.log

Доступность по журналу

bash
awk '$9 >= 500 {b++}
  END {printf "%d %d %.2f\n", NR, b, 100*(NR-b)/NR}' w.log

Печатает число запросов окна, число ответов 5xx и доступность в процентах с двумя знаками. Код ответа в combined — 9-е поле. Проверка поля — awk '{print $9}' w.log | sort | uniq -c: там только коды.

p95 по $request_time

bash
awk '{print $(NF-1)}' w.log | sort -n > /tmp/t
n=$(wc -l < /tmp/t)
k=$(( (n * 95 + 99) / 100 ))      # ⌈0,95 × n⌉ в целых числах
sed -n "${k}p" /tmp/t

sort -n обязателен: без него строка 10.002 встанет раньше 2.001 (sort). Пустое окно даёт n=0 и пустой ответ. Доля быстрых ответов — тем же полем: awk '$(NF-1) <= 0.3 {f++} END {print f/NR}' w.log.

Сколько бюджета осталось

bash
awk -v slo=0.995 -v total=400000 -v bad=1400 'BEGIN {
  ok = total * (1 - slo); left = ok - bad
  printf "можно %d, осталось %d (%.0f%%)\n", ok, left, 100*left/ok }'

bad — ответы 5xx за окно из рецепта доступности, total — все запросы окна или их ожидаемое число.

Неполадки

4

SLI высокий, а пользователи жалуются

  • Запросы не дошли до nginx: DNS, сеть, сертификат. Журнал их не видит — нужна проба снаружи, curl с другой машины.
  • Приложение отвечает 200 со страницей ошибки. Такой ответ SLI считает хорошим: проверяй тело или отдельный путь проверки.
  • Ответы медленные: доступность в порядке, страдает задержка. Нужен SLI задержки.
  • Сбой не попал в окно: часть строк уже в access.log.1 после ночной ротации (logrotate).

p95 не совпадает с другим подсчётом

  • сортировка без -n — порядок строк вместо порядка чисел;
  • другой метод: интерполяция вместо ближайшего ранга;
  • граница окна включена с обеих сторон, и строка ровно в конце окна посчитана;
  • в поле времени не число: $upstream_response_time пишет - у ответов, которые nginx отдал сам, и 0.000, 0.002 через запятую, если nginx повторил запрос на другом сервере (nginx).

Окно пустое

head -n 1 и tail -n 1 журнала покажут, какой период в нём есть. Частые причины: окно в другом поясе, чем время журнала; время combined сравнивается как текст, а месяц там словом ($4 ломается на стыке месяцев); журнал уже повёрнут, нужные строки в access.log.1 или .2.gz.

В 9-м поле не код

awk '{print $9}' | sort | uniq -c показывает "GET, размеры или слова — в строке запроса пробелы или мусор от сканеров ("-", двоичные байты). Код надёжнее брать по кавычкам: первое слово после строки запроса.

bash
awk -F'"' '{split($3, f, " "); if (f[1] >= 500) b++}
  END {printf "%d %d\n", NR, b}' w.log

Опасно

1

SLO 100 %

Цель 100 % не оставляет бюджета. Любой перезапуск, выкладка или сбой сети её нарушают, и по правилу бюджета изменения запрещены всегда. Цель выше, чем у того, от чего сервис зависит (сеть, хостинг, база), тоже недостижима.

Термины

6
SLI (показатель уровня обслуживания) SLI (service level indicator)
Измеренная доля хороших событий за окно времени: ответов без 5xx из всех, ответов быстрее порога из всех. Считается по журналу запросов или по метрикам. Ещё встречается в: nginx, Постмортем, Инцидент, Балансировка нагрузки и ещё 2
SLO (цель уровня обслуживания) SLO (service level objective)
Цель для SLI за окно времени: «99,5 % ответов без 5xx за 30 дней». Ставится ниже 100 %, разница с 100 % — бюджет ошибок. Ещё встречается в: Постмортем, Инцидент, nginx, Балансировка нагрузки и ещё 2
SLA (соглашение об уровне обслуживания) SLA (service level agreement)
Договор с клиентом об уровне сервиса, где за нарушение есть последствия: возврат денег, штраф. Цифру в нём ставят мягче своего SLO.
бюджет ошибок (error budget)
Сколько плохих запросов допускает SLO за окно: (1 − SLO) × все запросы. Остался — можно выкатывать, кончился — рискованные изменения ждут. Ещё встречается в: Постмортем, Инцидент
скорость расхода бюджета (burn rate)
Во сколько раз доля плохих запросов больше допустимой: доля ошибок ÷ (1 − SLO). При 1 бюджет кончится к концу окна, при 14 — в 14 раз быстрее. Ещё встречается в: Инцидент
перцентиль (p95) percentile (p95)
Значение, в которое уложилась заданная доля наблюдений: p95 времени ответа — время, за которое ответили 95 % запросов. Хвост медленных ответов виден в p95 и p99, среднее его прячет. Ещё встречается в: sort, nginx, sed и awk

См. также

  • nginx — access.log, log_format и $request_time.
  • sed-awk — поля и подсчёт в awk.
  • sort — числовая сортировка -n.
  • date — метки времени и unix-время.
  • promql — доля 5xx по метрикам Prometheus.
  • prometheus — правило алерта на скорость расхода.
  • http — классы кодов ответа.
  • logrotate — где строки журнала после ротации.
Загрузка…