Как реализовать взаимодействие между балансировщиком и инстансами для распределения нагрузки и обработки ошибок?
Что проверяют
Понимаете ли вы, как балансировщик узнаёт, что инстанс жив, и что происходит с запросом, когда инстанс падает посреди обработки. Следом почти всегда спрашивают, как выкатить новую версию без потерянных запросов и какие запросы безопасно повторять.
Как отвечать
Начните с того, что балансировка живёт в отдельном компоненте: nginx, HAProxy, Envoy, облачный L7-балансировщик или Service и Ingress в Kubernetes. Приложение на Python про соседей не знает.
- алгоритмы: round robin по умолчанию, взвешенный вариант для разных по мощности машин, least connections при неровной длительности запросов, хэш по ключу для привязки клиента. Сессии при этом лучше держать в Redis, чтобы привязка вообще не требовалась;
- активные health checks: балансировщик сам опрашивает
/healthс интервалом и выводит инстанс после нескольких неудач подряд; - пассивные проверки: ошибки на живом трафике, в nginx это
max_failsиfail_timeoutу апстрима; - liveness и readiness: readiness отвечает, готов ли инстанс принимать трафик, liveness говорит, жив ли процесс. В Kubernetes это
readinessProbeиlivenessProbe; - повторы:
proxy_next_upstreamв nginx отправляет запрос на другой апстрим при ошибке соединения или таймауте. POST, уже ушедший на апстрим, по умолчанию не повторяется, для таких операций нужен ключ идемпотентности; - graceful shutdown: по SIGTERM инстанс проваливает readiness, дорабатывает текущие запросы и только потом выходит. У gunicorn на это есть
--graceful-timeout, по умолчанию 30 секунд.
Где спотыкаются
Пишут балансировку в клиентском коде: перед каждым запросом дёргают /health у всех инстансов. Нагрузка удваивается, а между проверкой и запросом инстанс успевает упасть.
Делают health check, который либо всегда отвечает 200, либо проверяет все зависимости. Во втором случае падение Redis выводит из ротации сразу все инстансы, хотя половина эндпоинтов Redis не использует.
Повторяют всё подряд без лимита. При перегрузке ретраи умножают трафик, а повтор оплаты списывает деньги дважды. Нужны ограничение попыток, экспоненциальная задержка с джиттером и идемпотентность.