Назад | Перейти на главную страницу

Буферизация запросов к nginx на короткое время, если бэкэнд не работает

У меня есть приложение nodejs, которое всегда работает за nginx. Когда я развертываю новый код, я просто делаю forever restart но я не могу позволить себе получить 502 даже за такое короткое время.

Как настроить nginx для повторных попыток на этом одном вышестоящем сервере в случае 502? Я пробовал установить proxy_connect_timeout, proxy_read_timeout и proxy_send_timeout например 30s но я сразу получаю 502 ни на что :(

Конфигурация моего сайта:

upstream my_server {
  server 127.0.0.1:3000 fail_timeout=0;
  keepalive 1024;
}

server {
 listen 3333;

server_name myservername.com;
access_log /var/log/nginx/my_server.log;

location / {
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header X-NginX-Proxy true;

  # retry upstream on 502 error
  proxy_connect_timeout      30s;
  proxy_send_timeout         30s;
  proxy_read_timeout         30s;

  proxy_pass http://my_server;
  proxy_http_version 1.1;
  proxy_set_header Connection "";
  proxy_redirect off;
 }
}

Можно ли буферизовать запросы на это короткое время, когда апстрим недоступен?

В конечном итоге это звучит как проблема с вашим сервером: nginx отправляет запрос на ваш сервер, соединение сразу же отклоняется, поэтому у nginx нет другого варианта, который мог бы передать ошибку нижестоящему пользователю, поскольку никакой другой восходящий поток не указан, и timeout значения, которые вы указываете, не играют здесь никакого эффекта, поскольку nginx вообще ничего не должен ждать.


Я не знаю что forever есть или как это работает, но на ум приходят несколько возможных решений.

Есть две возможности того, что происходит на восходящей стороне:

  • "Навсегда" может быть принимая соединение и немедленно возвращает ошибку. В этом случае похоже, что вам действительно следует спросить, как заставить его не обрабатывать соединение неправильно, а подождать, пока ваше приложение не завершит развертывание, и обработать запрос тут же. В opengrok приложение на tomcat у сервера есть эта проблема.

  • Никто не слушание на порту, на котором должно работать ваше приложение, поэтому ядро ​​немедленно отбрасывает пакет и сразу же возвращает пакет TCP RST.

    • Если TCP RST является причиной, вы можете решить ее, имея forever сохранить прослушивающий сокет или настроить ядро ​​для постановки входящих пакетов в очередь на определенное время в ожидании того, что кто-то заберет их позже, так что когда forever действительно запускается, у него будет целая очередь, готовая к обслуживанию.

    • Настройте ядро ​​так, чтобы оно не выдавалось TCP RST когда никто не слушает, тогда твой timeout в nginx будет иметь эффект. Впоследствии настройте nginx сделать второй запрос другому апстриму.

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

В противном случае вам нужно попытаться настроить nginx, чтобы исправить проблему:

  • Вы могли бы попробовать proxy_cache с участием proxy_cache_use_stale.

  • Вы можете попробовать использовать обработчик ошибок: см. proxy_intercept_errors (вероятно, применяется только в том случае, если 503, который вы получаете, передается из вашего бэкэнда) и error_page. Вы можете потратить время на обработку ошибок, пока ваше приложение не вернется в исходное состояние, а затем сделать запрос в свое приложение.

    • Вы можете потратить время, запустив второе приложение, которое просто выполнит sleep() сколько бы времени ни потребовалось для повторного развертывания вашего приложения, затем либо выполните перенаправление HTTP, либо завершите работу без ответа; черт возьми, вы можете просто реализовать это, попытавшись проксировать TCP-порт, который вы block drop в брандмауэре, который активирует ваши таймауты в nginx. Впоследствии настройте nginx для выполнения второго запроса.

Если вы реализуете один из вышеперечисленных подходов, который включает timeout активации, то впоследствии потребуется сделать дополнительный запрос к бэкэнду. Вы можете использовать upstream директиву для этого, где вы либо указываете один и тот же сервер несколько раз, либо, если не принимаете, можете зеркалировать порт через свой брандмауэр, или, что еще лучше, вы могли бы фактически запустить несколько независимых серверов приложений в первую очередь.

Это возвращает нас к вашему серверу приложений: если он не может справиться с проблемой чистого повторного развертывания, возможно, вам следует запустить два таких сервера приложений и использовать nginx для балансировки нагрузки между ними. Или разверните их заново, а затем переключите nginx на новую копию, когда она действительно будет готова. Иначе, как вы могли быть уверены, что ваши клиенты будут готовы ждать ответа от вашего API даже 30 секунд?