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 — throttling | HTTP 429 при превышении steady/burst на stage/method | «Reject с 429; лимит X req/s, burst Y» — не «throttling с очередью» |
| Kong / nginx — rate limiting | Reject (429/503) или delay в зависимости от плагина/директивы | Явно: reject path или max queue delay p99 |
| Cloudflare — rate limiting rules | Block/challenge/log; не всегда 429 | Указать код ответа и действие на edge |
| Envoy — rate limit filter | Reject (обычно 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 Counter | Near-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 service | Envoy/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» без расчёта — типичный анти-паттерн. Свяжите лимит с:
- capacity downstream (БД, внешние API) и целевой утилизацией — см. 01.05 Теория ограничений и бережливое мышление;
- пиками из телеметрии или прогноза нагрузки;
- тарифом продукта (quota) и маржой;
- цепочкой ingress/LB — 03.06.04 Стратегии балансировки нагрузки.
Формулируйте в 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 зафиксируйте:
- уважение
Retry-Afterи заголовковRateLimit-*; - exponential backoff с jitter;
- лимит числа повторов;
- idempotency для mutating-операций при повторе — 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL).
Со стороны 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 Free | Tier Pro | Алгоритм | Идентификатор |
|---|---|---|---|---|
GET /items | 60/min | 600/min | Sliding Window Counter | API Key |
POST /items | 10/min | 100/min | Token Bucket (burst 20) | API Key |
POST /export | 1/hour | 10/hour | Sliding Window Counter | User 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 cap | Enterprise и free делят одну БД без fair sharing | Global cap + tier priority в elicitation |
| Один лимит на все эндпоинты | Дорогие операции «съедают» квоту read | Матрица endpoint × tier × bounded context |
| Лимит только по IP | Ложные блокировки за NAT | API Key / Tenant как primary key |
| Fixed Window для hourly export | Boundary burst 2× на стыке часов | Sliding counter / token bucket |
| Нет заголовков / metadata | Клиенты не адаптируют нагрузку | RateLimit-* или gRPC retry hint |
| Игнор retry storm | 429 провоцирует ещё большую нагрузку | Backoff, jitter, Retry-After в контракте |
| Quota в биллинге ≠ RL на Gateway | «Есть месячный план» не защищает от spike | Оба слоя в требованиях |
| Настроили и забыли | Лимиты устаревают с ростом системы | Регулярный review; связь с 02.03.02 Приоритизация требований (MoSCoW, WSJF, Кано) |
Связи с другими разделами базы
- Паттерны устойчивости (триггер RL vs CB vs Bulkhead) — 03.06.01 Архитектурные паттерны распределённых систем
- Bounded context, лимиты на domain capability — 03.06.02 Основы Domain-Driven Design
- Балансировка, ingress, пропускная способность цепочки — 03.06.04 Стратегии балансировки нагрузки
- Узкое место и обоснование capacity — 01.05 Теория ограничений и бережливое мышление
- ADR: альтернативы Gateway / mesh / app — 10.01.13 Шаблон архитектурного решения (ADR)
- API Gateway, точка входа — 03.05.01 Виды интеграции (точка-точка, ESB, API-led)
- HTTP 429, gRPC, GraphQL, retry, idempotency — 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL)
- Лимиты и заголовки в OpenAPI/контракте — 03.05.03 Спецификации контрактов (OpenAPI, AsyncAPI, Protobuf)
- Rate/backpressure для Kafka и очередей — 03.05.04 Асинхронное взаимодействие (очереди, Kafka, Events)
- Edge security, DDoS, брутфорс — 03.05.05 Безопасность API, 08.07 Основы кибербезопасности для системного аналитика
- Классификация и оформление НФТ — 08.02 Нефункциональные требования (НФТ) — классификация и стандарты
- Шаблон NFR и REST API spec — 10.01.12 Шаблон нефункциональных требований (NFR), 10.01.04 Шаблон спецификации REST API
- Поведение клиента при 429 — 07.02 Работа с API (практика)
- Критерии приёмки НФТ — 02.04.02 Критерии приёмки (Acceptance Criteria)
Источники и дополнительные материалы
Книги
- Chris Richardson — Microservices Patterns (глава о resilience patterns)
- Sam Newman — Building Microservices (rate limiting в контексте API Gateway)
Стандарты и спецификации
- RFC 6585 — HTTP 429 Too Many Requests: https://www.rfc-editor.org/rfc/rfc6585#section-4
- IETF Draft: RateLimit Headers —
RateLimit-Limit,RateLimit-Remaining,RateLimit-Reset: https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/
Статьи и документация
- Redis — Rate Limiting patterns: https://redis.io/docs/latest/develop/use/clients/patterns/rate-limiting/
- Stripe — Rate limits: https://docs.stripe.com/rate-limits
- Cloudflare — Rate limiting rules: https://developers.cloudflare.com/waf/rate-limiting-rules/
- microservices.io — Rate limiting pattern: https://microservices.io/patterns/reliability/rate-limiting.html
- AWS API Gateway — Throttling (vendor «throttling» = reject с 429): https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html
Инструменты (для согласования с архитектором)
- Resilience4j RateLimiter: https://resilience4j.readme.io/docs/ratelimiter
- Bucket4j: https://bucket4j.com/
- Envoy Rate Limit filter: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/rate_limit_filter
- Kong Rate Limiting Advanced: https://docs.konghq.com/hub/kong-inc/rate-limiting-advanced/
- nginx limit_req: https://nginx.org/en/docs/http/ngx_http_limit_req_module.html