Hello!
On Fri, Aug 05, 2011 at 02:36:06PM +0400, Maxim Dounin wrote:
Hello!
On Fri, Aug 05, 2011 at 12:21:55PM +0300, Sergey Kobzar wrote:
С утра остановил один из бэкэндов, но 504 отловить не получилось -
ошибка и до этого появлялась не перманентно. Выяснилось, что при
Ok. Как я уже говорил, 504 может возникать если второй бекенд
по каким-то причинам тоже на запрос не ответил.
остановленном бэкенде некоторые статические файлы загружаются с
задержкой ровно в минуту (или 1 мин, 1 сек).
Подобное поведение - в рамках используемого алгоритма.
Если лежащий бекенд признан в настоящий момент негодным - все
запросу идут на другой бекенд. Если нет - запрос попытаются
сначала отправить на основной бекенд для данного ip-адреса, и
только если он не ответит (в вашем случае - случится
proxy_connect_timeout) - перебросят на второй.
Алгоритм не оптимальный, в частности в типичной ситуации
"один из бекендов глухо лежит и ни на какие пакеты не отвечает"
балансировка будет выглядеть так:
0s:
Где-то тут backend1 умер, остался только backend2.
0s .. 60s:
Запросы отправляется на оба бекенда. Отрабатывают те, которые
попадают на backend2, те что на backend1 - ждут таймаута.
60s:
Случился первый таймаут для backend1 (proxy_connection_timeout
60s, по умолчанию). Бекенд признан негодным на ближайшие 60s
(server ... fail_timeout=60s, по умолчанию).
Как меня совершенно справедливо поправил Oleksandr V. Typlyns'kyi,
fail_timeout по умолчанию 10s.
60s .. 120s:
Все запросы идут на backend2 и обрабатываются. Продолжают
timeout'иться ранее отправленные запросы на backend1 (и обновляют
его статус недоступности). Потаймаутившиеся запросы по
proxy_next_upstream отправляются на backend2.
120s .. 180s:
Все запросы идут на backend2 и обрабатываются. Запросов на
backend1 больше не осталось, начал тикать fail_timeout.
180s:
Соответственно тут вместо 180s следует читать 130s.
Истёк fail_timeout, backend1 снова признан годным. Запросы снова
пойдут на оба бекенда и всё повторится с момента 0s.
Т.е. фактически при настройках по умолчанию 30 процентов времени
запросы пытаются идти на умерший бекенд. При двух бекендах - ждут
таймаута ~15 процентов запросов.
Ну и соответственно 23% запросов будут ждать таймаута по
умолчанию.
Очевидно что алгоритм не очень эффективен (и его надо менять),
но в настоящий момент он такой.
Для улучшения ситуации - тюнить таймауты (в частности - уменьшать
proxy_connect_timeout, 3 секунд должно хватить для локальной
сети), а равно условия признания бекенда негодным (server ...
max_fails/fail_timeout, увеличивать fail_timeout).
E.g. при
proxy_connect_timeout 3s;
server ... fail_timeout=300s;
ждать таймаута будет ~ 0.5% запросов, да и сам таймаут будет
практически незаметен для клиентов.
Документация где-то тут:
http://sysoev.ru/nginx/docs/http/ngx_http_proxy_module.html#proxy_connect_timeout
http://sysoev.ru/nginx/docs/http/ngx_http_upstream.html#server
Maxim Dounin
p.s. Cc'd в list для истории, ибо набирать столь подробное
объяснение мне обычно лень.
Maxim Dounin