On 21.05.2021 10:09, Evgeniy Berdnikov wrote:

Есть nginx, который проксирует запросы на единственный бекенд php-fpm.
Во время перезапуска php-fpm клиентам сразу сыпятся 5хх ошибки.

Каким образом можно настроить nginx так, чтобы он в случае ошибки
связи с бекендом пытался достучаться до него в течении N секунд
(например, 30 сек), с интервалом, например, в K секунд
(например, 0.1 сек) ?

Тогда клиент вместо сообщения про ошибку видел бы просто небольшое
замедление ответа сервера на секунду или максимум несколько секунд,
что гораздо лучше, чем мгновенный возврат сообщения про ошибку 5хх.

  Возврат 5xx говорит о том, что либо
1. хост недоступен по сети (возможно, ребутается), по сисколу connect(2)
     возвращается EHOSTUNREACH.
  2. хост доступен, но порт в этот момент не прослушивается, тогда
     возвращается ECONNREFUSED,
  3. приложение возвращает 5xx и nginx форвардит этот ответ клиенту.

  Ели речь о п.2 и п.3 (перезапуск php-fpm), то это вовсе не ситуация
  "нет связи с бэкендом", которая п.1.

nginx и php-fpm у меня находятся на одном и том же хосте,
связь между ними идет через unix domain socket по протоколу fastcgi.

Обрабатывать таким образом, через повтор запроса имеет смысл,
разумеется, только 502 и 504 статусы на стороне nginx.

Если же бекенд вернул 500 ошибку - это внутренняя ошибка бекенда,
повтор тут ничем не поможет, эту ошибку надо сразу вернуть клиенту.

Возврат 502 бывает в случае такой записи в логах:

connect() to unix:/run/php-fpm/www.sock failed (2: No such file or directory) while connecting to upstream

Сокет /run/php-fpm/www.sock отсутствует во время перезапуска php-fpm.

  Если же речь о ребуте хоста php-fpm, то либо бэкенд в локальной сети и
  оказывается недоступен по arp-у, тогда EHOSTUNREACH возвращается после
  arp-овского таймаута (обычно это 3 секунды), если бэкенд в другой
  подсети, то обычно шлюз возвращает icmp[host-unreachable] по той же
  причине, через те же 2-3 секунды.

Речь идет о перезапуске php-fpm командой "systemctl restart php-fpm"
Если делать "systemctl reload php-fpm" - это не всегра срабатывает,
иногда после релоада php-fpm оказывается в нерабочем состоянии,
поэтому использую именно "systemctl restart php-fpm" для изменения
конфигурации php-fpm, тогда и случаются 502 ошибки с сайтами.

Кроме того, иногда, время от времени, бывает еще такая ошибка:
upstream timed out (110: Connection timed out) while reading response header from upstream
- тогда клиенту возвращается 504 статус. Причину этих таймаутов найти
не могу, поэтому и хотелось бы сделать workaround средствами nginx.

Может быть как-то с помощью njs или nginx-module-perl или с помощью
ngx_http_upstream_module это можно сделать? Или тут единственно возможный
вариант - писать патч на С для решения этой задачи?

  Ох... да просто отрубить пакетным фильтром (файрволом) этот бэкенд
  на время всех манипуляций по перезапуску php-fpm. А когда запустится,
  открыть обратно. Конечно, proxy_connect_timeout подкрутить.
  И заскриптовать всё.

Там unix domain socket, какой пакетный фильтр может быть?
Кроме того, чем поможет отрубать этот бекенд, ведь он единственный?
(см. тему: Re: Configuring nginx to retry a single upstream server)
Будет точно так же 502 ошибка. А ведь именно этого я и хочу избежать.

P.S.

Понятное дело, что в случае ддос-атаки это даст amplification,
но ддос-атаки можно легко детектировать, например, по количеству
запросов в минуту, и если превышен какой-то предел - отключать
эту функциональность с повторами запросов и возвращаться
к старому поведению, так как это есть сейчас.

--
Best regards,
 Gena

_______________________________________________
nginx-ru mailing list
nginx-ru@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-ru

Ответить