🖥️ ИТ-эксплуатация — надёжность сервисов (SRE) Живая модель
Вы дежурите по веб-сервису: балансировщик нагрузки перед парком экземпляров, кэш перед базой данных и цель по доступности 99,9 %. Каждую минуту модель считает задержку в очереди, тайм-ауты, попадания в кэш и нагрузку на базу по учебникам — и во что обходятся ваши решения.
Чему вы научитесь
Почему задержка взрывается около полной загрузки (Erlang C) и почему автомасштабирование с задержкой загрузки всегда опаздывает.
Как SLO, бюджеты ошибок и оповещения по скорости расходования решают, когда откатываться.
Как холодный кэш превращается в отказ базы данных и какие рычаги выигрывают время: сброс трафика, деградация, прогрев.
Симулятор
Время 0 мин
▶Экземпляр обслуживает
⚙Экземпляр загружается
!Экземпляр на плохой сборке
·Свободное место
•Входящие запросы
Управление
Нижняя граница парка. Её повышение сразу запускает экземпляры — но им всё равно нужна задержка загрузки, прежде чем обслуживать.
Отслеживание целевой загрузки; новое наращивание не запускается, пока экземпляры ещё загружаются. Выкл. = ровно минимум.
Ниже = больше запаса и больше затрат. Измеренная загрузка не может превышать 100 %, поэтому насыщенный парк растёт лишь шаг за шагом.
Больше TTL = больше попаданий, но ответы могут быть старее (средний возраст ≈ TTL/2).
Загружает горячие ключи 6 минут (+12 % кэша в минуту) ценой 600 дополнительных запросов к базе данных в секунду.
Доля низкоприоритетных 30 % (предзагрузка, пакетные задачи, краулеры), отклоняемая на балансировщике нагрузки с ответом «повторите позже».
Тяжёлая функция добавляет 20 мс CPU и один запрос к базе данных на каждый запрос. Выкл. = плавная деградация.
Повторно развёртывает последнюю рабочую сборку на новом парке (5 мин, оплачивается дважды), затем переключает трафик. Повторное нажатие перезапускает подготовку; если плохой сборки в работе нет, это только тратит деньги.
Показатели
Доля ошибок
0,00%
норма
Задержка p99
342ms
норма
Остаток бюджета ошибок (30 дней)
50,0%
норма
Загрузка парка
52%
норма
Скорость расходования (1 ч)
0,0 ×
Запросы
1125 req/s
Экземпляры в работе
10
Экземпляры загружаются
0
Доля попаданий в кэш
77 %
Загрузка базы данных
19 %
Сброшенный трафик
0 %
Стоимость парка
4,00 $/h
Затраты на данный момент
0,00 $
Средний возраст ответов в кэше
30 s
Трафик на плохой сборке
0 %
Рекомендации доступны
100 %
Динамика
Кризисные сценарии
Уровень 1 · Неудачный релиз
В 09:10 выкатывается новая сборка. Месяц и так выдался тяжёлым: остаётся только 20 % бюджета ошибок. Через несколько минут после деплоя срабатывает оповещение о скорости расходования. Защитите бюджет.
Остаток бюджета ошибок в конце ≥ 18,5 %
Средняя доля ошибок ≤ 0,65 % после деплоя
Стоимость парка ≤ 9,50 $
Уровень 2 · Внезапный наплыв посетителей
Ссылка на сервис быстро распространяется, и сегодня утром ожидается всплеск трафика — никто не знает, когда именно и насколько большой. Новые экземпляры сейчас запускаются 8 минут. Когда он придёт, удерживайте низкий уровень ошибок и задержки, не тратя деньги на простаивающую мощность.
Средняя доля ошибок ≤ 0,2 %
Средняя задержка p99 ≤ 400 мс
Средний сброшенный трафик ≤ 5 %
Общие затраты ≤ 21 $
Рекомендации доступны ≥ 85 % времени
Уровень 3 · Холодный кэш
На дневном пике скрипт обслуживания сбрасывает весь кэш. Теперь каждый запрос идёт в базу данных, рассчитанную на обычную долю попаданий 85 %. Верните сервис, не перегрузив базу данных.
Средняя доля ошибок ≤ 1,5 %
Загрузка базы данных ни разу не выше 90 % после первой минуты
Средний возраст ответов в кэше ≤ 90 с в среднем
Общие затраты ≤ 9 $
Рекомендации доступны ≥ 80 % времени
Средний сброшенный трафик ≤ 5 %
Основа — модель, стоящая за числами
Все зависимости, которые использует симулятор, с источниками. Константы, помеченные как допущения, — иллюстративные калибровки.
Запросы следуют суточной кривой плюс возмущения; число за минуту случайно (Пуассон, нормальное приближение) с небольшой пачечностью.
λ(t) = base × (1 + 0.25·sin(2π(t + clock − 6 h)/24 h)) × surge(t), clock = time of day at the start (peak at 12:00); count/min ≈ N(60λ, √(60λ)) × (1 + N(0, 0.02))[6]Допущение: число воркеров, времена обслуживания, мощность базы данных, размер кэша, скорость заполнения, цены и доля ошибок плохой сборки — иллюстративные значения для веб-сервиса среднего размера.
Erlang C: вероятность того, что запросу придётся ждать свободного воркера в системе M/M/N.
N = instances × 16 workers, a = λ·S; C(a, N) = B / (1 − (a/N)(1 − B)), B = Erlang B[3][6]
Хвост времени ожидания: вероятность ждать дольше t падает экспоненциально; запросы, всё ещё ждущие к тайм-ауту 2 с, завершаются ошибкой. Сверх мощности избыток завершается ошибкой.
Задержка p99 из квантилей времени обслуживания и времени ожидания.
p99 ≈ S·ln 100 + ln(C/0.01)/(N/S − λ) (service + waiting quantile, an approximation)[3][6]Приближение: сумма квантилей обслуживания и ожидания не равна точному p99 их суммы (может быть чуть выше или ниже); очередь считается установившейся в пределах каждой минуты, так как запросы занимают миллисекунды.
Закон Литтла: занятые воркеры = интенсивность поступления × время обслуживания.
Кэш с TTL: при случайных запросах каждый промах начинает период TTL, в течение которого запросы попадают в кэш.
hit = warm × rT/(1 + rT), r = λ / 20,000 objects; mean age of a cached answer ≈ T/2[5]
Промахи кэша нагружают базу данных; её задержка в очереди замедляет каждый запрос, который к ней обращается, что заодно заполняет воркеры приложения.
DB load = λ·q·(1 − hit); query time = 5 ms/(1 − ρ_db) (≤ 250 ms); S = S_app + (1 − hit)·q·query time[6]Допущение: число воркеров, времена обслуживания, мощность базы данных, размер кэша, скорость заполнения, цены и доля ошибок плохой сборки — иллюстративные значения для веб-сервиса среднего размера.
SLO и бюджет ошибок: скорость расходования показывает, во сколько раз быстрее допустимого тратится бюджет.
budget = 1 − SLO = 0.1 %; burn = error rate / 0.1 %; Δbudget per min = burn / 43,200; burn (1 h) = mean error rate over the last 60 min / 0.1 % (window pre-filled with the opening minute)[1][2]
Автомасштабировщик с отслеживанием цели, задержкой загрузки и паузой (cooldown).
desired = ⌈serving × utilization / target⌉ (utilization saturates at 100 %); new instances serve after the boot delay[6]Допущение: число воркеров, времена обслуживания, мощность базы данных, размер кэша, скорость заполнения, цены и доля ошибок плохой сборки — иллюстративные значения для веб-сервиса среднего размера.
16 workers/instance · app time 50 ms (+20 ms and +1 query with the feature on) · 2 queries/request · DB 4,000 queries/s · 20,000 hot objects · cache refill τ = 30 min (slower while the DB is saturated) · warm-up job +12 %/min for 6 min, +600 queries/s · timeout 2 s · 30 % low-priority traffic · bad build +5 % errors, ×1.25 CPU · rollback 5 min · $0.40 per instance-hour · scale-in by ≤ 20 % of the fleet after 10 quiet minutes · up to 40 instancesДопущение: число воркеров, времена обслуживания, мощность базы данных, размер кэша, скорость заполнения, цены и доля ошибок плохой сборки — иллюстративные значения для веб-сервиса среднего размера.
Случайность: генератор mulberry32 с seed; используемые распределения — равномерное, экспоненциальное (обратная CDF), нормальное (Бокса — Мюллера), Пуассона (Кнут). Seed показан и им можно делиться.
M. Harchol-Balter — Performance Modeling and Design of Computer Systems: Queueing Theory in Action (M/M/k, server farms, capacity provisioning) — Cambridge University Press, 2013