Гид по технологиям

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

5 min read Go Обновлено 05 Jan 2026
Ограничение запросов в Go: rate limiting
Ограничение запросов в Go: rate limiting

Гофер — талисман Go

Одним из факторов при проектировании приложения является ожидаемый объём трафика от пользователей. Объём трафика влияет на распределение ресурсов, масштабирование и стоимость хостинга.

Ограничение частоты запросов — одна из техник контроля входящего трафика к приложению или сети.

Что такое ограничение частоты запросов?

Ограничение частоты запросов — распространённый способ ограничить сетевой трафик в пределах заданных временных окон или при превышении числа запросов от пользователя.

Эта техника полезна для снижения риска атак, таких как брутфорс и DDoS (распределённый отказ в обслуживании), ограничивает web scraping, нагрузку на API и другие нежелательные автоматизированные взаимодействия (боты).

В Go для реализации rate limiting используется пакет rate, который совместим с пакетом time.

Схема пакета rate в Go

Пакет rate является частью экосистемы Go (golang.org/x/time/rate), но не входит в стандартную библиотеку. Его нужно добавить в зависимости проекта.

Выполните эту команду в терминале рабочей директории, чтобы добавить пакет:

go get "golang.org/x/time/rate"

Импортируйте пакеты в файл Go для этого примера:

import (
    "encoding/json"
    "golang.org/x/time/rate"
    "log"
    "net/http"
)

Пакет json используется для кодирования структуры в JSON для клиента. Пакет log нужен для логирования ошибок в консоль, а http — для создания endpoint, middleware и запуска сервера.

Простое API с одним endpoint

Обычно для ограничения частоты запросов пишут middleware, который оборачивает обработчик. Каждый раз при поступлении запроса middleware проверяет, разрешён ли доступ, и в случае успеха передаёт управление обработчику.

Вот модель структуры с полями-строками, которую мы кодируем в JSON:

type Message struct {
    Response    string `json:"response"`
    Description string `json:"description"`
}

Обработчик устанавливает Content-Type = application/json, возвращает статус 200 и кодирует экземпляр структуры в ответ.

func endpointExample(writer http.ResponseWriter, request *http.Request) {
    writer.Header().Set("Content-Type", "application/json")

    writer.WriteHeader(http.StatusOK)

    message := Message{
        Response:    "Successful",
        Description: "You've successfully hit the API endpoint",
    }
    err := json.NewEncoder(writer).Encode(&message)
    if err != nil {
        return
    }
}

Функция endpointExample принимает writer и request из пакета http и возвращает JSON с помощью writer.

Ограничение частоты запросов в простом приложении на Go

Ограничение можно реализовать по числу запросов в единицу времени или по доступному «кредиту» запросов (burst). Всегда нужно создать лимитер до авторизации запроса.

Ниже пример создания лимитера и авторизации по числу запросов:

func rateLimiterMiddleware(next func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {
    limiter := rate.NewLimiter(3, 6) // max of 6 requests and then three more requests per second
    return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
        if !limiter.Allow() {
            writer.Write([]byte("rate limit exceeded "))
            return
        } else {
            endpointExample(writer, request)
        }
    })
}

Функция rateLimiterMiddleware — middleware, принимающая обработчик и создающая лимитер через rate.NewLimiter. Первый параметр — скорость (events/секунду), второй — burst (максимум перед началом регулярной конверсии).

Метод Allow возвращает булево значение — разрешён ли текущий запрос. В примере при превышении лимита клиент получает текст “rate limit exceeded”.

func main() {
    http.HandleFunc("/home", rateLimiterMiddleware(endpointExample))
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Println("There was an error listening on port :8080", err)
    }
}

Функция main монтирует endpoint /home на middleware и запускает сервер на localhost:8080.

Для тестирования можно выполнить в терминале:

for i in {1..10}; do curl http://localhost:8080/home; done

Этот цикл выполнит 10 запросов к /home. На шестом запросе, в примере с burst=6, последующие запросы начнут получать отказ.

Результат работы программы с ограничением частоты

Когда ограничение запросов не сработает

