Возможная причина кодов ошибок NGINX 499

119

Я получаю много кодов ошибок 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 все в порядке. Я принимаю это за чистую монету. Похоже, проблема клиента.

Тампа
источник
Вы когда-нибудь находили решение этой проблемы? Я вижу ту же проблему с uWSGI и nginx.
Raj
1
Я получаю это, когда прерываю запрос jQuery ajax.
mpen 02 апр.'14
1
Я знаю, что это очень старый вопрос, но количество неуместных вопросов по SO ошеломляет. Это явно относится к SF.
Sosukodo

Ответы:

167

HTTP 499 в Nginx означает, что клиент закрыл соединение до того, как сервер ответил на запрос. По моему опыту, это обычно вызвано таймаутом на стороне клиента . Насколько я знаю, это специфический код ошибки Nginx.

mrbo
источник
1
В качестве особого случая я заметил, что иногда это происходит, когда конечный пользователь дважды нажимает кнопку отправки формы. Форма отправляется дважды, но клиент ожидает только одного ответа. Это можно обойти, отключив (хотя бы на несколько секунд) кнопки в JS при первом нажатии на них.
Антуан Пинсар
14
Важно отметить, что «клиент» на самом деле может быть прокси. Например, если вы используете балансировщик нагрузки, он может отменить запрос к серверу nginx из-за тайм-аута.
Брэд Кох,
Это происходит в моем приложении Angular, если пользователь закрывает вкладку и мои запросы API не выполняются.
Вивек Саураб,
Важно отметить, что это также может быть вызвано сервером ; если сервер слишком долго отвечает, клиент сдается.
ijoseph
78

В моем случае я был нетерпеливым и в итоге неправильно истолковал журнал.

Фактически, настоящая проблема заключалась во взаимодействии между nginx и uwsgi, а не между браузером и nginx. Если бы я загрузил сайт в свой браузер и достаточно долго ждал, я бы получил «504 - Bad Gateway». Но это заняло так много времени, что я продолжал пробовать разные вещи, а затем обновлялся в браузере. Поэтому я никогда не ждал достаточно долго, чтобы увидеть ошибку 504. При обновлении в браузере, то есть когда предыдущий запрос закрывается, и Nginx записывает это в журнал как 499.

разработка

Здесь я предполагаю, что читатель знает так же мало, как и я, когда начал экспериментировать.

Моя установка была обратным прокси, сервером nginx и сервером приложений, сервером uWSGI за ним. Все запросы от клиента будут поступать на сервер nginx, затем перенаправляются на сервер uWSGI, а затем ответ отправляется таким же образом обратно. Я думаю, что именно так все используют nginx / uwsgi и должны его использовать.

Мой nginx работал как надо, но что-то не так с сервером uwsgi. Есть два способа (а может и больше), при которых сервер uwsgi может не отвечать серверу nginx.

1) uWSGI говорит: «Я обрабатываю, просто подождите, и вы скоро получите ответ». У nginx есть определенный период времени, в течение которого он готов ждать, fx 20 секунд. После этого он ответит клиенту с ошибкой 504.

2) uWSGI мертв, или uWSGi умирает, пока nginx его ждет. nginx видит это сразу и в этом случае возвращает ошибку 499.

Я тестировал свою установку, делая запросы в клиенте (браузере). В браузере ничего не происходило, просто все зависало. Примерно через 10 секунд (меньше таймаута) я пришел к выводу, что что-то не так (что было правдой), и закрыл сервер uWSGI из командной строки. Затем я бы пошел в настройки uWSGI, попробовал что-то новое, а затем перезапустил сервер uWSGI. В тот момент, когда я закрою сервер uWSGI, сервер nginx вернет ошибку 499.

Поэтому я продолжил отладку с ошибкой 499, что означает поиск ошибки 499 в Google. Но если бы я подождал достаточно долго, то получил бы ошибку 504. Если бы я получил ошибку 504, я смог бы лучше понять проблему, а затем отладить.

Таким образом, можно сделать вывод, что проблема была в uWGSI, который продолжал зависать («Подождите еще немного, еще немного, тогда я дам вам ответ ...»).

Как я решил эту проблему, не помню. Думаю, это могло быть вызвано множеством причин.

