Ограничение частоты запросов

OxPHP поставляется со встроенным ограничителем частоты запросов по IP, поэтому не нужно запускать внешние зависимости или инфраструктуру. После включения он отслеживает количество запросов для каждого клиентского IP и возвращает ответ 429 Too Many Requests, когда клиент превышает настроенный порог.

Как это работает

Ограничитель частоты запросов использует счётчик с фиксированным окном, ключом которого служит IP-адрес клиента. У каждого IP есть собственный независимый счётчик и окно.

  1. Когда приходит запрос, OxPHP ищет клиентский IP в своём внутреннем трекере.
  2. Если записи нет или текущее окно истекло, начинается новое окно со счётчиком, равным нулю.
  3. Счётчик увеличивается на каждый запрос.
  4. Если счётчик превышает RATE_LIMIT, сервер немедленно возвращает ответ 429 с заголовками ограничения частоты запросов. Запрос отклоняется до маршрутизации и выполнения PHP.

Запросы, отклонённые ограничителем частоты, по-прежнему отражаются в логах доступа и метриках.

Конфигурация

Переменная По умолчанию Описание
RATE_LIMIT 0 Максимальное количество запросов на один IP в пределах окна. 0 полностью отключает ограничение частоты запросов без каких-либо накладных расходов
RATE_WINDOW_SECONDS 60 Длительность окна ограничения частоты запросов в секундах
bash
# Allow 100 requests per IP per 60-second window RATE_LIMIT=100 RATE_WINDOW_SECONDS=60

Заголовки ответа

Отклонённые запросы возвращают ответ 429 Too Many Requests со следующими заголовками:

Заголовок Описание
Retry-After Количество секунд до сброса текущего окна
x-ratelimit-limit Максимальное количество запросов, разрешённых на одно окно
x-ratelimit-remaining Количество запросов, оставшихся в текущем окне (0 при срабатывании ограничения)
x-ratelimit-reset Количество секунд до сброса текущего окна
x-request-id Идентификатор запроса для сопоставления этого ответа с логами доступа

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

http
HTTP/1.1 429 Too Many Requests Retry-After: 45 x-ratelimit-limit: 100 x-ratelimit-remaining: 0 x-ratelimit-reset: 45 x-request-id: 67e2a1f412341a2b0042 429 Too Many Requests

Устранение неполадок

Легитимные пользователи попадают под ограничение частоты

Возможно, ваш порог слишком низкий для реальных паттернов трафика. Проверьте долю ответов 429 в метриках и соответственно скорректируйте RATE_LIMIT или RATE_WINDOW_SECONDS.

Проверьте количество запросов, отклонённых ограничителем:

bash
curl http://localhost:9090/metrics | grep rate_limited

Решение: Увеличьте RATE_LIMIT или расширьте RATE_WINDOW_SECONDS, чтобы дать клиентам больше свободы.

Пользователи за корпоративным NAT используют общий счётчик по IP

OxPHP ограничивает частоту запросов по исходному IP. Все пользователи за общим NAT или прокси используют один счётчик. Если это создаёт проблемы, рассмотрите возможность отключить встроенный ограничитель OxPHP (RATE_LIMIT=0) и применять ограничение частоты запросов на более высоком уровне (например, на балансировщике нагрузки или API-шлюзе), где у вас есть доступ к идентификаторам пользователей.

За обратным прокси?

Задайте TRUSTED_PROXIES, чтобы ограничение частоты запросов использовало настоящий IP клиента, а не IP прокси. См. Доверенные прокси.

Ограничение частоты запросов не работает между несколькими экземплярами

Ограничитель частоты запросов OxPHP работает в памяти и на уровне отдельного экземпляра. Если вы запускаете несколько экземпляров OxPHP за балансировщиком нагрузки, каждый из них ведёт собственные независимые счётчики. Клиент может отправить RATE_LIMIT запросов на каждый экземпляр, не вызвав ответ 429. Для согласованного ограничения частоты запросов между экземплярами используйте внешний ограничитель на уровне балансировщика нагрузки или API-шлюза.

Растёт потребление памяти при атаках с ротацией IP

OxPHP отслеживает до 100 000 уникальных IP-адресов. При достижении этого предела истёкшие записи удаляются перед добавлением новых. Если вы наблюдаете рост потребления памяти из-за того, что атакующий быстро меняет IP, автоматическая очистка ограничивает влияние ограниченным объёмом памяти.

Пример для Docker

compose.yaml
services: app: image: ghcr.io/oxphp/oxphp:0.10.0 ports: - "8080:80" environment: RATE_LIMIT: "100" RATE_WINDOW_SECONDS: "60" volumes: - ./app:/var/www/html:ro

Рекомендации

  • Начинайте консервативно. Начните с более низкого лимита (например, 60 запросов в минуту) и увеличивайте его на основе наблюдаемых паттернов трафика. Ослабить лимиты проще, чем восстанавливаться после перегруженного сервера.
  • Используйте общий ограничитель частоты запросов для развёртываний с несколькими экземплярами. Ограничитель частоты запросов OxPHP работает на уровне отдельного экземпляра. Для согласованного ограничения между экземплярами применяйте ограничение частоты запросов на уровне балансировщика нагрузки или API-шлюза.
  • Следите за долей ответов 429. Отслеживайте долю запросов, отклонённых ограничителем, в метриках, чтобы обнаруживать неверно настроенные пороги или неожиданные всплески трафика.

Примечания

  • Алгоритм с фиксированным окном. Ограничитель использует счётчик с фиксированным окном, а не со скользящим. На границе между двумя окнами клиент может всплеском отправить до 2x от настроенного лимита.
  • Только по IP. Ключом ограничения частоты запросов служит исходный IP-адрес. Пользовательские ключи, такие как API-ключ или идентификатор пользователя, не поддерживаются.
  • Состояние в памяти. Счётчики ограничения частоты запросов не разделяются между несколькими экземплярами OxPHP.
  • Автоматическая очистка. Истёкшие записи очищаются, когда трекер превышает 100 000 IP, удаляя все записи с истёкшими окнами.

Смотрите также