Сервис балансировки нагрузки с поддержкой динамической конфигурации и ограничением запросов.
- Балансировка между бэкенд-серверами с алгоритмами:
- Round Robin
- Least Connections
- (Дополнительные стратегии могут быть добавлены)
- Health-check серверов в реальном времени
- Ограничение запросов (Rate Limiting) по токен-бакету
- Hot-reload конфигурации без перезапуска
- Graceful shutdown
- Go 1.21+
- Docker 20.10+
- PostgreSQL 12+ (для хранения конфигурации лимитов)
- Клонировать репозиторий:
git clone https://github.com/singl3focus/load_balancer-go
cd load-balancer
- Запустить компоуз с балансировщиком и тестовыми серверами:
docker compose up -d
- Пересобрать все сервисы без кэша:
docker compose build --no-cache
- Перезапустить контейнеры с пересобранными образами:
docker compose up --force-recreate
- Остановить и удалить контейнеры, сети, тома (без удаления образов):
docker compose down
- Остановить и удалить всё (контейнеры, тома, образы):
docker compose down --volumes --rmi all
- Обращение к api балансировщика:
curl --location 'http://localhost:8080/clients?key=192.168.1.33' \
--header 'Content-Type: application/json' \
--data '{
"key":"192.168.1.33",
"config": {
"capacity": 1,
"fillrate": "1s"
}
}'
- Обращение к бэкэнд серверам через балансировщик:
curl --location --request POST 'http://localhost:8080/check'
- Использование стандартного HTTP-пакет Go (net/http) для работы с запросами и для переадресации (reverse proxy, например, с использованием пакета net/http/httputil).
Основной функционал:
- Реализовать HTTP-сервер, который принимает входящие запросы (например, на порту 8080).
- При получении запроса балансировщик должен пересылать его на один из заранее заданных бэкенд-серверов. Адреса серверов можно задавать через конфигурационный файл или переменные окружения.
Распределение запросов:
- Реализовать алгоритм распределения запросов по бэкендам:
- Минимально:
- Round Robin
- Дополнительно:
- Least Connections
- [] Weighted Round Robin
- [] IP Hash
- [] Least Response Time
- Минимально:
- Балансировщик должен корректно обрабатывать ситуацию, когда один или несколько бэкендов недоступны (выводить понятное сообщение об ошибке или перенаправлять запросы на работающие серверы).
Параллелизм и конкурентность:
- Обеспечить одновременную обработку нескольких запросов с использованием горутин.
- Гарантировать корректную работу в условиях конкурентных вызовов (избегать гонок данных).
Обработка ошибок:
- Реализовать обработку ошибок при обращении к бэкендам. Выводить понятные сообщения ошибок в лог (например, при недоступности сервера).
Логирование:
- Реализовать базовое логирование входящих запросов, ошибок и событий (например, смены бэкенда при сбое одного из серверов). Можно использовать стандартный пакет log или другую библиотеку для логирования.
Конфигурация:
- Балансировщик должен получать список бэкендов и порт для прослушивания через внешний конфигурационный файл (JSON или YAML) или через параметры командной строки.
- Конфигурация должна быть независима от кода (изменения конфигурации без перекомпиляции).
Требуется разработать модуль для ограничения частоты запросов (rate-limiting) на основе алгоритма Token Bucket. Модуль должен защищать внутренние сервисы от перегрузок, обеспечивать честное распределение ресурсов между клиентами и корректно обрабатывать высокую нагрузку.
Реализация алгоритма Token Bucket:
- Каждому клиенту (IP или API-ключ) выделяется отдельный bucket токенов.
- Настройки bucket: количество токенов (емкость), скорость пополнения.
- Запрос считается допустимым, если в bucket клиента есть токен. В противном случае — отклоняется.
Гранулярное ограничение:
- Отслеживать состояние каждого клиента (IP/API-ключ)
- [] Поддерживать возможность настройки разных лимитов для разных клиентов.
- [] Настройки для разных клиентов можно сохранять в базе данных
Автоматическое пополнение токенов:
- Использовать
time.Ticker
для периодического пополнения токенов в buckets. - Гарантировать атомарность операций с токенами (проверка, извлечение, пополнение).
Конкурентность:
- Методы обработки запросов и обновления состояния buckets должны быть потокобезопасными.
- Обеспечить минимальные блокировки для максимизации производительности.
- Модульная архитектура проекта: код разделен на логически обособленные пакеты (например, для логики распределения, работы с конфигурацией и реализации HTTP-сервера).
- Чистота кода поддерживается, понятное и подробное комментирование, а также примененяются интерфейсы для упрощения замены реализаций.
- Dockerfile и docker-compose.yml для развертывания сервиса и БД
- Интеграционные тесты с использованием go test -bench=. -race.
- Пример нагрузки через Apache Bench (ab -n 5000 -c 1000 http://localhost:8080/).
Здоровье бэкендов (Health Checks):
- Добавить механизм периодических проверок состояния каждого бэкенд-сервера.
- При обнаружении недоступного сервера временно исключать его из пула, а при восстановлении работы возвращать обратно.
Graceful Shutdown:
- Реализовать корректное завершение работы балансировщика (обработка сигнала SIGINT или SIGTERM), чтобы завершить обработку текущих запросов без потери данных.
CRUD для управления клиентами:
- [] API для добавления/удаления клиентов (IP/API-ключей) и настройки их лимитов.
- [] Пример эндпоинта: POST /clients { "client_id": "user1", "capacity": 100, "rate_per_sec": 10 }
Персистентность:
- Сохранять состояние клиентов (текущие токены, настройки) в БД или файле.
- Использовать конфигурационный файл для дефолтных лимитов.
Обработка ошибок:
- [] Возвращать структурированные JSON-ошибки с кодом и описанием.
- [] Пример: { "code": 429, "message": "Rate limit exceeded" }