Коды ошибок Nginx 499
Я получаю много 499 кодов ошибок nginx. Я вижу, что это проблема на стороне клиента. Это не проблема с Nginx или моим стеком uWSGI. Я отмечаю корреляцию в логах uWSGI, когда получаю 499.
address space usage: 383692800 bytes/365MB} {rss usage: 167038976
bytes/159MB} [pid: 16614|app: 0|req: 74184/222373] 74.125.191.16 ()
{36 vars in 481 bytes} [Fri Oct 19 10:07:07 2012] POST /bidder/ =>
generated 0 bytes in 8 msecs (HTTP/1.1 200) 1 headers in 59 bytes (1
switches on core 1760)
SIGPIPE: writing to a closed pipe/socket/fd (probably the client
disconnected) on request /bidder/ (ip 74.125.xxx.xxx) !!!
Fri Oct 19 10:07:07 2012 - write(): Broken pipe [proto/uwsgi.c line
143] during POST /bidder/ (74.125.xxx.xxx)
IOError: write error
Я ищу более подробное объяснение и надеюсь, что с моим конфигом nginx для uwsgi все в порядке. Я принимаю это по номиналу... это не проблема меня... это проблема клиента.
Спасибо
17 ответов
HTTP 499 в Nginx означает, что клиент закрыл соединение до того, как сервер ответил на запрос. По моему опыту это обычно вызвано тайм-аутом на стороне клиента. Как я знаю, это специфический код ошибки Nginx.
В моем случае я был нетерпелив и в итоге неправильно интерпретировал журнал.
На самом деле настоящей проблемой была связь между nginx и uwsgi, а не между браузером и nginx. Если бы я загрузил сайт в свой браузер и ждал достаточно долго, я бы получил "504 - Bad Gateway". Но это заняло так много времени, что я продолжал пробовать что-то, а потом обновлялся в браузере. Поэтому я никогда не ждал достаточно долго, чтобы увидеть ошибку 504. При обновлении в браузере закрывается предыдущий запрос, и Nginx записывает это в журнал как 499.
разработка
Здесь я предположу, что читатель знает так же мало, как и я, когда начал играть.
Моей настройкой был обратный прокси-сервер, сервер nginx и сервер приложений, сервер uWSGI, стоящий за ним. Все запросы от клиента будут отправляться на сервер nginx, затем перенаправляться на сервер uWSGI, а затем ответ отправляется таким же образом обратно. Я думаю, что так все используют nginx/uwsgi и должны его использовать.
Мой nginx работал как надо, но что-то не так с сервером uwsgi. Есть два способа (возможно, больше), при которых сервер uwsgi может не отвечать на сервер nginx.
1) uWSGI говорит: "Я обрабатываю, просто подожди, и ты скоро получишь ответ". У nginx есть определенный период времени, который он готов ждать, например, 20 секунд. После этого он ответит клиенту с ошибкой 504.
2) uWSGI мертв, или uWSGi умирает, пока nginx его ждет. Nginx видит это сразу и в этом случае возвращает ошибку 499.
Я проверял свои настройки, отправляя запросы в клиент (браузер). В браузере ничего не произошло, просто висело. Примерно через 10 секунд (меньше, чем время ожидания) я пришел к выводу, что что-то не так (что было правдой), и закрыл сервер uWSGI из командной строки. Затем я перехожу к настройкам uWSGI, пробую что-то новое и перезагружаю сервер uWSGI. В тот момент, когда я закрывал сервер uWSGI, сервер nginx выдаст ошибку 499.
Так что я продолжал отлаживать с ошибкой 499, что означает поиск ошибок 499. Но если бы я ждал достаточно долго, я бы получил ошибку 504. Если бы я получил ошибку 504, я смог бы лучше понять проблему, а затем отладить.
Таким образом, вывод заключается в том, что проблема была с uWGSI, который продолжал зависать ("Подожди немного дольше, просто немного дольше, тогда у меня будет ответ для тебя...").
Как я исправил эту проблему, я не помню. Я думаю, это может быть вызвано многими вещами.
Клиент закрыл соединение, это не значит, что это проблема браузера!? Не за что!
Вы можете найти 499 ошибок в файле журнала, если у вас есть LB (балансировщик нагрузки) перед вашим веб-сервером (nginx) либо AWS, либо haproxy (настраиваемый). Тем не менее, LB будет выступать в качестве клиента для nginx.
Если вы запустите haproxy по умолчанию для:
timeout client 60000
timeout server 60000
Это будет означать, что LB будет превышать 60000 мсек, если от nginx не будет ответа. Тайм-ауты могут случиться для загруженных веб-сайтов или сценариев, которым требуется больше времени для выполнения. Вам нужно будет найти тайм-аут, который будет работать для вас. Например, расширить его до:
timeout client 180s
timeout server 180s
И вы, вероятно, будете установлены.
В зависимости от вашей настройки вы можете увидеть ошибку тайм-аута 504 в вашем браузере, которая указывает, что что-то не так с php-fpm, но это не будет иметь место с 499 ошибками в ваших файлах журнала.
Как вы указываете 499
прерывание соединения, зарегистрированное nginx. Но обычно это происходит, когда ваш бэкэнд-сервер работает слишком медленно, и другие тайм-ауты прокси сначала или пользовательское программное обеспечение прерывает соединение. Поэтому проверьте, отвечает ли uWSGI быстро или нет, есть ли какая-либо нагрузка на сервер uWSGI / Database.
Во многих случаях есть некоторые другие прокси между пользователем и nginx. Некоторые из них могут находиться в вашей инфраструктуре, например, CDN, Load Balacer, кэш Varnish и т. Д. Другие могут быть на стороне пользователя, например, кеширующий прокси и т. Д.
Если на вашей стороне есть прокси-серверы, такие как LoadBalancer / CDN ... вы должны установить тайм-ауты для тайм-аута сначала вашего бэкенда и постепенно для других прокси для пользователя.
Если у вас есть:
user >>> CDN >>> Load Balancer >>> Nginx >>> uWSGI
Я рекомендую вам установить:
n
секунд до тайм-аута uSSGIn+1
время ожидания от секунд до nginx- `n+2'отправляет тайм-аут на балансировщик нагрузки
n+3
секунды тайм-аута в CDN.
Если вы не можете установить некоторые тайм-ауты (например, CDN), найдите его тайм-аут и настройте другие в соответствии с ним (n
, n-1
...).
Это обеспечивает правильную цепочку тайм-аутов. и вы действительно найдете чей тайм-аут и вернете правильный код ответа пользователю.
Оказывается, 499 действительно означает "соединение прервано клиентом".
У меня была настройка клиента "таймаут чтения" 60 секунд (и nginx также имеет значение proxy_read_timeout по умолчанию 60 секунд). Так что в моем случае происходило то, что nginx вызывал ошибку. Log anupstream timed out (110: Connection timed out) while reading upstream
а затем nginx повторяет попытку "следующего прокси-сервера в группе внутренних серверов, которую вы настроили". Это если у вас их больше одного.
Затем он пробует следующий и следующий, пока (по умолчанию) не исчерпает их всех. По мере истечения времени ожидания они также удаляются из списка "живых" внутренних серверов. После того, как все исчерпаны, он возвращает504 gateway timeout.
Итак, в моем случае nginx пометил сервер как "недоступный", повторно попробовал его на следующем сервере, затем мой клиент 60s
тайм-аут (немедленно) произошел, поэтому я бы увидел upstream timed out (110: Connection timed out) while reading upstream
log, сразу за которым следует журнал 499. Но это было совпадение во времени.
Связанные с:
Если все серверы в группе отмечены как недоступные в настоящее время, возвращается 502 Bad Gateway.
на 10 секунд. Смотрите здесь max_fails
и fail_timeout. В журналах будет сказаноno live upstreams while connecting to upstream.
Если у вас есть только один прокси-сервер в вашей группе серверов, он просто пробует использовать один сервер и возвращает 504 Gateway Time-out
и не удаляет отдельный сервер из списка "живых" серверов, если proxy_read_timeout
превзойден. См. Здесь "Если в группе только один сервер, параметры max_fails, fail_timeout и slow_start игнорируются, и такой сервер никогда не будет считаться недоступным".
По-настоящему сложная часть заключается в том, что если вы укажете proxy_pass как "localhost", и на вашем ящике будут одновременно присутствовать "версии местоположения" ipv6 и ipv4 (в большинстве ящиков это по умолчанию), он будет засчитан так, как если бы у вас были "список" нескольких серверов в вашей группе серверов, что означает, что вы можете попасть в описанную выше ситуацию, когда он вернет "502 за 10 секунд", даже если вы укажете только один сервер. См. Здесь "Если доменное имя разрешается по нескольким адресам, все они будут использоваться циклически". Один из способов решения этой проблемы - объявить его какproxy_pass http://127.0.0.1:5001;
(его ipv4 адрес), чтобы избежать его быть IPv4 и IPv6. Тогда это считается поведением "только один сервер".
Есть несколько различных настроек, которые вы можете настроить, чтобы сделать эту проблему "менее сложной". Например, увеличить таймауты или сделать так, чтобы серверы не помечались как "отключенные", когда они истекли... или исправление списка, чтобы он был только размером 1, см. Выше:)
См. Также: https://serverfault.com/a/783624/27813
В моем случае я получил 499, когда клиентский API закрыл соединение, прежде чем он получил какой-либо ответ. Буквально отправил POST и сразу же закрыл соединение. Это решается с помощью опции:
proxy_ignore_client_abort on
Эту ошибку довольно легко воспроизвести, используя стандартную конфигурацию nginx с php-fpm.
Удерживая кнопку F5 на странице, вы получите десятки запросов на обновление к серверу. Каждый предыдущий запрос отменяется браузером при новом обновлении. В моем случае я нашел десятки 499 в лог-файле интернет-магазина моего клиента. С точки зрения nginx: если ответ не был доставлен клиенту до следующего запроса на обновление, nginx регистрирует ошибку 499.
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:32 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:35 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:35 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
Если обработка php-fpm занимает больше времени (например, тяжелая WP-страница), это, конечно, может вызвать проблемы. Например, я слышал о сбоях php-fpm, но я считаю, что их можно предотвратить, настроив службы должным образом, например, обработку вызовов xmlrpc.php.
Я знаю, что это старый поток, но он точно соответствует тому, что недавно случилось со мной, и я подумал, что задокументирую его здесь. Настройка (в Docker) следующая:
- nginx_proxy
- nginx
- php_fpm запускает фактическое приложение.
Симптомом было "502 тайм-аут шлюза" в приглашении на вход в приложение. Обследование найденных журналов:
- кнопка работает через HTTP
POST
к/login
... так что... - nginx-proxy получил
/login
запрос и, в конце концов, сообщил о тайм-ауте. - nginx вернул
499
ответ, который, конечно же, означает "хост умер". - в
/login
запрос вообще (!) не появлялся в логах сервера FPM! - в FPM не было никаких трассировок или сообщений об ошибках... nada, zero, zippo, none.
Оказалось, что проблема заключалась в отказе подключиться к базе данных для проверки входа в систему. Но как это выяснить, оставалось только догадываться.
Полное отсутствие журналов отслеживания приложений... или даже записи о том, что запрос был получен FPM ... был для меня полной (и, что ужасно...) неожиданностью. Да, приложение должно регистрировать сбои, но в этом случае похоже, что рабочий процесс FPM умер из-за ошибки выполнения, что привело к499
ответ от nginx. Очевидно, это проблема в нашем приложении... где-то. Но я хотел записать подробности того, что произошло, для следующих людей, которые столкнутся с чем-то вроде этого.
Это не отвечает на вопрос OP, но поскольку я оказался здесь после яростных поисков ответа, я хотел поделиться тем, что мы обнаружили.
В нашем случае оказалось, что эти 499-е ожидаемые. Например, когда пользователи используют функцию опережающего ввода в некоторых окнах поиска, мы видим что-то подобное в журналах.
GET /api/search?q=h [Status 499]
GET /api/search?q=he [Status 499]
GET /api/search?q=hel [Status 499]
GET /api/search?q=hell [Status 499]
GET /api/search?q=hello [Status 200]
Так что в нашем случае я считаю его безопасным в использовании proxy_ignore_client_abort on
что было предложено в предыдущем ответе. Спасибо за это!
... пришел сюда из поиска Google
Я нашел ответ в другом месте здесь -> /questions/5481618/nginx-vyidaet-oshibku-http-499-cherez-60-sekund-nesmotrya-na-nastrojki-php-i-aws/5481620#5481620
что должно было увеличить время простоя соединения моего упругого распределителя нагрузки AWS!
(Я настроил сайт Django с обратным прокси-сервером nginx/apache, и действительно очень реальное задание / просмотр бэкэнда журнала истекло)
Как только я получил 499 "Запрос был запрещен антивирусом" в виде HTTP-ответа AJAX (ложное срабатывание Kaspersky Internet Security с легким эвристическим анализом, глубокий эвристический анализ понял, что в этом нет ничего плохого).
Мы также получали код ответа 499 в Production. Наш стек
- НГИНКС,
- Гуникорн
- Джанго
- Сельдерей (асинхронный)
- Сельдерейный брокер Redis.
- PostgreSQL
Проблема: наш API не возвращал ответ Gunicorn -> NGINX. Поскольку Redis был недоступен (загрузка данных), сельдерей передал запрос методу для разгрузки рабочей нагрузки от API и не вернул никакого ответа.
Как воспроизвести его в Django и другом стеке?
Не возвращайте никакого ответа от API.NGINX отправит клиенту код ответа 499.
Как мы это решили?
Мы проверили каждый компонент стека и наконец добрались до вызывающего компонента, которым оказался Redis. Мы прокомментировали
.delay()
(Этот метод использовал вызов метода Redis) и протестировал API, он работал нормально.
Это одна из возможных причин, по которой NGINX возвращает 499. Убедитесь, что ваш веб-фреймворк возвращает ответ или нет. Если он возвращает 200, проверьте настройки NGINX или клиентскую часть.
В моем случае я настроил как
AWS ELB >> ECS(nginx) >> ECS(php-fpm).
Я настроил неправильную группу безопасности AWS для службы ECS(php-fpm), поэтому Nginx не смог связаться с контейнером задач php-fpm. Вот почему я получал ошибки в журнале задач nginx
499 0 - elb-healthchecker/2.0
Проверка работоспособности была настроена так, чтобы проверять службу php-fpm, подтверждать ее работу и возвращать ответ.
Одной из причин такого поведения может быть то, что вы используете http
за uwsgi
вместо socket
, Используйте команду ниже, если вы используете uwsgi
непосредственно.
uwsgi --socket :8080 --module app-name.wsgi
Та же команда в.ini файле
chdir = /path/to/app/folder
socket = :8080
module = app-name.wsgi
Я столкнулся с этой проблемой, и причина была из-за плагина Kaspersky Protection в браузере. Если вы столкнулись с этим, попробуйте отключить ваши плагины и посмотреть, решит ли это вашу проблему.
Со своей стороны я включил ufw
но я забыл открыть свои восходящие порты._.
Во многих случаях возникает ошибка 499. Один из моих случаев - поле Content-Length пропущено в запросе http от клиента pocco.