Распределённая служба ограничения скорости Gubernator
Разработка на Gubernator переехала в новый дом по адресу gubernator-io/gubernator
v2.4.0 — это последняя версия, доступная из этого репозитория, все новые функции и исправления ошибок будут происходить в новом репозитории.
Gubernator — это распределённая, высокопроизводительная, облачная и не имеющая состояния служба ограничения скорости.
Gubernator является статичным в том смысле, что ему не требуется дисковое пространство для работы. Никакая конфигурация или данные кэша никогда не синхронизируются с диском. Это связано с тем, что каждый запрос к gubernator включает конфигурацию ограничения скорости. Сначала вы можете подумать, что это ненужная нагрузка для каждого запроса. Однако на самом деле конфигурация ограничения скорости состоит всего из 4 64-битных целых чисел.
# Скачать файл docker-compose
$ curl -O https://raw.githubusercontent.com/mailgun/gubernator/master/docker-compose.yaml
# Запустить контейнер docker
$ docker-compose up -d
Теперь вы можете делать запросы ограничения скорости через CURL
# Обратиться к HTTP API на localhost:9080 (GRPC находится на 9081)
$ curl http://localhost:9080/v1/HealthCheck
# Сделать запрос ограничения скорости
$ curl http://localhost:9080/v1/GetRateLimits \
--header 'Content-Type: application/json' \
--data '{
"requests": [
{
"name": "requests_per_sec",
"uniqueKey": "account:12345",
"hits": "1",
"limit": "10",
"duration": "1000"
}
]
}'
Пример запроса ограничения скорости, отправленного через GRPC, может выглядеть следующим образом:
rate_limits:
# Ограничивает запрос определённым ограничением скорости
- name: requests_per_sec
# Уникальный ключ, который идентифицирует этот экземпляр ограничения скорости
unique_key: account_id=123|source_ip=172.0.0.1
# Количество обращений, которые мы запрашиваем
hits: 1
# Общее количество запросов, разрешённых для этого ограничения скорости
limit: 100
# Длительность ограничения скорости в миллисекундах
duration: 1000
# Алгоритм, используемый для расчёта ограничения скорости
# 0 = Token Bucket
# 1 = Leaky Bucket
algorithm: 0
# Поведение ограничения скорости в gubernator.
# 0 = BATCHING (Включает пакетирование запросов к одноранговым узлам)
# 1 = NO_BATCHING (Отключает пакетирование)
# 2 = GLOBAL (Включить глобальное кэширование для этого ограничения скорости)
behavior: 0
Пример ответа будет таким:
rate_limits:
# Статус ограничения скорости. OK = 0, OVER_LIMIT = 1
- status: 0,
# Текущее настроенное ограничение
limit: 10,
# Оставшееся количество запросов
remaining: 7,
# Временная метка unix в миллисекундах, когда корзина будет сброшена, или если установлено OVER_LIMIT, это время, когда ограничение скорости больше не будет возвращать OVER_LIMIT.
reset_time: 1551309219226,
# Дополнительная метаинформация о запросе, которая может быть полезна клиенту
metadata:
# Это имя
... **Оставшийся счётчик при первом превышении лимита**
Затем последовательные вызовы `GetRateLimits` будут возвращать нулевой оставшийся счётчик и не будут возвращать никакого остаточного значения. Это поведение лучше всего работает с алгоритмом «токенового ведра», поскольку счётчик `Remaining` будет оставаться нулевым после превышения лимита до момента сброса, тогда как алгоритм «протекающего ведра» немедленно обновит `Remaining` до ненулевого значения.
Это облегчает сценарии, в которых событие превышения лимита должно оставаться таким до сброса лимита. Этот подход необходим, если процесс должен выполнить две проверки лимита — до и после процесса, а значение `Hit` неизвестно до завершения процесса.
*До процесса:* вызовите `GetRateLimits`, указав `Hits=0`, чтобы проверить значение счётчика `Remaining`. Если `Remaining` равен нулю, известно, что лимит исчерпан, и процесс можно прервать.
*После процесса:* вызовите `GetRateLimits`, используя указанное пользователем значение `Hits`. Если вызов возвращает превышение лимита, процесс не может быть прерван, поскольку он уже завершён. Используя поведение `DRAIN_OVER_LIMIT`, счётчик `Remaining` будет обнулён.
Как только произойдёт превышение лимита на этапе «после», последующие процессы обнаружат состояние превышения лимита на этапе «до».
**Gubernator как библиотека**
Если вы используете golang, вы можете использовать Gubernator в качестве библиотеки. Это полезно, если вы хотите реализовать сервис ограничения скорости с собственной моделью компании. Мы делаем это внутри Mailgun с помощью сервиса, который мы творчески назвали `ratelimits`, который отслеживает ограничения, накладываемые на основе учётных записей. Таким образом, вы можете воспользоваться мощью и скоростью Gubernator, но при этом добавить бизнес-логику и интегрировать специфические для домена проблемы в свой сервис ограничения скорости.
Когда вы используете библиотеку, ваш сервис становится полноправным членом кластера, участвующим в том же согласованном хешировании и кэшировании, что и автономный сервер Gubernator. Всё, что вам нужно сделать, это предоставить экземпляр сервера GRPC и сообщить Gubernator о расположении пиров в вашем кластере. Файл `cmd/gubernator/main.go` — отличный пример того, как использовать Gubernator в качестве библиотеки.
**Дополнительная дисковая персистентность**
Хотя сервер Gubernator в настоящее время напрямую не поддерживает дисковую персистентность, библиотека Gubernator предоставляет интерфейсы, через которые пользователи библиотеки могут реализовать персистентность. Библиотека Gubernator имеет два интерфейса, доступных для дисковой персистентности. В зависимости от варианта использования разработчик может реализовать интерфейс [Loader](/store.go) и поддерживать сохранение ограничений скорости только при запуске и завершении работы или пользователи могут реализовать интерфейс [Store](/store.go), и Gubernator будет непрерывно вызывать `OnChange()` и `Get()`, чтобы поддерживать актуальность кеша в памяти и постоянного хранилища с последними данными об ограничении скорости. Оба интерфейса *могут* быть реализованы одновременно, чтобы гарантировать сохранение данных в постоянном хранилище.
Для тех, кто решит реализовать интерфейс `Store`, не требуется сохранять ВСЕ ограничения скорости, полученные через `OnChange()`. Например, если вы хотите поддерживать длительность ограничения скорости дольше минуты, дня или месяца, вызовы `OnChange()` могут проверять длительность ограничения скорости и решать сохранять только те ограничения скорости, которые имеют длительности сверх самостоятельно определённого предела.
**API**
Все методы доступны через GRPC, но также доступны через HTTP с использованием [GRPC Gateway](https://github.com/grpc-ecosystem/grpc-gateway).
**Проверка работоспособности**
Проверка работоспособности возвращает `unhealthy`, если узел сообщается etcd или kubernetes как `up`, но экземпляр сервера не может связаться с этим узлом по его объявленному адресу.
###### GRPC
```grpc
rpc HealthCheck (HealthCheckReq) returns (HealthCheckResp)
GET /v1/HealthCheck
Пример ответа:
{
"status": "healthy",
"peer_count": 3
}
Получение ограничения скорости
Ограничения скорости можно применять или получать с помощью этого интерфейса. Если клиент делает запрос к серверу с hits: 0
, то текущее состояние ограничения скорости извлекается, но не увеличивается.
rpc GetRateLimits (GetRateLimitsReq) returns
``` **HTTP**
POST /v1/GetRateLimits
**Пример запроса:**
```json
{
"requests": [
{
"name": "requests_per_sec",
"uniqueKey": "account:12345",
"hits": "1",
"limit": "10",
"duration": "1000"
}
]
}
Ответ:
{
"responses": [
{
"status": "UNDER_LIMIT",
"limit": "10",
"remaining": "9",
"reset_time": "1690855128786",
"error": "",
"metadata": {
"owner": "gubernator:81"
}
}
]
}
Примечание: Gubernator использует etcd, Kubernetes или циклический DNS для обнаружения одноранговых узлов и создания кластера. Если у вас нет ни того, ни другого, метод docker-compose — это самый простой способ попробовать gubernator.
$ docker run -p 8081:81 -p 9080:80 -e GUBER_ETCD_ENDPOINTS=etcd1:2379,etcd2:2379 \
ghcr.io/mailgun/gubernator:latest
# Зайдите в HTTP API по адресу localhost:9080
$ curl http://localhost:9080/v1/HealthCheck
# Загрузите спецификацию развёртывания Kubernetes
$ curl -O https://raw.githubusercontent.com/mailgun/gubernator/master/k8s-deployment.yaml
# Отредактируйте файл развёртывания, чтобы изменить переменные конфигурации среды
$ vi k8s-deployment.yaml
# Создайте развёртывание (включает спецификацию службы безголового режима)
$ kubectl create -f k8s-deployment.yaml
Если ваша служба DNS поддерживает автоматическую регистрацию, например AWS Route53 service discovery, вы можете использовать один и тот же полный домен для поиска как контейнеров бизнес-логики, так и экземпляров gubernator, а также для поиска контейнеров/экземпляров gubernator друг друга.
Gubernator поддерживает TLS как для HTTP, так и для GRPC соединений. Вы можете увидеть пример с самозаверяющими сертификатами, запустив docker-compose-tls.yaml
# Запуск docker compose
$ docker-compose -f docker-compose-tls.yaml up -d
# Зайти в HTTP API на localhost:9080 (GRPC находится на 9081)
$ curl --cacert certs/ca.cert --cert certs/gubernator.pem --key certs/gubernator.key https://localhost:9080/v1/HealthCheck
Gubernator настраивается через переменные среды с необязательным флагом --config
, который берёт файл пар ключ-значение и помещает их в локальную среду перед запуском.
См. example.conf
для всех доступных параметров конфигурации и их описаний.
См. architecture.md для полного описания архитектуры и внутренней работы gubernator.
Gubernator публикует метрики Prometheus для мониторинга в реальном времени. См. prometheus.md для получения подробной информации.
Gubernator поддерживает OpenTelemetry. См. tracing.md для получения дополнительной информации.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )