Nginx 499错误代码

Tam*_*mpa 91 nginx http-headers uwsgi

我收到了很多499 nginx错误代码.我看到这是客户端问题.这不是Nginx或我的uWSGI堆栈的问题.我注意到当获得499时uWSGI日志中的相关性.

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
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个更深入的解释,并希望我的nginx配置为uwsgi没有任何问题.我正在接受它的面子价值......这不是我的问题......客户问题.

谢谢

小智 141

Nginx中的HTTP 499表示客户端在服务器应答请求之前关闭了连接.根据我的经验,通常是由客户端超时引起的.据我所知,这是一个Nginx特定的错误代码.

  • 重要的是要注意,“客户端”实际上可能是代理。例如,如果您使用的是负载均衡器,则可能由于超时而取消了对Nginx服务器的请求。 (4认同)
  • 需要注意的是,这也可能是由**服务器**引起的;如果服务器响应时间太长,客户端就会放弃。 (4认同)
  • 作为一种特殊情况,我注意到当最终用户双击表单提交按钮时有时会发生这种情况。表单发送了两次,但客户端只需要一个响应。这可以通过在 JS 中第一次点击按钮时禁用(至少几秒钟)来解决。 (3认同)
  • 如果用户关闭选项卡并且我的 API 请求未完成,它就会发生在我的 Angular APP 上。 (2认同)

Mad*_*ern 64

在我的情况下,我不耐烦,最终误解了日志.

实际上真正的问题是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错误.但如果我等了足够长的时间,我就会得到504错误.如果我得到504错误,我本来能够更好地理解问题,然后能够调试.

所以结论是,问题在于uWGSI,它一直悬挂着("再等一会儿,再多一点,然后我会为你找到答案......").

我怎么解决这个问题,我不记得了.我想这可能是由很多事情引起的.

  • @Shafiul:我的阐述没有解释导致uWSGI问题的原因,它只是解释了uWSGI是原因(而非nginx)。详细描述了症状以及我对这些症状的误解。我了解您的失望,但您误解了我回答的实质。真诚的 (3认同)
  • 非常有用的答案,永不删除!这些概念应该在文档中的某个地方充实,通过详细说明它的行为方式与文档所暗示的不同,您可以提供出色的服务! (3认同)

mrk*_*rki 18

客户关闭连接并不意味着它是一个浏览器问题!?一点也不!

如果在Web服务器(nginx)前面有一个LB(负载均衡器),可以在AWS或haproxy(自定义)中找到499个错误.这就是LB将充当nginx的客户端.

如果您运行haproxy默认值:

    timeout client  60000
    timeout server  60000
Run Code Online (Sandbox Code Playgroud)

这意味着如果没有来自nginx的响应,LB将在60000ms后超时.对于需要更多时间执行的繁忙网站或脚本,可能会发生超时.您需要找到适合您的超时.例如,将其扩展为:

    timeout client  180s
    timeout server  180s
Run Code Online (Sandbox Code Playgroud)

你可能会被设定.

根据您的设置,您可能会在浏览器中看到504网关超时错误,这表示php-fpm出现了问题,但日志文件中的499错误情况并非如此.

  • 非常感谢,你救了我的命:'(。我花了很多天来解决这个问题。我的问题与`haproxy`中的超时有关。我从来没有意识到这一点 (2认同)

小智 17

当您指向499由 nginx 记录的连接中止时。但通常这是在您的后端服务器太慢时产生的,并且另一个代理首先超时或用户软件中止连接。因此,请检查 uWSGI 是否快速响应,或者 uWSGI / 数据库服务器上是否有任何负载。

在许多情况下,用户和 nginx 之间还有一些其他代理。有些可以在你的基础设施中,比如 CDN、Load Balacer、Varnish 缓存等。其他可以在用户端,比如缓存代理等。

如果您身边有像 LoadBalancer / CDN 这样的代理……您应该将超时设置为首先超时您的后端,然后逐步将其他代理设置为用户。

如果你有:

user >>> CDN >>> Load Balancer >>> Nginx >>> uWSGI
Run Code Online (Sandbox Code Playgroud)

我会建议你设置:

  • n 到 uWSGI 超时的秒数
  • n+1 秒到 nginx 超时
  • n+2 发送超时到负载均衡器
  • n+3 CDN 的超时秒数。