Мадс Скьерн
источник
1
Как вы это решили? У меня такая же проблема, и я не могу определить причину.
Колин Николс
1
Я добавил уточнение, к сожалению, не думаю, что это решит вашу проблему.
Mads Skjern
1
Просто хотел сказать спасибо! У меня была точно такая же ситуация, и это поставило меня на правильный путь.
Аарон
3
@Shafiul: Моя разработка не объясняет, что вызвало проблему с uWSGI, а просто объясняет, что причиной была uWSGI (а не nginx). В разработке описаны симптомы и то, как я их неверно истолковал. Я понимаю ваше разочарование, но вы неправильно поняли суть моего ответа. Искренне.
Mads Skjern
2
Чрезвычайно полезный ответ, никогда не удаляйте! Эти концепции следует где-то конкретизировать в документации, вы окажете большую услугу, подробно объяснив, как она ведет себя иначе, чем это подразумевается в документации!
jerclarke
21

Клиент закрыл соединение, это не значит, что проблема в браузере !? Не за что!

Вы можете найти 499 ошибок в файле журнала, если у вас есть LB (балансировщик нагрузки) перед вашим веб-сервером (nginx) либо AWS, либо haproxy (custom). При этом LB будет действовать как клиент для nginx.

Если вы запустите значения по умолчанию haproxy для:

    timeout client  60000
    timeout server  60000

Это будет означать, что время ожидания LB истечет через 60000 мс, если от nginx не будет ответа. Тайм-ауты могут происходить для загруженных веб-сайтов или сценариев, которым требуется больше времени для выполнения. Вам нужно будет найти тайм-аут, который подойдет вам. Например, расширите его до:

    timeout client  180s
    timeout server  180s

И вы, вероятно, будете настроены.

В зависимости от ваших настроек вы можете увидеть ошибку тайм-аута шлюза 504 в вашем браузере, которая указывает на то, что что-то не так с php-fpm, но этого не будет с ошибками 499 в ваших файлах журнала.

МРКИ
источник
12

Когда вы указываете 499на прерывание соединения, регистрируемое файлом nginx. Но обычно это происходит, когда ваш внутренний сервер работает слишком медленно , и сначала истекает время ожидания другого прокси или когда пользовательское программное обеспечение прерывает соединение. Поэтому проверьте, быстро ли отвечает uWSGI или нет, есть ли нагрузка на сервер uWSGI / базы данных.

Во многих случаях между пользователем и nginx есть другие прокси. Некоторые из них могут быть в вашей инфраструктуре, например, CDN, Load Balacer, Varnish cache и т. Д. Другие могут быть на стороне пользователя, например, кэширующий прокси и т. Д.

Если на вашей стороне есть прокси, такие как LoadBalancer / CDN ... вы должны установить таймауты на таймаут сначала для вашего бэкэнда, а затем для других прокси для пользователя.

Если у вас есть:

user >>> CDN >>> Load Balancer >>> Nginx >>> uWSGI

Я рекомендую вам установить:

  • n секунд до тайм-аута uWSGI
  • n+1 секунд до тайм-аута nginx
  • n+2 секунд до тайм-аута для балансировщика нагрузки
  • n+3 секунд тайм-аута для CDN.

Если вы не можете установить некоторые тайм-ауты (например, CDN), найдите его тайм-аут и настройте остальные в соответствии с ним ( n, n-1...).

Это обеспечивает правильную цепочку тайм-аутов. и вы действительно обнаружите, кто дает тайм-аут и возвращает пользователю правильный код ответа.

Bartomeu
источник
8

В моем случае я получил 499, когда клиентский API закрыл соединение до того, как получил какой-либо ответ. Буквально отправил POST и сразу закрыл соединение. Это решается опцией:

proxy_ignore_client_abort на

Документ Nginx

DerSkythe
источник
3
Я не понимаю, как это помогает
Владимир Старков
Может это не твой случай? Клиент отправляет данные и не интересуется, что с ним будет и что будет в ответ. Но мое приложение должно обрабатывать данные. Без этой опции данные просто не успевают дойти до моего приложения.
DerSkythe 02
Спасибо. Точные симптомы и идеальное решение.
TTimo
Вау! Это почти то, что мне нужно. Единственное, что я бы добавил - это отправить ответ 200 на источник веб-перехватчика, прежде чем он закроет само соединение. В противном случае они, как правило, отключают веб-перехватчики и не отправляют их снова ... Могу ли я сделать это для выбранных URL-адресов?
пилат
1
Это не решает проблему того, что ваш клиент не получает ответа. Он устраняет только 499 ошибок в ваших журналах и заменяет их кодом состояния 200. Плохая идея делать это. Настоящее решение - сказать вашему клиенту увеличить время ожидания ...
marcinx
7

