Убрать копию из ротации на время работ
sudo nginx -t && sudo systemctl reload nginx — копия больше не
получает новых запросов, текущие доходят. Вернуть — убрать down и
снова reload. reload не рвёт соединения, restart рвёт
(nginx).
Балансировщик принимает запросы на одном адресе, раздаёт их между копиями сервиса и убирает больные из ротации.
sudo nginx -T | grep -A4 '^upstream'
копии и их параметры
tail -n 5 /var/log/nginx/access.log
$upstream_addr: кто ответил
sudo tail -n 3 /var/log/nginx/error.log
почему копия выпала
curl -s -o /dev/null -w '%{http_code}\n' 127.0.0.1:8082
копия сама
curl -s -o /dev/null -w '%{http_code} %header{x-upstream}\n' localhost
sudo nginx -t && sudo systemctl reload nginx
применить без простоя
ip -br a
VIP — второй адрес интерфейса
Один сервер — единая точка отказа: упал, и сайт лежит. Балансировщик нагрузки (load balancer) принимает запросы на одном адресе и раздаёт их между несколькими одинаковыми копиями сервиса — бэкендами (upstream). Упала одна копия — запросы идут на остальные, и пользователи этого не видят. На Linux балансировщиком обычно служит nginx или haproxy.
upstream — группа копий под одним именем, proxy_pass шлёт запросы
в группу. По умолчанию nginx перебирает копии по кругу (round robin):
8081, 8082, 8081… Другие способы и параметры строки server — в
разделе nginx:
| Параметр | Что делает |
|---|---|
least_conn; |
запрос — копии с меньшим числом соединений |
ip_hash; |
один клиент — всегда одна копия |
weight=3 |
копии достаётся втрое больше запросов |
backup |
копия получает запросы, только когда остальные недоступны |
down |
копия выключена руками |
Кто ответил, видно в журнале по $upstream_addr и $upstream_status
и в заголовке X-Upstream. Если nginx повторил запрос на другой
копии, поля — списки через запятую:
Первая копия не ответила (502 — отказ в соединении), вторая
ответила 200. Пользователь получил 200.
Балансировщик должен знать, какая копия больна. nginx судит по
настоящим запросам — это пассивная проверка здоровья. Неудача
запроса к копии — плюс один к счётчику. max_fails неудач за
fail_timeout — копия выключена на время fail_timeout. Потом nginx
пробует её снова одним запросом.
По умолчанию max_fails=1, fail_timeout=10s: после первой неудачи
копия отдыхает 10 секунд. max_fails=0 выключает учёт — копия
считается живой всегда. Копия, которую починили в эти 10 секунд,
получает запросы только после них. Какая неудача считается неудачей,
задаёт proxy_next_upstream (ниже).
У пассивной проверки два минуса: за неё платит запрос пользователя, и больную копию она замечает только по трафику.
proxy_next_upstream — какие ответы считать неудачей и повторять на
следующей копии. По умолчанию error timeout: копия не приняла
соединение или не ответила вовремя.
| Копия | Что видит пользователь по умолчанию |
|---|---|
не слушает порт (Connection refused) |
200: nginx повторил запрос на другой копии |
отвечает 500 |
500 через раз: ответ копии — не неудача |
| висит без ответа | ответ через 60 с: ждёт proxy_read_timeout |
Ответы копии с кодами ошибок добавляют в список явно:
Запрос, который мог что-то изменить (POST), nginx повторно не
отправляет, если уже передал его копии: два списания денег хуже
одной ошибки. Сколько повторов и сколько секунд на них —
proxy_next_upstream_tries и proxy_next_upstream_timeout.
| Директива | Сколько ждёт | По умолчанию |
|---|---|---|
proxy_connect_timeout |
соединения с копией | 60 с |
proxy_read_timeout |
ответа копии между двумя чтениями | 60 с |
proxy_send_timeout |
пока копия примет запрос | 60 с |
Копия, недоступная по сети (пакеты пропадают), и зависшая копия
стоят каждому запросу минуту. Короткие тайм-ауты (2–3 с) вместе с
timeout в proxy_next_upstream делают из минуты пару секунд и
повтор на живой копии. Слишком короткий proxy_read_timeout рвёт
медленные, но здоровые ответы: тяжёлые отчёты, выгрузки.
При активной проверке балансировщик сам опрашивает каждую копию
раз в несколько секунд — например, запросом GET /health. Копию
выключают после нескольких неудач подряд и включают после нескольких
успехов. Больная копия выпадает до того, как к ней придёт
пользователь. Так проверяет haproxy (параметр check у строки
server); в бесплатном nginx активной проверки нет, только
пассивная.
Балансировщик — тоже единая точка отказа. Его делают из двух машин с
плавающим адресом (VIP, virtual IP): клиенты ходят на VIP, а он
живёт на одной машине — MASTER. keepalived на обеих машинах
обменивается объявлениями VRRP. Объявления MASTER пропали — адрес
забирает запасная машина (BACKUP), примерно за 3 секунды при
advert_int 1. При systemctl stop keepalived MASTER сам объявляет
уход, и адрес переезжает сразу.
Второй адрес на интерфейсе — VIP: эта машина сейчас MASTER. Если машины не слышат объявлений друг друга, адрес оказывается на обеих — раздвоение (split brain), разбор в keepalived.
sudo nginx -t && sudo systemctl reload nginx — копия больше не
получает новых запросов, текущие доходят. Вернуть — убрать down и
снова reload. reload не рвёт соединения, restart рвёт
(nginx).
Поле upstream= — подпись $upstream_addr в формате журнала; в
своём формате ищи то же поле. Перекос — weight, ip_hash, копия
выключена после неудач или помечена backup.
Запрос к каждой копии напрямую, мимо балансировщика: код и время
ответа. Копия на другой машине — её адрес вместо 127.0.0.1.
Одна копия из двух отвечает 500 или 503 сама. Для nginx такой
ответ — успешный: копия остаётся в ротации, и через раз пользователь
получает ошибку. Почини копию, убери её (down) или добавь коды в
proxy_next_upstream (load-balancing). Какая копия
отвечает ошибкой — $upstream_addr у строк с 500 в журнале.
Копия недоступна по сети или зависла, и nginx ждёт
proxy_connect_timeout или proxy_read_timeout — по 60 с. В
error.log — upstream timed out (110: Connection timed out).
Поставь 2–3 секунды (load-balancing).
Все копии группы выключены после неудач — клиент получает 502, в
$upstream_addr вместо адреса имя группы (app). Почини хотя бы одну
копию: через fail_timeout nginx попробует их снова.
fail_timeout после последней неудачи;down или backup;upstream при загрузке конфига — нужен reload.upstream server temporarily disabled nginx пишет с уровнем warn, а
error_log в Ubuntu ведёт уровень error и выше. Выключение копии
видно по Connection refused и upstream timed out в error.log и
по спискам в $upstream_addr.
Учёт неудач выключен: мёртвая копия остаётся в ротации навсегда. При отказе в соединении это лишний повтор на каждом запросе, при зависшей копии — тайм-аут на каждом её запросе.
non_idempotent в proxy_next_upstream разрешает повторять POST на
другой копии. Если первая копия успела выполнить запрос и упала на
ответе, заказ или платёж пройдёт дважды.
upstream, server, повторы, тайм-ауты.-w с кодом и временем.Есть неточность? Сообщить об ошибке в статье