我看到一个奇怪的情况,其中Nginx或uwsgi似乎正在建立一个长时间的请求队列,并在客户端连接超时后长时间尝试处理它们。我想了解并停止这种行为。以下是更多信息:
我的服务器使用Nginx通过Unix文件套接字将HTTPS POST请求传递给uWSGI和Flask。我基本上在所有东西上都使用默认配置。 我有一个Python客户端向服务器发送每秒钟3个请求。
在运行客户端约4小时后,客户端机器开始报告所有连接超时。(它使用Python请求库,并设置了7秒超时。)大约10分钟后,行为发生了变化:连接开始以502 Bad Gateway失败。
我关闭了客户端。但在关闭客户端后约10分钟,服务器端的uWSGI日志显示uWSGI仍然尝试响应来自该客户端的请求!而且top显示uWSGI使用100% CPU(每个工作进程使用25%)。
在那10分钟内,每个uwsgi.log条目都像这样: Thu May 25 07:36:37 2017 - SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request /api/polldata (ip 98.210.18.212) !!! Thu May 25 07:36:37 2017 - uwsgi_response_writev_headers_and_body_do(): Broken pipe [core/writer.c line 296] during POST /api/polldata (98.210.18.212) IOError: write error [pid: 34|app: 0|req: 645/12472] 98.210.18.212 () {42 vars in 588 bytes} [Thu May 25 07:36:08 2017] POST /api/polldata => generated 0 bytes in 28345 msecs (HTTP/1.1 200) 2 headers in 0 bytes (0 switches on core 0)
Nginx的error.log显示了很多这样的内容: 2017/05/25 08:10:29 [error] 36#36: *35037 connect() to unix:/srv/my_server/myproject.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 98.210.18.212, server: example.com, request: "POST /api/polldata HTTP/1.1", upstream: "uwsgi://unix:/srv/my_server/myproject.sock:", host: "example.com:5000"
大约10分钟后,uWSGI活动停止。当我重新启动客户端时,Nginx愉快地接受POST请求,但是uWSGI在每个请求上都会给出相同的“写入关闭的管道”错误,就好像它被永久性地破坏了一样。重启web服务器的docker容器无法解决问题,但重新启动主机可以解决问题。
理论:
在默认的Nginx-> socket-> uWSGI配置中,是否存在没有超时的请求长队列?我查看了uWSGI文档,并看到了一堆可配置的超时时间,但所有默认值都约为60秒左右,因此我无法理解为什么会处理10分钟前的请求。我没有更改任何默认的超时设置。
该应用程序在我的小型开发服务器上使用了几乎所有的1GB RAM,因此我认为资源限制可能会触发这种行为。
无论如何,我想更改我的配置,以便> 30秒的请求会因500错误而被丢弃,而不是被uWSGI处理。我希望能得到关于如何做到这一点的建议和对所发生情况的理论。
我的服务器使用Nginx通过Unix文件套接字将HTTPS POST请求传递给uWSGI和Flask。我基本上在所有东西上都使用默认配置。 我有一个Python客户端向服务器发送每秒钟3个请求。
在运行客户端约4小时后,客户端机器开始报告所有连接超时。(它使用Python请求库,并设置了7秒超时。)大约10分钟后,行为发生了变化:连接开始以502 Bad Gateway失败。
我关闭了客户端。但在关闭客户端后约10分钟,服务器端的uWSGI日志显示uWSGI仍然尝试响应来自该客户端的请求!而且top显示uWSGI使用100% CPU(每个工作进程使用25%)。
在那10分钟内,每个uwsgi.log条目都像这样: Thu May 25 07:36:37 2017 - SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request /api/polldata (ip 98.210.18.212) !!! Thu May 25 07:36:37 2017 - uwsgi_response_writev_headers_and_body_do(): Broken pipe [core/writer.c line 296] during POST /api/polldata (98.210.18.212) IOError: write error [pid: 34|app: 0|req: 645/12472] 98.210.18.212 () {42 vars in 588 bytes} [Thu May 25 07:36:08 2017] POST /api/polldata => generated 0 bytes in 28345 msecs (HTTP/1.1 200) 2 headers in 0 bytes (0 switches on core 0)
Nginx的error.log显示了很多这样的内容: 2017/05/25 08:10:29 [error] 36#36: *35037 connect() to unix:/srv/my_server/myproject.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 98.210.18.212, server: example.com, request: "POST /api/polldata HTTP/1.1", upstream: "uwsgi://unix:/srv/my_server/myproject.sock:", host: "example.com:5000"
大约10分钟后,uWSGI活动停止。当我重新启动客户端时,Nginx愉快地接受POST请求,但是uWSGI在每个请求上都会给出相同的“写入关闭的管道”错误,就好像它被永久性地破坏了一样。重启web服务器的docker容器无法解决问题,但重新启动主机可以解决问题。
理论:
在默认的Nginx-> socket-> uWSGI配置中,是否存在没有超时的请求长队列?我查看了uWSGI文档,并看到了一堆可配置的超时时间,但所有默认值都约为60秒左右,因此我无法理解为什么会处理10分钟前的请求。我没有更改任何默认的超时设置。
该应用程序在我的小型开发服务器上使用了几乎所有的1GB RAM,因此我认为资源限制可能会触发这种行为。
无论如何,我想更改我的配置,以便> 30秒的请求会因500错误而被丢弃,而不是被uWSGI处理。我希望能得到关于如何做到这一点的建议和对所发生情况的理论。
ignore_client_abort
设置很有趣;我会尝试一下。(harakiri设置并没有解决问题。) - Lukesiege
命令行工具来向我的开发服务器发送一堆请求,针对一个只是睡眠10秒然后返回的端点。结果发现,有人将uwsgi的最大队列长度调整得非常大。因此,uwsgi的工作进程一直在处理非常旧的请求(一旦请求进入uwsgi队列,nginx的连接超时不会将其移除)。解决方案是:1)缩短队列长度,2)让nginx为每个请求添加一个带有时间戳的头部,并添加Django中间件来丢弃旧的请求(立即返回400错误)。 - Luke