На каких уровнях архитектуры можно реализовать Rate Limiter?

Ответ

Rate Limiter (ограничитель скорости запросов) можно и нужно реализовывать на разных уровнях архитектуры, в зависимости от целей. Вот основные из них, от внешнего к внутреннему:

  1. Уровень шлюза / балансировщика (API Gateway / Load Balancer)

    • Где: Nginx, Kong, Traefik, AWS API Gateway.
    • Зачем: Это первая линия защиты. Ограничивает трафик еще до того, как он попадет в ваши сервисы. Защищает всю инфраструктуру от DDoS-атак и всплесков трафика. Обычно настраивается по IP-адресу или API-ключу.
  2. Уровень приложения (HTTP Middleware)

    • Где: В коде самого приложения, как промежуточный слой для обработки HTTP-запросов. Это самый распространенный способ для бэкенд-сервисов.
    • Зачем: Позволяет реализовать гибкую логику: ограничение для конкретного пользователя, эндпоинта или на основе бизнес-логики. Часто используется алгоритм "Token Bucket" (Ведро с токенами).
      // Пример с использованием стандартной библиотеки golang.org/x/time/rate
      func RateLimit(next http.Handler) http.Handler {
      // 10 запросов в секунду с возможностью "всплеска" до 20 запросов
      limiter := rate.NewLimiter(rate.Limit(10), 20)
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          if !limiter.Allow() {
              http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
              return
          }
          next.ServeHTTP(w, r)
      })
      }
  3. Распределенный Rate Limiter (Distributed Rate Limiter)

    • Где: Использует внешнее хранилище, такое как Redis или Memcached.
    • Зачем: Критически важен для горизонтально масштабируемых приложений. Если у вас несколько экземпляров сервиса, локальный ограничитель (как в примере выше) будет работать некорректно. Централизованное хранилище (например, Redis и его атомарные команды INCR, EXPIRE) обеспечивает единый счетчик для всех экземпляров.
  4. Уровень бизнес-логики

    • Где: Внутри конкретной функции или метода сервиса.
    • Зачем: Для ограничения специфических, ресурсоемких операций, не связанных напрямую с HTTP-запросами. Например: "не более 5 отправок SMS в час для одного пользователя" или "не более 1 генерации отчета в минуту".