Nginx 正在给 uWSGI 非常旧的请求?
Nginx is giving uWSGI very old requests?
我看到一个奇怪的情况,Nginx 或 uwsgi 似乎正在建立一个长长的传入请求队列,并在客户端连接超时后很长时间内尝试处理它们。我想理解并停止这种行为。这里有更多信息:
我的设置
我的服务器使用 Nginx 通过 Unix 文件套接字将 HTTPS POST 请求传递给 uWSGI 和 Flask。我基本上所有的默认配置。
我有一个 Python 客户端每秒向该服务器发送 3 个请求。
问题
在 运行 客户端大约 4 小时后,客户端机器开始报告所有连接都超时。 (它使用具有 7 秒超时的 Python 请求库。)大约 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 activity 停止。当我重新打开客户端时,Nginx 愉快地接受了 POST 请求,但是 uWSGI 在每个请求上都给出了相同的 "writing to a closed pipe" 错误,就好像它以某种方式永久损坏了一样。重新启动网络服务器的 docker 容器不能解决问题,但重新启动主机可以解决问题。
理论
在默认的Nginx -> socket -> uWSGI 配置中,是否有没有超时的长请求队列?我查看了 uWSGI 文档,看到了一堆可配置的超时,但所有超时都默认为 60 秒左右,所以我不明白我是如何看到 10 分钟前的请求被处理的。我没有更改任何默认超时设置。
该应用程序使用了我小型开发服务器中几乎所有的 1GB RAM,因此我认为资源限制可能会触发该行为。
无论哪种方式,我都想更改我的配置,以便超过 30 秒的请求因 500 错误而被丢弃,而不是被 uWSGI 处理。我将不胜感激关于如何做到这一点的任何建议,以及关于正在发生的事情的理论。
似乎对 Nginx uWSGI 的 DoS 攻击返回 100% CPU 使用 Nginx 502、504、500。IP 欺骗在 DoS 攻击中很常见。通过检查日志排除。
这似乎是 uWSGI 端的下游问题。
听起来您的后端代码可能有问题,因为它 takes too long 处理请求,没有对请求实施任何类型的速率限制,并且没有正确捕获任何底层连接已被终止(因此,您会收到您的代码试图写入已关闭管道的错误,甚至可能在基础连接终止很久之后才开始处理新请求)。
根据 http://lists.unbit.it/pipermail/uwsgi/2013-February/005362.html,您可能希望在后端 if not uwsgi.is_connected(uwsgi.connection_fd())
.
中止处理
您可能想探索 https://uwsgi-docs.readthedocs.io/en/latest/Options.html#harakiri。
作为最后的手段,根据 Re: Understanding "proxy_ignore_client_abort" functionality (2014), you might want to change uwsgi_ignore_client_abort
从 off
到 on
为了不丢弃已经传递到上游的正在进行的 uWSGI 连接(即使客户端随后确实断开连接)以便不从 uWSGI 接收到关闭的管道错误,以及在 nginx 本身内强制执行任何可能的并发连接限制(否则,如果客户端断开连接,到 uWSGI 的连接将被 nginx 丢弃,而 nginx 将不知道有多少请求在 uWSGI 中排队等待后续处理)。
我看到一个奇怪的情况,Nginx 或 uwsgi 似乎正在建立一个长长的传入请求队列,并在客户端连接超时后很长时间内尝试处理它们。我想理解并停止这种行为。这里有更多信息:
我的设置
我的服务器使用 Nginx 通过 Unix 文件套接字将 HTTPS POST 请求传递给 uWSGI 和 Flask。我基本上所有的默认配置。
我有一个 Python 客户端每秒向该服务器发送 3 个请求。
问题
在 运行 客户端大约 4 小时后,客户端机器开始报告所有连接都超时。 (它使用具有 7 秒超时的 Python 请求库。)大约 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 activity 停止。当我重新打开客户端时,Nginx 愉快地接受了 POST 请求,但是 uWSGI 在每个请求上都给出了相同的 "writing to a closed pipe" 错误,就好像它以某种方式永久损坏了一样。重新启动网络服务器的 docker 容器不能解决问题,但重新启动主机可以解决问题。
理论
在默认的Nginx -> socket -> uWSGI 配置中,是否有没有超时的长请求队列?我查看了 uWSGI 文档,看到了一堆可配置的超时,但所有超时都默认为 60 秒左右,所以我不明白我是如何看到 10 分钟前的请求被处理的。我没有更改任何默认超时设置。
该应用程序使用了我小型开发服务器中几乎所有的 1GB RAM,因此我认为资源限制可能会触发该行为。
无论哪种方式,我都想更改我的配置,以便超过 30 秒的请求因 500 错误而被丢弃,而不是被 uWSGI 处理。我将不胜感激关于如何做到这一点的任何建议,以及关于正在发生的事情的理论。
似乎对 Nginx uWSGI 的 DoS 攻击返回 100% CPU 使用 Nginx 502、504、500。IP 欺骗在 DoS 攻击中很常见。通过检查日志排除。
这似乎是 uWSGI 端的下游问题。
听起来您的后端代码可能有问题,因为它 takes too long 处理请求,没有对请求实施任何类型的速率限制,并且没有正确捕获任何底层连接已被终止(因此,您会收到您的代码试图写入已关闭管道的错误,甚至可能在基础连接终止很久之后才开始处理新请求)。
根据 http://lists.unbit.it/pipermail/uwsgi/2013-February/005362.html,您可能希望在后端
if not uwsgi.is_connected(uwsgi.connection_fd())
. 中止处理
您可能想探索 https://uwsgi-docs.readthedocs.io/en/latest/Options.html#harakiri。
作为最后的手段,根据 Re: Understanding "proxy_ignore_client_abort" functionality (2014), you might want to change
uwsgi_ignore_client_abort
从off
到on
为了不丢弃已经传递到上游的正在进行的 uWSGI 连接(即使客户端随后确实断开连接)以便不从 uWSGI 接收到关闭的管道错误,以及在 nginx 本身内强制执行任何可能的并发连接限制(否则,如果客户端断开连接,到 uWSGI 的连接将被 nginx 丢弃,而 nginx 将不知道有多少请求在 uWSGI 中排队等待后续处理)。