Проблема появляется, когда в релизном обсуждении говорят: «мы потратили бюджет», но никто не может показать, из какого окна, знаменателя и цели получилась фраза. Два отчёта могут дать разные проценты из одних и тех же событий, если один начал считать после смены версии, а второй оставил в знаменателе отмены до запроса. Цена — не математическая придирка. Команда способна заморозить полезное изменение по шумному сигналу или, наоборот, продолжить рискованный rollout, потому что неудобные события тихо исчезли из формулы.
Вторая ловушка — копировать target как число с девятками и считать, что появился error budget. Бюджет — это допустимая доля неуспеха в конкретной модели, а не универсальный счётчик проблем. Без scope и policy он становится красной полосой, которой каждый объясняет своё решение задним числом. Цена — у команды нет общей точки остановки: инженер приносит график, продукт говорит о сроке, а владелец сервиса не может назвать, какое действие разрешено именно при этом состоянии.
Механизм состоит из пяти связанных частей
У простого success-ratio договора есть eligible count, good count, target, window и правило реакции. Сначала считают долю good среди eligible. Затем target определяет допустимую долю bad в том же окне. Разница между допустимым и фактическим числом bad — остаток учебного бюджета. Если поменять хотя бы одну часть, получится другая величина. Поэтому нельзя взять число ошибок за день и назвать его расходом четырёхнедельного бюджета без явного правила агрегации.
В коде этой партии target равен 99, synthetic eligible count — 1000, synthetic good count — 994. Из этого следуют шесть synthetic bad и десять допустимых synthetic bad, то есть остаток четыре условные единицы. Это именно проверяемая арифметика модели, а не расчёт для услуги: в коде нет источника событий, часов, реального окна, monitoring или backend. Слово `synthetic` повторяется намеренно, чтобы понятная формула не превратилась в несуществующий отчёт о доступности.
| Элемент | Вопрос | Если он не назван | Что проверять до решения |
|---|---|---|---|
| Scope | какой путь пользователя оцениваем? | в одну цифру попадают разные операции | маршрут, версию и границу владельца |
| Eligible | какие попытки имеют право попасть в знаменатель? | часть ошибок или отмен исчезает неявно | источник, фильтр и отрицательные примеры |
| Good | какой исход считается допустимым? | HTTP-код или технический ответ подменяет смысл результата | связь статуса с пользовательским действием |
| Window | за какой период сравниваем? | один всплеск и долгий тренд смешиваются | rolling/fixed правило, reset и низкий трафик |
| Policy | кто и что делает при состоянии бюджета? | цвет графика выдают за автоматический gate | owner, evidence, исключения и обратимое действие |
Окно — это граница сравнения, а не подпись оси
Окно отвечает на вопрос «какие события имеют право повлиять на это решение сейчас». В Example SLO Document Google показано rolling window в четыре недели; этот документ датирован 19 февраля 2018 года. Это не доказывает, что четыре недели подходят всем. Для малотрафикового пути один failure может резко изменить процент, а для потоковой задачи важнее задержка завершения. Google SRE Workbook отдельно предупреждает, что подходы alerting для высокотрафиковых сервисов дают ложный сигнал на low traffic. Значит, размер окна и способ действия надо выбрать вместе с характером события, а не после того, как график уже настроен.
Нужно также решить, что происходит на границе окна. Fixed window проще объяснить: все события относятся к явно названному периоду, затем начинается следующий. Rolling window быстрее показывает недавнее ухудшение, но требует точного описания того, как момент измерения сдвигает набор событий. Нельзя менять режим в середине отчёта без новой версии договора: сравнение с прошлым значением потеряет смысл. В fixture выбран fixed 28-day object только потому, что его отрицательную ветку легко проверить; он ничего не говорит о реальном календаре.
Знаменатель не должен прятаться в query
Есть соблазн исключить неудобные ответы, чтобы сделать ratio спокойнее. Исключение может быть законным, например событие не дошло до измеряемой операции, но его надо объяснить на языке пользователя и фиксировать в контракте. «Не успели отправить запрос» и «операция завершилась ошибкой на сервере» — разные состояния. Их нельзя склеить под общим названием «шум». Хороший SLI не обязан учитывать всё; он обязан честно говорить, что именно не учитывает и какой другой сигнал требуется для этой слепой зоны.
Арифметика не заменяет policy
Google SRE Book 2017 связывает error budget с решением о риске, а Example Error Budget Policy 2018 прямо описывает policy как способ защитить пользователя, а не наказать команду. Из этого следует практический вывод: после расчёта должна появиться не автоматическая команда, а заранее согласованная развилка. Например, владелец может назначить review, сузить rollout или запланировать reliability work. Какое действие верно, зависит от продукта, класса изменения, обратимости, security-исключений и качества evidence. Ни один процент сам по себе не знает этих условий.
В учебной модели `proposal` имеет только два значения: `synthetic-review-before-change` и `synthetic-reliability-work-first`. Рядом стоит `releaseAuthority=not-granted`. Это намеренно ограничивает fixture: он показывает, что состояние арифметики может привести к вопросу владельцу, но не даёт право останавливать CI, менять feature flag или выполнять rollout. Такой запрет полезен в коде примера, потому что в реальной системе именно место принятия решения и права на действие чаще всего оказываются неявными.
Исполнимый fixture ловит плохую границу раньше графика
Ниже один и тот же fixture. Он проверяет не PromQL, не правила alerting и не production telemetry, а форму входа. Хорошая ветка содержит ровно один synthetic scope, фиксированное 28-day окно, explicit good/eligible event, target меньше 100 и целые счётные значения. Плохие ветки пытаются подменить окно 30 днями, размыть eligible event, записать невозможную цель, передать нулевой знаменатель или сделать good count больше eligible. Эти ошибки должны быть заметны ещё в review, а не после публикации красивого отчёта.
import { runSloFixture } from './upgrade-2023-10.mjs';
const report = runSloFixture();
if (!Object.values(report.assertions).every(Boolean)) throw new Error('fixture failed');
console.log(report.samples.valid.decision.releaseAuthority); // not-granted
console.log(report.samples.valid.calculation.observed); // not-observed
// Полный synthetic вход и отрицательные ветки находятся в этом же модуле.
// Нет чтения проекта, monitoring, CI, сети, real SLI, incident, burn rate или availability.
node web/scripts/upgrade-2023-10.mjs --verify-fixture
# PASS подтверждает только согласованность synthetic договора и его отрицательных веток.
При запуске код не использует дату, файл, environment, monitoring API, CI, HTTP или сеть. У него нет clock и нет таблицы реальных точек. Даже строка `syntheticBudgetSpentShare=0.6` не является burn rate: она лишь результат деления шести fixed synthetic bad на десять synthetic допустимых bad внутри одного объекта. PASS не подтверждает, что система выдерживает цель, что произошёл incident или что изменение безопасно выпускать.
Маршрут: симптом → причина → проверка → действие
- Симптом. В обсуждении звучит «бюджет потрачен», но для числа нельзя назвать scope, окно, eligible count и target.
- Причина. Процент, период и policy живут в разных запросах, документах или головах участников; одинаковое слово обозначает разные формулы.
- Проверка модели. Выпишите пять частей из таблицы. На synthetic примере пересчитайте good, eligible, bad и допустимое число bad; отдельно отметьте события вне scope.
- Проверка данных. В разрешённой среде подтвердите, что источник предоставляет именно те поля и границы, которые обещает договор. Не подменяйте это прогоном fixture.
- Действие. Версионируйте договор и policy вместе: изменение фильтра, окна или target — это новое правило сравнения, а не косметика дашборда.
- Следующий контроль. Перед спорным релизом попросите owner показать входные определения и evidence, затем выбрать обратимый шаг. Если evidence нет, статус — «решение отложено», а не «бюджет зелёный».
Изменение формулы требует своего rollback
Ограничения и следующий шаг
Этот текст не вычисляет настоящий error budget, real SLI, availability, burn rate, incident, traffic, alert или SLO compliance. Fixture не читает проект, не использует monitoring/CI/сеть/HTTP/SDK и не открывает production-данные. Он не устанавливает цель 99 для чьей-либо услуги, не утверждает, что 28 дней универсальны, и не создаёт release gate. Источники доступны до конца октября 2023, но их примеры не заменяют договор команды и не дают готовую формулу для неизвестного продукта.
Следующий шаг — взять одну существующую метрику и провести обратный путь: от цвета панели к точному user journey, eligible set, good outcome, window и policy. Если хотя бы один пункт невозможно восстановить, метрика пока diagnostic, а не основа для error budget. После этого можно сравнить fixed и rolling варианты на известном наборе данных в разрешённой среде и зафиксировать, какой вопрос каждый вариант отвечает. Выбирать можно не самый красивый процент, а самый проверяемый договор.
Историческая граница октября 2023
Все источники в статье существовали к концу октября 2023: Google SRE Book имеет copyright 2017, а SRE Workbook и его Example SLO Document, Error Budget Policy и Alerting on SLOs — copyright или даты 2018 года. Поэтому материал не приписывает автору позднюю платформу и не ссылается на более новые методы как на обязательный стандарт. Уровень M6 здесь проявляется в границе модели, версии правила и обратимом решении, а не в лозунге о «культуре SRE».
Проверяемые источники
- Google SRE Book: Service Level Objectives, copyright 2017 — Первичный материал Google SRE: определяет SLI как количественную меру, SLO как целевое значение или диапазон и связывает error budget с решением о риске. Он не задаёт порог, окно, формулу или владельца для конкретного проекта.
- Google SRE Workbook: Example SLO Document, 19.02.2018 — Официальный пример документа с датой 19.02.2018: в нём есть scope, SLI, SLO и четырёхнедельное rolling window. Это пример формы, а не обязательное окно для любого сервиса.
- Google SRE Workbook: Example Error Budget Policy, 19.02.2018 — Официальный пример policy: расход бюджета служит правилом приоритизации и не должен быть наказанием. Он не разрешает автоматически блокировать или выпускать чужие изменения.
- Google SRE Workbook: Alerting on SLOs, copyright 2018 — Официальная глава о том, что alert должен относиться к действенной угрозе бюджету; отдельно разбираются ограничения low-traffic систем. Она не подтверждает реальный burn rate, alert или incident этого учебного пакета.