Публичный API принимает запросы быстрее, чем зависимая система их обрабатывает; назовите механизм ограничения входного потока.
Это ограничение скорости — rate limiting, или управление допуском запросов на границе системы. Оно ограничивает число запросов за интервал времени для клиента, tenant-а или общего ресурса и тем самым не позволяет входному потоку перегрузить зависимость.
Ограничение скорости не ускоряет обработку и не устраняет уже принятые запросы. Поэтому его часто сочетают с ограничением числа одновременно выполняющихся операций, тайм-аутами и контролируемым отказом.
По мере роста сетевых и распределённых систем стало недостаточно рассчитывать ресурсы на среднюю нагрузку. Кратковременные всплески, неравномерные клиенты и повторные попытки после ошибок могли исчерпать соединения, потоки, память или квоты внешней системы.
Rate limiting появился как форма управления допуском: система заранее решает, сколько работы она готова принять. Это переносит отказ на границу, где его можно сделать быстрым, предсказуемым и менее разрушительным для внутренних компонентов.
Если API принимает все запросы без ограничения, они накапливаются в очередях, занимают рабочие потоки и соединения с зависимостью. В результате растут задержки, истекают тайм-ауты, а клиенты начинают повторять запросы, усиливая перегрузку.
Особенно опасна ситуация с общей зависимостью: один агрессивный клиент или один тип дорогостоящих операций может вытеснить остальных. Простое масштабирование потребителя не всегда помогает, если ограниченным ресурсом остаётся база данных или внешний сервис.
Ограничитель хранит состояние потребления и разрешает запрос только при наличии доступной квоты. Квота может задаваться для всего API, отдельного клиента, tenant-а, операции или конкретной зависимости.
Распространённые модели различаются поведением при всплесках:
При превышении лимита система обычно быстро отвечает отказом или сигналом временной недоступности. Важно различать отказ от ограничения скорости и отказ от бизнес-валидации: клиенту нужен однозначный сигнал, чтобы не повторять запрос немедленно без изменения поведения.
В распределённой системе локальный ограничитель на каждом экземпляре может пропустить суммарно больше запросов, чем предусмотрено политикой. Для общего лимита требуется согласованное состояние или централизованная точка ограничения, но это добавляет задержку и само становится зависимостью.
Rate limiting ограничивает скорость, но не обязательно число одновременно выполняющихся операций. Если запросы долгие, даже разрешённый поток может занять все рабочие ресурсы. Поэтому для защиты конкретной зависимости полезно дополнительно применять concurrency limit, а для очередей — ограничение их размера.
Главный компромисс — между защитой системы и качеством обслуживания. Слишком низкий лимит снижает утилизацию ресурсов и отказывает легитимным клиентам, слишком высокий не предотвращает перегрузку. Лимиты следует выбирать по измеренной пропускной способности зависимости, классу операции и требуемому уровню изоляции клиентов.
Платёжный API обслуживает несколько компаний. Одна интеграция после сетевой ошибки начала повторять запросы с высокой частотой, из-за чего выросло число обращений к платёжному провайдеру и увеличились задержки для остальных клиентов.
Рассматривались три варианта. Увеличение числа экземпляров API почти не помогало, поскольку узким местом был лимит провайдера. Неограниченная очередь сохраняла запросы, но увеличивала задержку и риск исчерпания памяти. Полный глобальный лимит защищал провайдера, однако позволял одному tenant-у занять всю квоту.
Выбрали token bucket с отдельными лимитами для tenant-ов и более строгим лимитом для дорогих платёжных операций. Дополнительно ввели ограничение одновременных обращений к провайдеру и контролируемые повторы с экспоненциальной задержкой.
В результате всплеск одного клиента перестал вытеснять остальных, а нагрузка на провайдера стала предсказуемой. Цена решения — дополнительное состояние ограничителя, необходимость согласовывать лимиты с провайдером и риск отказа добросовестных клиентов при неверно выбранной квоте.
1. Чем ограничение скорости отличается от ограничения параллелизма?
Ограничение скорости задаёт, сколько запросов допускается за единицу времени. Ограничение параллелизма задаёт, сколько операций может выполняться одновременно.
Эти меры решают разные задачи. Быстрые запросы можно контролировать rate limiting, а для медленной зависимости критично не занять все рабочие потоки одновременно; в таком случае нужен concurrency limit. В перегруженной системе они часто применяются вместе.
2. Почему локального ограничителя недостаточно для общего лимита в кластере?
Каждый экземпляр при локальном подсчёте видит только свою долю запросов. Если лимит равен ста запросам в секунду, а работают десять экземпляров, суммарный поток может приблизиться к тысяче запросов в секунду.
Общий лимит требует общего состояния или маршрутизации через единую точку. Централизованный вариант проще для согласованности, но добавляет сетевую задержку и новую точку отказа; распределённое состояние уменьшает централизацию, но усложняет корректность и поведение при разделении сети.
3. Почему бездумные повторы могут обойти ограничение и усилить перегрузку?
Клиент, получив отказ по лимиту или тайм-аут, может немедленно отправить несколько новых запросов. Если таких клиентов много, система получает положительную обратную связь: ухудшение обработки вызывает больше входной нагрузки.
Нужны ограниченные повторы, экспоненциальная задержка, случайное рассеивание времени повторов и ясное различие между временным отказом и окончательной ошибкой. Для неидемпотентных операций также требуется защита от повторного выполнения, иначе попытка стабилизировать нагрузку может привести к дублированию бизнес-действий.