如果您无法设置某些超时(如 CDN),请查找它的超时时间并根据它调整其他超时(nn-1...)。

这提供了正确的超时链。你会发现真的是谁给出了超时并将正确的响应代码返回给用户。


rog*_*ack 14

事实证明,499 确实意味着“客户端中断连接”。

我的客户端“读取超时”设置为 60 秒(并且 nginx 的默认 proxy_read_timeout 也为 60 秒)。所以在我的情况下发生的事情是 nginx 会 error.log 一个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.

如果您的服务器组中只有一个代理后端,它只会尝试使用一台服务器,并返回 a504 Gateway Time-out并且不会从“实时”服务器列表中删除单个服务器,如果proxy_read_timeout超过了。请参阅此处“如果组中只有一个服务器,则忽略 max_fails、fail_timeout 和 slow_start 参数,并且永远不会认为这样的服务器不可用。”

真正棘手的部分是,如果您将 proxy_pass 指定为“localhost”,并且您的盒子碰巧同时具有 ipv6 和 ipv4“位置版本”(大多数盒子默认情况下都这样做),它将被视为您拥有服务器组中多台服务器的“列表”,这意味着即使您只列出一台服务器,您也可以进入上述情况,即返回“502 for 10s” 。请参阅此处“如果域名解析为多个地址,则所有地址都将以循环方式使用。” 一种解决方法是将其声明为proxy_pass http://127.0.0.1:5001;(其 ipv4 地址)以避免它同时是 ipv6 和 ipv4。然后它算作“只有一台服务器”的行为。

您可以调整一些不同的设置来使这个问题“减少”。就像增加超时或设置超时一样,它不会在服务器超时时将其标记为“已禁用”……或修复列表使其只有大小 1,请参见上文:)

另见:https : //serverfault.com/a/783624/27813


小智 7

以我为例,当客户端的API在获得任何响应之前关闭连接时,我得到了499。从字面上发送一个POST,并立即关闭连接。这可以通过选项解决:

proxy_ignore_client_abort在

Nginx文档

  • 这并不能解决您的客户没有得到回复的问题。它只会消除日志中的 499 错误,并将其替换为状态代码 200。这样做是个坏主意。真正的解决方案是告诉您的客户增加超时设置...... (5认同)
  • 我不明白这有什么帮助 (4认同)

kar*_*nen 6

使用带有 php-fpm 的标准 nginx 配置很容易重现此错误。

在页面上按住 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)
Run Code Online (Sandbox Code Playgroud)

当然,如果 php-fpm 处理时间较长(例如沉重的 WP 页面),则可能会导致问题。例如,我听说过 php-fpm 崩溃,但我相信可以通过正确配置服务来阻止它们,例如处理对 xmlrpc.php 的调用。


Mik*_*son 6

我知道这是一个旧线程,但它与最近发生在我身上的事情完全匹配,我想我应该在这里记录它。设置(在 Docker 中)如下:

  • nginx_代理
  • nginx
  • php_fpm 运行实际的应用程序。

症状是应用程序登录提示上出现“502 网关超时”。检查日志发现:

  • 该按钮通过 HTTP 工作POST.../login等等...
  • nginx-proxy收到请求/login,最终报超时。
  • nginx 返回了一个499响应,这当然意味着“主机死亡”。
  • /login请求根本没有出现(!)在 FPM 服务器的日志中!
  • FPM 中没有回溯或错误消息……nada、零、zippo、无。

原来问题是连接数据库验证登录失败。但事实证明,如何弄清楚这一点纯粹是猜测。

完全没有应用程序回溯日志……甚至没有 FPM 收到请求的记录……对我来说是一个完整的(而且是毁灭性的……)惊喜。是的,应用程序应该记录失败,但在这种情况下,FPM 工作进程似乎因运行时错误而死亡,导致499nginx 做出响应。现在,这显然是我们的应用程序中的一个问题......某处。但我想记录下发生的事情的细节,以造福于接下来面临类似问题的人。

  • “nginx 返回了 499 响应,这当然意味着“主机死亡”。似乎不正确。应该是“nginx **记录** 499 响应,这意味着“客户端不再等待 nginx 了”。 (3认同)

Ron*_*lio 5

这并没有回答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]
Run Code Online (Sandbox Code Playgroud)

因此,在我们的例子中,我认为使用proxy_ignore_client_abort on之前的答案中建议的方法是安全的。感谢那!