Rate Limiting (ограничение скорости) — механизм контроля числа запросов клиента к API или сервису за заданный интервал. Для системного аналитика тема закрывает вопрос «какие лимиты зафиксировать в НФТ и контракте» и «где в архитектуре их применять», а не «как написать Lua-скрипт в Redis». Статья даёт критерии выбора алгоритма и уровня размещения; детали HTTP-, gRPC- и GraphQL-семантики и оформления контракта — в 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL) и 03.05.03 Спецификации контрактов (OpenAPI, AsyncAPI, Protobuf).

1. Суть темы

Rate Limiting — жёсткое ограничение скорости в коротком окне (секунды, минуты): при превышении запрос отклоняется, обычно с HTTP 429 Too Many Requests. Throttling (смягчение трафика) — отдельная стратегия: запрос не отклоняют, а задерживают или ставят в очередь. Quota — бюджет на длительный период (день, месяц). В разговоре термины смешивают; в требованиях различайте явно: «отклонять 429» и «задерживать до N мс» — разные НФТ.

ФункцияЧто даёт системе
Защита от перегрузкиНе даёт исчерпать CPU, память, пул соединений БД при всплесках
СправедливостьОдин «шумный» клиент не монополизирует общий ресурс
Контроль затратОграничивает неконтролируемый рост инфраструктурных расходов
Защита от атакСнижает эффективность DDoS, брутфорса, credential stuffing — детали политик edge см. 03.05.05 Безопасность API
Поддержание SLAПредсказуемое качество для всех потребителей — трассировка к 08.02 Нефункциональные требования (НФТ) — классификация и стандарты

Место в цепочке устойчивости: Rate Limiter проактивно отсекает трафик по счётчику до вызова зависимости; Circuit Breaker реактивно реагирует на ошибки и деградацию latency; Bulkhead ограничивает параллелизм. Типовая цепочка и сравнение паттернов — в 03.06.01 Архитектурные паттерны распределённых систем; здесь не дублируем таблицу, а фиксируем триггер: RL — «сколько запросов», CB — «как ведёт себя зависимость».

Место в топологии ingress: клиент → балансировщик → API Gateway → (опционально) Service Mesh → сервис. Rate Limiting чаще всего ставят на Gateway как единую точку входа; mesh добавляет лимиты east-west; приложение — для дорогих операций внутри bounded context. Связь с балансировкой и пропускной способностью цепочки — 03.06.04 Стратегии балансировки нагрузки.

Термины вендоров vs формулировка в SRS

В облачных продуктах «throttling» часто означает отклонение, а не очередь. В SRS переводите на поведение, а не на маркетинговое имя функции.

Как называютТипичное поведениеКак писать в требованиях
AWS API Gateway — throttlingHTTP 429 при превышении steady/burst на stage/method«Reject с 429; лимит X req/s, burst Y» — не «throttling с очередью»
Kong / nginx — rate limitingReject (429/503) или delay в зависимости от плагина/директивыЯвно: reject path или max queue delay p99
Cloudflare — rate limiting rulesBlock/challenge/log; не всегда 429Указать код ответа и действие на edge
Envoy — rate limit filterReject (обычно 429) через external RL serviceГлобальная политика + latency reject path
Throttling в смысле shapingОчередь, искусственная задержка«Max wait N ms, p95 queue delay» — отдельное NFR

2. Ключевые понятия

Три компонента любой политики

КомпонентСмыслПример
Лимит (Limit)Максимум разрешённых запросов100 запросов
Окно (Window)Период применения лимита60 секунд
Идентификатор (Identifier)Ключ клиентаAPI Key, User ID, Tenant ID, IP

Мультиарендность и конфликты идентификаторов: корпоративный egress, NAT и мобильные операторы дают один IP многим пользователям — лимит «по IP» может заблокировать легитимных клиентов. Для B2B предпочтительны API Key или Tenant ID; IP — как дополнительный слой на edge, не единственный идентификатор.

Rate Limiting vs Throttling vs Quota

ТерминГоризонтПоведение при превышении
Rate LimitingСекунды–минутыОтклонение (429)
ThrottlingСекунды–минутыЗадержка или очередь
QuotaДень, месяц, биллинговый периодОтклонение до сброса периода

Quota vs технический RL: месячный план «10 000 вызовов» часто считает биллинговый счётчик (отдельная подсистема); rate limit на Gateway защищает инфраструктуру в реальном времени. В требованиях укажите оба, если продукт продаёт тарифы: quota — в контракте/SLA, RL — в эксплуатационных НФТ.

