Сети и протоколы
Proxy и load balancing: пережить падающий backend
Читать про retry storm — не то же самое, что удержать кластер живым, пока один узел заваливается. Поднимите небольшой пул backends за реальным proxy, внесите сбой под нагрузкой, посмотрите, как блип на 500 мс пытается стать отказом, и применяйте меры отказоустойчивости юнита, пока кластер не переживёт его — с доказательствами на каждом шаге.
Превратите ментальную модель юнита в воспроизводимый цикл: балансируйте load-aware алгоритмом, обнаруживайте сбой active и passive health check, дренируйте аккуратно, ограничивайте каскад circuit breaker и retry budget, вынесите состояние сессии наружу и проверяйте каждую меру метриками до/после под одинаковой нагрузкой.
Поставьте перед пулом из 3–5 backend-инстансов реальный load balancer (Envoy, nginx или HAProxy), внесите отказ одного узла под нагрузкой и докажите, что кластер остаётся доступным — удерживая error rate ниже 0.1% и p99 в пределах цели — применяя лестницу отказоустойчивости юнита с измерениями на каждом шаге.
- Таблица до/после под одинаковой нагрузкой: error rate, латентность p99, retry rate и время обнаружения упавшего узла — измеренные, не оценочные — показывающая error rate снова ниже 0.1% и retry rate снова ниже 0.1% после применения мер.
- Доказательство, что active и passive health check каждый обнаружил свой режим отказа (жёсткий краш против узла, принимающего TCP, но отдающего 500).
- Rolling restart с connection draining даёт ноль видимых клиенту reset соединений в access-логах, тогда как резкое убийство (draining отключён) их даёт — оба захвачены.
- Краткий разбор, называющий в порядке приоритета, какая мера остановила каскад и почему circuit breaker и retry budget стоят выше простого добавления ёмкости.
- Добавьте второй load balancer и поставьте пару за общий VIP (keepalived/VRRP локально или anycast в лабе), чтобы убийство одного LB не роняло весь трафик; измерьте время failover.
- Разделите proxy на L4-уровень перед L7-уровнем и маршрутизируйте /api/ против /static/ в разные пулы на L7; сохраните реальный IP клиента сквозь через X-Forwarded-For или PROXY protocol и проверьте, что backend логирует настоящего клиента.
- Добавьте slow start: когда восстановившийся backend возвращается в пул, наращивайте его трафик 10% → 100% за несколько минут и покажите, что его p99 остаётся ограниченным против немедленного возврата под полную нагрузку.
- Соберите одностраничный on-call runbook: триаж по дашборду, сигнатура retry storm, лестница отказоустойчивости (алгоритм → health → drain → breaker → budget → вынос состояния) и чек-лист верификации.
Это цикл, который вы запустите на каждом реальном инциденте с LB: балансировать load-aware алгоритмом, обнаруживать сбой И active, И passive проверками, дренировать in-flight запросы перед удалением узла, ограничивать каскад circuit breaker и retry budget прежде чем хвататься за ёмкость, выносить состояние сессии наружу, чтобы любой backend мог продолжить любой запрос, и проверять каждую меру числами до/после под одинаковой нагрузкой. Сделав это один раз на игрушечном пуле, вы превращаете продакшен-версию в мышечную память.