На каких уровнях приложения можно реализовать Rate Limiter и какие инструменты для этого есть в Go?

Ответ

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

Уровни реализации:

  1. HTTP Middleware (Промежуточное ПО)

    • Описание: Самый распространенный способ для веб-сервисов. Ограничитель встраивается в цепочку обработки HTTP-запросов и проверяет каждый входящий запрос перед тем, как передать его основному обработчику.
    • Пример:

      import (
          "net/http"
          "time"
          "golang.org/x/time/rate"
      )
      
      func RateLimitMiddleware(next http.Handler) http.Handler {
          // 10 запросов в секунду с пиковым разрешением до 20
          limiter := rate.NewLimiter(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)
          })
      }
  2. gRPC Interceptors

    • Описание: Аналог Middleware, но для gRPC. Перехватывает входящие RPC-вызовы для применения логики ограничения.
  3. На уровне бизнес-логики

    • Описание: Используется для ограничения не самих запросов, а ресурсоёмких операций внутри сервиса (например, отправка email, генерация отчетов, сложные вычисления). Это позволяет защитить систему независимо от того, как была вызвана операция (через HTTP, gRPC, CLI или фоновую задачу).
  4. На уровне API Gateway / Ingress Controller / Proxy

    • Описание: Ограничение настраивается на уровне инфраструктуры (Nginx, Traefik, Kong, облачные API Gateway). Запросы отсекаются еще до того, как достигнут вашего приложения. Это снижает нагрузку на сам сервис.
  5. Внешний сервис (Распределенный Rate Limiter)

    • Описание: Критически важен для систем с горизонтальным масштабированием (несколько экземпляров сервиса). Чтобы лимит был общим для всех экземпляров, его состояние хранится во внешнем быстром хранилище, чаще всего в Redis.

Популярные инструменты в Go:

  • golang.org/x/time/rate: Стандартная библиотека для реализации алгоритма Token Bucket (как в примере выше). Отлично подходит для локальных ограничителей в рамках одного процесса.
  • github.com/go-redis/redis_rate: Библиотека для создания распределенных ограничителей на базе Redis.
  • github.com/ulule/limiter: Гибкая библиотека, поддерживающая разные хранилища (in-memory, Redis, Memcached) и фреймворки.