Важно: rate limiting — не универсальное решение. Он не защитит, если:

  • Атака идёт с большого количества распределённых адресов (если лимит привязан к IP, понадобятся дополнительные меры).
  • Злоумышленник использует легитимные учётные записи (требуется поведение на уровне приложения — throttling по пользователю, капча, MFA).
  • Нехватка ресурсов на сервере уже произошла (ограничение запросов помогает предотвратить, но не мгновенно восстановить систему).

Альтернативные и дополняющие подходы

  • Сниффинг и фильтрация на уровне CDN/WAF (Cloudflare, AWS WAF) — блокировка до попадания на приложение.
  • Rate limiting на уровне API gateway (например, Kong, Envoy) — централизованное управление.
  • Token bucket и leaky bucket — разные алгоритмы для разных сценариев; rate в Go фактически реализует token bucket.
  • Трёхуровневая защита: CDN → API gateway → приложение.

Эмпирические правила и эвристики

  • Начинайте с консервативных лимитов в тестовом окружении.
  • Используйте burst для пиковых легитимных операций, но держите его небольшим.
  • Привязывайте лимиты не только к IP: по ключу API, аккаунту, пользователю и даже по маршруту.
  • Логируйте отклонённые запросы отдельно для анализа.

Важно: выбор привязки лимита (IP, user, API key) определяет, какие типы атак вы сможете отразить.

Уровни зрелости внедрения

  • Уровень 1 — базовый: глобальный лимит на endpoint (как в примере).
  • Уровень 2 — продвинутый: лимиты по API-ключам или пользователям, маршрутам.
  • Уровень 3 — корпоративный: интеграция с CDN/WAF, мониторинг, автоматическое масштабирование и alerting.

Факто-бокс

  • Пример в статье: скорость = 3 req/s, burst = 6.
  • Типичный порядок тестов: нагрузка в 2–10× ожидаемой пиков.
  • Пакет: golang.org/x/time/rate.

Мини-методология внедрения

  1. Оцените сценарии использования и ожидаемую нагрузку.
  2. Выберите стратегию привязки лимитов (IP, user, api key).
  3. Реализуйте локально middleware с логированием отказов.
  4. Протестируйте в staging с повторяемыми нагрузочными тестами.
  5. Перенесите на prod с мониторингом и alertami.

Чек‑лист по ролям

Разработчик:

  • Реализовать middleware и unit-тесты.
  • Обеспечить корректные заголовки ответа и коды статуса.

DevOps:

  • Настроить метрики и дашборды (ошибки 429, latency).
  • Выбрать место для rate limiting (app, gateway, CDN).

Security:

  • Определить правила блокировки и реагирования на аномалии.
  • Проверить, что лимит не позволяет легко обходить защиту.

Критерии приёмки

  • Система отказывает запросам при превышении лимита (код 429 или понятный ответ).
  • Логируются все отклонённые запросы.
  • Нельзя обойти лимит простым переадресованием трафика.

Тестовые сценарии

  • Выполнить цикл из 10 запросов и убедиться, что после burst запросы отклоняются.
  • Тесты для разных ключей API и комбинаций IP.
  • Нагрузочный тест для проверки влияния на latency.

Диаграмма принятия решения

flowchart TD
    A[Наблюдается повышенная нагрузка] --> B{Это легитимный трафик?}
    B -- Да --> C[Увеличить масштаб/проверить burst]
    B -- Нет --> D{IP распределён?}
    D -- Да --> E[Применить блокировку на уровне CDN/WAF]
    D -- Нет --> F[Ограничить по ключу API/пользователю]
    C --> G[Мониторинг]
    E --> G
    F --> G

Безопасность и конфиденциальность

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

Краткое резюме

Ограничение частоты запросов — важная базовая приёмка для защиты и экономии ресурсов. В Go пакет golang.org/x/time/rate даёт простой и гибкий способ реализовать token bucket. Для надёжной защиты комбинируйте лимиты с уровнями CDN и API gateway.

Глоссарий

  • rate limiting — ограничение количества операций в единицу времени.
  • burst — кратковременное превышение скорости (буфер для пиков).
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство