Rate Limiting — это метод контроля количества запросов, которые могут быть отправлены в систему за определенный период времени. Это помогает избежать перегрузки вашего сервера, предотвратить злоупотребление ресурсами и эффективно управлять трафиком. Давайте рассмотрим несколько распространенных методов:
Использование Guava’s RateLimiter
Библиотека Google Guava предоставляет класс RateLimiter, который можно использовать для реализации ограничения скорости на основе алгоритма сегмента токенов.
Приведенный выше код ограничит обработку до 5 запросов в секунду. RateLimiter.acquire() заблокирует поток до тех пор, пока не будет получено разрешение. Обратите внимание, что оно ограничено скоростью памяти и будет сброшено, если вы перезапустите приложение. Это ограничения по запросам для всех клиентов. Если вы хотите иметь ограничение скорости для каждого клиента, вы можете изменить код, чтобы иметь объект ограничения скорости для каждого клиента. Вы можете идентифицировать клиента по IP-адресу, идентификатору клиента или ключу API.
Использование Redis для распределенного ограничения скорости
В распределенных системах Redis часто используется для хранения счетчиков ограничения скорости, обеспечивая единообразие ограничения скорости для нескольких экземпляров службы. В этом примере мы реализуем ограничение скорости, при котором клиенту разрешено определенное количество запросов в минуту (или любой определенный временной интервал). Если лимит превышен, клиенту будет запрещено делать больше запросов до окончания времени.
- setex: Он устанавливает значение со сроком действия (в секундах). По истечении срока действия Redis автоматически удаляет ключ, что сбрасывает счетчик запросов.
- incr: Считает количество запросов для клиента.
- Rate-limiting per client: У каждого клиента есть собственный счетчик запросов, хранящийся в Redis. Система отслеживает количество запросов и на основании этого устанавливает ограничение скорости.
Это очень простая реализация, но вы можете легко расширить ее для более сложных сценариев (например, разные лимиты для разных клиентов, разные лимиты времени и т. д.).
Использование фильтра в Spring Boot для реализации Rate Limiting API
Мы можем использовать комбинацию filter/interceptor и хранилища Redis для управления количеством запросов в распределенных системах.
Шаги:
- Подсчитайте количество запросов от каждого клиента, используя кеш или базу данных (например, Redis для распределенных сред).
- Ограничьте количество запросов в единицу времени (например, в секунду, в минуту) и отклоните или задержите лишние запросы.
- Обработайте логику ограничения скорости с помощью фильтра, перехватчика или аннотации.
Создайте фильтр, который проверяет количество запросов, сделанных каждым клиентом, и ограничивает запросы на основе фиксированного окна (например, 5 запросов в минуту).
В примере идентифицируем клиента по IP-адресу (request.getRemoteAddr()), но можно использовать ключи API или идентификаторы пользователей. Если предел скорости превышен, фильтр возвращает статус HTTP 429 Too Many Requests с сообщением об ошибке.
Библиотека Resilience4j для Rate Limiting
Resilience4j — это легкая библиотека отказоустойчивости, созданная на основе Netflix Hystrix. Он обеспечивает ограничение скорости, разрыв цепи, переборку, повторную попытку и многое другое. Вот пример того, как реализовать ограничение скорости с помощью Resilience4j в приложении Spring Boot.
Используйте аннотацию @RateLimiter, чтобы ограничить запросы API на уровне контроллера или сервиса.
в этом примере:
- RateLimiter настроен на ограничение 5 запросов за 60 секунд для экземпляра myService.
- Если клиент превышает лимит, генерируется исключение RaceLimiterException, которое можно обработать с помощью специального обработчика ошибок.
- Если вы хотите предоставить собственное сообщение об ошибке при превышении ограничения скорости, вы можете использовать ControllerAdvice для обработки исключений:
Преимущество заключается в том, что он обеспечивает чистую конфигурацию на основе аннотаций, что упрощает интеграцию с Spring Boot. Вы можете определить ограничения, периоды обновления и поведение тайм-аута для каждой службы или API. Он хорошо интегрируется со Spring Boot и прост в использовании с аннотацией @RateLimiter. Наряду с ограничением скорости он предлагает размыкание цепи, повторные попытки, изоляцию переборки и т. д., которые можно использовать вместе для повышения устойчивости системы. Хотя Resilience4j обладает широкими возможностями настройки, он не имеет прямой поддержки распределенного кэширования или ограничения скорости с помощью Redis. При необходимости вам придется интегрировать Redis вручную.
Заключение
Google Guava сосредоточился только на ограничении скорости. Нет встроенного механизма отказоустойчивости. Ограничение скорости часто выполняется на уровне метода. В памяти, Не распределяется.
Rsilance4j — общая отказоустойчивость (автоматический выключатель, повторные попытки, перегородка и т. д.), включая ограничение скорости. Можно ограничить на уровне каждого сервиса, используя аннотации и интеграцию с Spring Boot. Очень детальный контроль над ограничениями скорости (для каждого API, сервиса и т. д.). Ограничение скорости работы в памяти; нет распределенной поддержки «из коробки». Легко использовать с аннотациями Spring Boot.
Redis — можно использовать в качестве центрального хранилища для отслеживания запросов каждого пользователя или клиента, обеспечивая единообразие ограничения скорости для нескольких экземпляров приложений/распределенной системы.