Оказывается, 499 действительно означает «соединение прервано клиентом».

У меня был тайм-аут чтения клиента 60 секунд (и nginx также имеет значение proxy_read_timeout по умолчанию 60 секунд). Итак, в моем случае происходило то, что nginx регистрировал ошибку, upstream 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журнал, за которым сразу же следует журнал 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

rogerdpack
источник
3

Эту ошибку довольно легко воспроизвести, используя стандартную конфигурацию 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.

Карвонен
источник
2

... попал сюда из поиска Google

Я нашел ответ в другом месте здесь -> https://stackoverflow.com/a/15621223/1093174

что должно было увеличить тайм-аут простоя соединения моего эластичного балансировщика нагрузки AWS!

(Я настроил сайт Django с обратным прокси-сервером nginx / apache, и действительно, действительно, действительно, задание / просмотр бэкэнд-журнала истекло)

Дэвид Лам
источник
1

Я знаю, что это старый поток, но он точно соответствует тому, что недавно случилось со мной, и я подумал, что задокументирую его здесь. Настройка (в Docker) следующая:

  • nginx_proxy
  • Nginx
  • php_fpm запускает фактическое приложение.

Симптомом было «502 тайм-аут шлюза» в приглашении на вход в приложение. Обследование найденных журналов:

  • кнопка работает через HTTP POSTна /login... и так ...
  • nginx-proxy получил /loginзапрос и в конце концов сообщил о тайм-ауте.
  • nginx вернул 499ответ, что, конечно же, означает «хост умер».
  • /loginзапрос не появлялся на всех (!) в журналах МПФ сервера!
  • в FPM не было никаких трассировок или сообщений об ошибках ... nada, zero, zippo, none.

Оказалось, что проблема заключалась в отказе подключиться к базе данных для проверки логина. Но как это выяснить, оставалось только догадываться.

Полное отсутствие журналов отслеживания приложений ... или даже записи о том, что запрос был получен FPM ... был для меня полной (и, что ужасно ...) неожиданностью. Да, приложение должно регистрировать сбои, но в этом случае похоже, что рабочий процесс FPM умер из-за ошибки времени выполнения, что привело к 499ответу от nginx. Очевидно, это проблема в нашем приложении ... где-то. Но я хотел записать подробности того, что произошло, для следующих людей, которые столкнутся с чем-то вроде этого.

Майк Робинсон
источник
0

Как только я получил 499 «Запрос был запрещен антивирусом» в качестве ответа AJAX http (ложное срабатывание Kaspersky Internet Security с легким эвристическим анализом, глубокий эвристический анализ правильно понял, что все в порядке).

TeeJay
источник
0

Я столкнулся с этой проблемой, и причина связана с плагином Kaspersky Protection в браузере. Если вы столкнулись с этим, попробуйте отключить плагины и посмотрите, решит ли это вашу проблему.

EGN
источник
0

Одной из причин такого поведения может быть вы используете httpдля uwsgiвместо socket. Используйте команду ниже, если вы используете uwsgiнапрямую.

uwsgi --socket :8080 --module app-name.wsgi

Та же команда в файле .ini

chdir = /path/to/app/folder
socket = :8080
module = app-name.wsgi
Пенки Суреш
источник
0

Это не отвечает на вопрос 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что было предложено в предыдущем ответе. Спасибо за это!

Рон ДеФулио
источник
0

Со своей стороны, я включил, ufwно забыл открыть свои восходящие порты ._.

Александр Добрикур
источник
0

В моем случае я настроил как

AWS ELB >> ECS(nginx) >> ECS(php-fpm).

Я настроил неправильную группу безопасности AWS для службы ECS (php-fpm), поэтому Nginx не смог связаться с контейнером задач php-fpm. Вот почему я получал ошибки в журнале задач nginx

499 0 - elb-healthchecker/2.0

Проверка работоспособности была настроена так, чтобы проверять службу php-fpm, подтверждать ее работу и возвращать ответ.

Пиюш Сонигра
источник