Не только HTTP: gRPC, GraphQL, асинхронные потоки

Статья опирается на REST для примеров, но лимиты нужны и для других синхронных контрактов. gRPC: код RESOURCE_EXHAUSTED, метаданные grpc-status-details-bin / retry hint — семантика в 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL). GraphQL: отдельные лимиты на query depth, complexity/cost-based limiting, иногда per-field — не сводите к «100 req/min на один endpoint». Ограничение consumer lag или throughput в Kafka/RabbitMQ — см. 03.05.04 Асинхронное взаимодействие (очереди, Kafka, Events); это backpressure и quota на уровне брокера, не HTTP 429. В интеграционных требованиях не подменяйте одно другим.

Алгоритмы: компромиссы для выбора в ADR

Пять распространённых алгоритмов; для аналитика важны точность, поведение на границах окна и допустимость burst — не конкретная структура данных в Redis. Сравнение альтернатив и атрибутов качества оформляйте в 10.01.13 Шаблон архитектурного решения (ADR).

АлгоритмТочностьПамятьВсплескиКогда выбирать
Fixed WindowПриблизительнаяМинимальнаяДо 2× на границе двух окон (boundary burst)Простые лимиты, throttling логина
Sliding Window LogАбсолютнаяO(N) на клиентаНетПлатёжные API, аудит каждого запроса
Sliding Window CounterNear-exact (~95%+)O(1)Сглаженные границыDefault для большинства API
Token BucketТочнаяO(1)Контролируемый burst (накопленные токены)Публичные API, легитимные пики (Stripe, GitHub)
Leaky BucketТочнаяO(1)Нет всплесковPolicing (отброс) или shaping (очередь с постоянной «утечкой»)

Sliding Window Counter — модель для verifiable NFR: хранятся счётчики текущего и предыдущего фиксированного окна. Оценка числа запросов в скользящем окне:

weighted_count = count_previous × (1 − elapsed/window) + count_current

где elapsed — время от начала текущего окна, window — длина окна.

Семантика границы (inclusive/exclusive): при реализации «N запросов за окно» обычно считают, что N-й запрос ещё разрешён, (N+1)-й — отклонён. В формуле выше это соответствует проверке до инкремента: запрос разрешён, если weighted_count < limit (строгое неравенство); после успешного запроса счётчик увеличивается. Если в приёмке формулируют «не более N включительно за любое скользящее окно» — явно укажите это в NFR и согласуйте с нагрузочным сценарием на границе окна, иначе спор между «≤ N» и «< limit» неизбежен.

Требование «sliding window counter, точность ≥ 95%» verifiable: на performance-тесте сравнивают фактический RPS с эталонным Sliding Window Log при том же limit/window.

Leaky Bucket — policing vs shaping: policing — переполненная корзина отбрасывает запросы (близко к rate limiting); shaping — запросы ждут в очереди с постоянной скоростью обработки — это throttling, и в НФТ нужен SLA задержки (p95/p99), а не только 429.

RPS vs concurrent limits: rate limiter считает запросы в секунду; ограничение одновременных вызовов ближе к Bulkhead. В чеклисте уточняйте оба: «100 req/min per API Key» и «не более 10 параллельных long-polling соединений».

Конкуренция за общий ресурс: fair sharing и приоритеты

Per-tenant лимит «100 req/min» не отвечает на вопрос: кто выигрывает, если все упираются в одну БД, партнёрский API или пул воркеров export. На elicitation зафиксируйте:

  • Глобальный cap на дорогую операцию vs per-tenant fair queue (равные доли при дефиците);
  • Приоритет tier (enterprise над free) — weighted fair sharing или отдельные пулы;
  • Blast radius: один tenant не должен исчерпать глобальный бюджет на export.

Связь с узким местом цепочки — 01.05 Теория ограничений и бережливое мышление и 03.06.04 Стратегии балансировки нагрузки: лимит на ingress без учёта downstream capacity даёт ложное ощущение защиты.

Распределённый Rate Limiting

В кластере из нескольких экземпляров локальный лимит на каждом умножает эффективную квоту:

Политика: 100 req/min на клиента глобально
Лимит на экземпляр: 100 req/min (локально)
 
Клиент → 100 req/min → Экземпляр A  (локально OK)
       → 100 req/min → Экземпляр B  (локально OK)
       Итого: 200 req/min — глобальная политика нарушена в 2×

Решения для требований:

ПодходСутьTrade-off
Централизованное хранилищеRedis / Valkey, атомарные операцииСогласованность; сетевая задержка, зависимость от store
External rate limit serviceEnvoy/Istio external RL, Kong clusterЕдиная политика; операционная сложность
ГибридЛокальный token bucket + периодическая синхронизацияБаланс задержки и точности

