Почему перегрузка ведёт к коллапсу. Когда запросов больше, чем сервис может обработать, очередь растёт, а с ней и время ответа. Клиенты не дожидаются ответа и уходят по таймауту — но сервер всё равно тратит ресурсы на их запросы. Клиенты повторяют — нагрузка ещё растёт. В итоге сервер на 100% занят работой, результат которой никому не нужен: полезная пропускная способность падает (goodput → 0), хотя CPU загружен полностью.
Load shedding — сознательный отказ:
- ограничение параллелизма — не больше N запросов в работе (семафор), лишние сразу 503/429. N по закону Литтла: пропускная способность × нормальное время ответа;
- по времени в очереди — запрос, простоявший в очереди дольше X (или дольше оставшегося дедлайна клиента), выбрасывается без обработки: его всё равно не дождутся. Вариант — очередь LIFO при перегрузке: свежие запросы успеют, старые и так потеряны;
- CoDel для запросов — если очередь не опустошалась дольше интервала, начинать сбрасывать;
- адаптивный лимит (Netflix concurrency-limits, AIMD/Vegas/Gradient): лимит растёт, пока задержка не растёт, и уменьшается, когда растёт. Не нужно знать пропускную способность заранее — она меняется с выкатками, данными, соседями.
Приоритеты. Не все запросы равны: проверка здоровья, платежи, вход пользователя — важнее фоновой синхронизации, предзагрузки и аналитики. Метка приоритета (заголовок) и отбрасывание с нижних уровней первыми. Отличать новые сессии от продолжающихся: лучше обслужить начатую оформление заказа.
Деградация — вместо отказа дать упрощённый ответ: из кэша (даже устаревший), без персонализации, без второстепенных блоков, меньше результатов поиска. Флаги аварийного отключения тяжёлых функций.
Вокруг: отказ должен быть дешёвым (до разбора тела и походов в базу), клиенты — с повторами с отсрочкой и бюджетом повторов, чтобы отказы не превращались в шторм, автомасштабирование — для устойчивого роста, а не для секундных пиков.