Health-checks и отказоустойчивость апстрима
Сервер в апстриме упал — а пользователи не должны этого заметить. Nginx умеет выводить мёртвые бэкенды из ротации автоматически.
«Хорошая балансировка — это не только раздать нагрузку, но и вовремя перестать отправлять её туда, где никто не отвечает.»
Бэкенды падают: деплой, перегрузка, сбой. Если Nginx продолжит слать туда запросы, пользователи получат ошибки. Поэтому в апстриме есть механизмы определения «здоровья» серверов и автоматического исключения мёртвых.
Пассивные проверки: max_fails и fail_timeout
upstream backend {
server 10.0.0.1 max_fails=3 fail_timeout=30s;
server 10.0.0.2 max_fails=3 fail_timeout=30s;
}
Это пассивные проверки: Nginx судит о здоровье по реальным запросам. Если в течение fail_timeout (30s) случилось max_fails (3) неудач, сервер помечается недоступным на fail_timeout и не получает запросов. По истечении срока Nginx снова осторожно попробует его.
сервер B: ошибка, ошибка, ошибка (3 за 30с)
|
v
помечен DOWN на 30с -> трафик идёт только на A
|
v
через 30с -> пробный запрос; ОК -> вернулся в ротацию
Резервные серверы и переключение
upstream backend {
server 10.0.0.1;
server 10.0.0.2;
server 10.0.0.9 backup; # включается, только если основные легли
}
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2;
}
backup-сервер молчит, пока живы основные, и подхватывает нагрузку при их отказе. proxy_next_upstream говорит, при каких ошибках Nginx должен повторить запрос на другом сервере апстрима — это даёт прозрачное восстановление: клиент даже не узнает, что первый бэкенд не ответил.
Как работает под капотом
Пассивные проверки бесплатны: Nginx уже отправляет запросы, ему лишь нужно считать неудачи. Минус — он узнаёт о падении только когда чей-то запрос уже провалился (этот один запрос «принимает удар», но proxy_next_upstream повторит его на здоровом сервере). Активные health-checks (Nginx сам периодически дёргает /health до запросов пользователей) есть в коммерческом Nginx Plus и в Open Source реализуются внешними средствами. Важно: повторять (proxy_next_upstream) безопасно только идемпотентные операции — иначе можно дважды списать платёж.
Частые ошибки
- Полагаться на default
max_fails=1. Один случайный таймаут выкинет живой сервер из ротации; для шумной сети подними порог. - proxy_next_upstream на неидемпотентных POST. Повтор платежа = двойное списание. Ограничь повторы безопасными методами.
- Думать, что Open Source Nginx делает активные проверки сам. Из коробки — только пассивные.
Best practices
- Задавай
max_failsиfail_timeoutявно под свою сеть, не полагайся на дефолты. - Держи
backup-сервер для аварийного режима. proxy_next_upstream— только для безопасных к повтору ситуаций; для платежей будь осторожен.- Заведи на бэкенде лёгкий эндпоинт
/healthдля внешнего мониторинга.
Пассивные и активные проверки на практике
Разница между пассивными и активными проверками здоровья определяет, как быстро пользователи почувствуют падение бэкенда. При пассивной проверке (то, что умеет open-source Nginx) сервер узнаёт о проблеме только когда реальный запрос пользователя провалится: этот невезучий запрос «принимает удар на себя», а Nginx после нескольких таких неудач выводит бэкенд из ротации. Спасает то, что proxy_next_upstream тут же повторяет пострадавший запрос на здоровом сервере, так что пользователь обычно ничего не замечает. Но окно между падением и срабатыванием max_fails существует.
Активные проверки решают это иначе: Nginx сам, в фоне, периодически дёргает специальный эндпоинт /health на каждом бэкенде — ещё до того, как туда пойдёт пользовательский трафик. Упавший сервер исключается превентивно. В чистом open-source Nginx этой функции нет (она в коммерческом Nginx Plus), но на практике её роль выполняют внешние инструменты: оркестраторы вроде Kubernetes делают liveness/readiness-пробы и сами убирают нездоровые поды из сервиса, а системы вроде Consul обновляют список апстримов. Поэтому хорошая привычка — всегда заводить на бэкенде лёгкий эндпоинт /health, который быстро отвечает «жив» (а в продвинутом варианте ещё и проверяет доступность базы). Этот маленький маршрут становится точкой опоры для всей системы отказоустойчивости, кто бы ни выполнял проверки — сам Nginx, оркестратор или внешний мониторинг.
Итоги
Nginx выводит упавшие бэкенды из ротации пассивно через max_fails/fail_timeout, держит backup-серверы на случай аварии и прозрачно повторяет запросы через proxy_next_upstream (осторожно с неидемпотентными). Активные health-checks — за Nginx Plus или внешними инструментами. На этом балансировка завершена — переходим к финальному разделу: HTTPS, безопасность и оптимизация прода.