При падении central store зафиксируйте fail-open (пропускать — доступность) или fail-closed (отклонять — безопасность/compliance). Для регулируемых контуров см. 08.06 Юридические и регуляторные требования РФ (PCI-DSS) и 08.07 Основы кибербезопасности для системного аналитика.

Уровни размещения в архитектуре

API Gateway — основной уровень для north-south трафика: централизованные политики per API Key, per IP, per method/stage (пример уровней: account → stage → method → client в AWS API Gateway). Размещение на edge защищает бэкенды до входа в сервисы — см. 03.05.01 Виды интеграции (точка-точка, ESB, API-led).

Service Mesh — дополнительный слой для east-west (сервис ↔ сервис): local rate limit на sidecar или external RL service.

Application layer — лимиты на domain capability внутри bounded context: export/report в одном контексте, read model в другом — не «просто тяжёлые эндпоинты». См. 03.06.02 Основы Domain-Driven Design.

Критерий выбора уровня (decision hint):

УровеньКогда достаточноКогда недостаточно
Managed Gateway ruleЕдиный north-south ingress, политики per API Key/IP, быстрый time-to-marketНужны east-west лимиты, сложная fair queue, кастомная логика по payload
Mesh filter + external RLМного сервисов, единая политика tenant/service, mTLS-трафикНет mesh; операционная команда не готова к external RL
Application / library (Resilience4j, Bucket4j)Дорогие операции per aggregate, контекстно-зависимые правилаНужна централизованная смена лимитов без деплоя сервиса

Важно не смешивать контексты умножения квоты:

  • Несколько реплик Gateway с локальным счётчиком на каждой → эффективный лимит ≈ n × quota (n реплик).
  • Local rate limit на sidecar каждого pod → та же проблема для лимита «на tenant глобально».
  • External / centralized RL на Gateway или mesh → глобальная политика соблюдается.

Многоуровневый подход:

[Edge Gateway]     — глобальные лимиты (per API Key, per IP)
       ↓
[Service Mesh]     — лимиты между сервисами (per tenant)
       ↓
[Application]      — лимиты на domain capability (export, report)

3. Как применяется в работе аналитика

Скелет ADR: что сравнивать

При выборе размещения заполните 10.01.13 Шаблон архитектурного решения (ADR) минимум так:

Блок ADRСодержание для rate limiting
КонтекстКакой трафик (north-south / east-west), SLA, compliance
АльтернативыТолько Gateway; Gateway + mesh; Gateway + mesh + app-level
Атрибуты качестваТочность глобального лимита; p95 latency reject path; blast radius при падении Redis/RL service
РешениеАлгоритм, идентификатор, уровень, fail-open/closed
ПоследствияОперационные затраты, точки отказа, что проверять на performance-тесте

Чеклист вопросов на elicitation

ВопросЧто определяет
Лимит: RPS, RPM или concurrent?Тип ограничения и алгоритм
Идентификатор: API Key, User, Tenant, IP?Ключ политики; конфликты NAT
Разные лимиты по эндпоинтам / domain capability?Матрица endpoint × tier × algorithm
Тарифные планы (free / pro / enterprise)?Tiered limiting
При общем bottleneck — fair queue или приоритет tier?Weighted sharing, global cap
При превышении: 429, очередь (throttling) или degrade?Стратегия reject vs shaping
Глобальный или per-instance лимит?Централизованный store vs local
Поведение при сбое лимитера?Fail-open vs fail-closed
Протокол: REST, gRPC, GraphQL, async?Коды ошибок и метрики в контракте
Как клиент узнаёт лимиты?Заголовки, metadata, документация
Retry клиента при 429 / RESOURCE_EXHAUSTED?Backoff, jitter, idempotency
Метрики и алерты?Наблюдаемость для приёмки

Обоснование цифры лимита

«100 req/min» без расчёта — типичный анти-паттерн. Свяжите лимит с:

Формулируйте в 10.01.12 Шаблон нефункциональных требований (NFR) с измеримыми критериями.

Заголовки ответа (REST, IETF draft)

ЗаголовокСмысл
RateLimit-LimitЛимит в текущем окне
RateLimit-RemainingОстаток
RateLimit-ResetСекунды до сброса
Retry-AfterПри 429 — когда повторить

Пример ответа:

HTTP/1.1 429 Too Many Requests
Retry-After: 30
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30

