Nginx upstream - server down
Sergey Kobzar
sergey.kobzar на itcraft.org
Вт Авг 9 00:10:31 UTC 2011
Максим
Спасибо за детальное описание. Идея понятна.
В данной реализации есть ньюансы. Например php скрипт "подвис" или база
данных залочена (ALTER на таблице в 10G). Соответственно получаем proxy
connect timeout и так для _всех_ серверов.
Как вариант решения (частный случай) - сделать "пингалку". У того же
php-fpm есть ping.path
(http://php.net/manual/en/install.fpm.configuration.php). И если ответа
нет N sec, то тогда действительно сервер в дауне. На что правим список
backend серверов в конфиге и делаем nginx reload.
Может глупости пишу на ночь глядя... Здравая критика приветствуется.
On 08/05/11 14:41, Maxim Dounin wrote:
> 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
>
Подробная информация о списке рассылки nginx-ru