Описание в контракте — 03.05.03 Спецификации контрактов (OpenAPI, AsyncAPI, Protobuf) и 10.01.04 Шаблон спецификации REST API: per-operation limits, коды ошибок, семантика заголовков. Для gRPC/GraphQL — поля и коды в том же духе, детали протокола в 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL).

429 и retry storm

Агрессивный retry клиента при 429 усиливает нагрузку (retry storm). В требованиях к клиенту и SDK зафиксируйте:

Со стороны API документируйте ожидаемое поведение клиента; для интеграторов — 07.02 Работа с API (практика).

Стратегии при превышении

СтратегияПоведениеКогда
Reject (hard limit)429 / RESOURCE_EXHAUSTEDЖёсткие квоты, публичный API
Queue (throttling / shaping)Задержка в очередиДопустима latency; укажите p95/p99
DegradeУпрощённый ответGraceful degradation
Fail-openПропуск при сбое лимитераДоступность важнее
Fail-closedОтклонение при сбоеБезопасность, compliance

Пример матрицы лимитов

ЭндпоинтTier FreeTier ProАлгоритмИдентификатор
GET /items60/min600/minSliding Window CounterAPI Key
POST /items10/min100/minToken Bucket (burst 20)API Key
POST /export1/hour10/hourSliding Window CounterUser ID

Для hourly quota на тяжёлые операции (export) Fixed Window даёт boundary burst до 2× на стыке часов — два job подряд. Для строгого «не более N в любой скользящий час» используйте Sliding Window Counter или Token Bucket с burst=1; в NFR явно укажите «без boundary burst».

Примеры формулировок в требованиях

User Story:

Как владелец API-ключа, я хочу лимит 1000 запросов в минуту, чтобы интеграция работала предсказуемо. При превышении система возвращает HTTP 429 с Retry-After и заголовками RateLimit-*.

NFR (разделить метрики):

API применяет rate limiting по алгоритму sliding window counter (модель weighted count двух окон) с точностью не хуже 95% относительно эталонного sliding window log при performance-тесте. Лимит N запросов за окно W: N-й запрос разрешён, (N+1)-й отклонён (семантика «не более N включительно»). Лимиты настраиваются per API Key и per IP. При превышении — HTTP 429; путь отклонения (reject path) отвечает ≤ 50 мс при p95 на edge gateway.

Наблюдаемость и приёмка

Минимум для эксплуатации и 02.04.02 Критерии приёмки (Acceptance Criteria):

  • метрики: доля 429, RPS по tier, latency reject path, ошибки central store;
  • алерт при аномальном росте 429 (> порога от baseline);
  • дашборд «top consumers» по идентификатору;
  • performance / NFR verification (нагрузочный сценарий): sustained rate, boundary burst, распределённость по N экземплярам — это отдельный контур проверки НФТ, не путать со 08.03 Тестирование требований (статическое тестирование) (ревью текста требований).

4. Типовые ошибки и ограничения

ОшибкаПочему плохоКак избежать
Только локальные счётчикиКлиент обходит лимит через несколько экземпляровТребование central store или external RL
Лимит «с потолка»Блокировка легитимного трафика или перегрузкаРасчёт от capacity и телеметрии
RL и throttling в одном NFRНепроверяемое поведениеРаздельные требования: 429 vs max queue delay
Копировать «throttling» вендора как очередьAWS/Kong throttling часто = rejectТаблица вендор vs SRS; поведение в NFR
Per-tenant без global capEnterprise и free делят одну БД без fair sharingGlobal cap + tier priority в elicitation
Один лимит на все эндпоинтыДорогие операции «съедают» квоту readМатрица endpoint × tier × bounded context
Лимит только по IPЛожные блокировки за NATAPI Key / Tenant как primary key
Fixed Window для hourly exportBoundary burst 2× на стыке часовSliding counter / token bucket
Нет заголовков / metadataКлиенты не адаптируют нагрузкуRateLimit-* или gRPC retry hint
Игнор retry storm429 провоцирует ещё большую нагрузкуBackoff, jitter, Retry-After в контракте
Quota в биллинге ≠ RL на Gateway«Есть месячный план» не защищает от spikeОба слоя в требованиях
Настроили и забылиЛимиты устаревают с ростом системыРегулярный review; связь с 02.03.02 Приоритизация требований (MoSCoW, WSJF, Кано)

Связи с другими разделами базы

Источники и дополнительные материалы

Книги

  • Chris Richardson — Microservices Patterns (глава о resilience patterns)
  • Sam Newman — Building Microservices (rate limiting в контексте API Gateway)

Стандарты и спецификации

Статьи и документация

Инструменты (для согласования с архитектором)