Nginx 反向代理到 Django 接收“上游从上游读取响应标头时过早关闭的连接”

Joh*_*ell 4 django nginx python-2.x

长话短说

当 Nginxupstream prematurely closed connection while reading response header from upstream尝试通过 HTTP 反向代理到本地 Django 实例(没有 WSGI 中间件)时记录日志时,会发生什么 http/tcp 现象?

长版

冒着激怒社区的风险,我不会包含任何配置,因为虽然我确信它是相关的,但我正在尝试理解这种现象背后的理论。

我和一些队友维护一个网络服务器供内部使用。在/我们的内部工具世界中,事物永远不会产品化。我们通常会尽一切努力为我们的同事提供一些价值。风险和可用资源都很低。

因此,我们在独立建立 Python 2 Django 服务器时犯了一个大罪。没有 WSGI 中间件,没有额外的进程。我已经看到了警告,但我们已经做了我们已经做的事情。

我最近在这个令人讨厌的东西面前建立了一个 Nginx 实例,使我们能够以零停机时间“热交换”我们的 Web 应用程序实例。我仍然没有在中间插入任何东西。Nginx 只是反向代理,通过本地主机 http 到侦听本地主机非标准端口的 Django 实例。

进行此更改后,我们开始看到来自 Nginx 的 502 突发。有几个页面是“实时”的,因为它们会进行一些轮询来检查事物的更新。因此,对于我们拥有的用户数量来说,有“大量”的流量。

我实际上认为无论什么问题在引入 Nginx 之前就已经存在了,但是由于浏览器直接收到错误,它只是重试并且用户看不到问题,而现在他们收到了丑陋的 502 错误消息。

现在的问题是:如果我在 Nginx error.log 中看到upstream prematurely closed connection while reading response header from upstream这实际上意味着什么?我在这个网站上看到了很多关于配置更改建议的线程,这些建议似乎都不适合我,但我正在寻找的是理论。

这个错误是什么意思?当 Nginx 尝试将请求代理给 Django 时,它到底经历了什么?Django 拒绝连接吗?Django 会在连接完成之前关闭连接吗?

如果 Django 正在做这些事情,为什么?是否内存不足、线程不足、是否有某种原因限制线程数量等?

作为临时的周末修复的盲目尝试,我建立了应用程序的第二个实例,并将 Nginx 配置为对它们进行循环负载平衡。它似乎有效,但直到周一早上高峰负载到来时我才能确定。

第二个实例位于同一机器上,因此不能有任何额外的系统资源。Python 解释器实例中是否存在某些资源即将耗尽,因此创建第二个实例可以为我提供“两倍”的容量?

我真的想在这里学习一些有价值的东西,而不仅仅是“投入更多资源!”

任何帮助,将不胜感激。提前致谢!

更新

菲利普,非常感谢您的详尽回答!一个简单的问题来锁定我的理解......

如果我的上游 Python 服务器“无法并行处理足够的请求并阻塞”,这可能是什么原因。我认为这是一个单一的过程,因此可以简化问题。什么资源会耗尽?服务器是否可能只是以它可以容纳的任何速度读取套接字?什么样的系统/服务器配置将决定它一次可以处理的正在进行的请求的数量?我仔细检查了一遍,没有找到任何显式的 Django(Python 服务器库)配置选项,这些选项会人为地限制其响应能力。我当然可以承受额外的资源,但如果这更多的是系统限制,那么我不会期望同一个盒子上的另一个实例做任何事情(这就是我现在所期望的,因为第二个实例开始在周末)。我想在这里一劳永逸地做出一个深思熟虑的决定。

再次感谢您(或其他人)的帮助!

更新2

根本问题(周一早上我一上来,一位精通 Linux 内核的同事向我描述的)是监听队列深度。

正是这种结构的能力受到限制。当进程侦听端口并且有新的连接尝试进入时(在建立连接之前),如果进程建立连接的速度比连接进来的速度慢,则侦听队列就会建立。

因此,这与内存或 CPU 无关(除非这些资源的短缺是连接建立缓慢的原因),而是对进程连接能力的限制。

我绝不是这方面的专家,但我所追求的正是这种结构,解释为什么给定进程突然决定(或操作系统决定)它将不再接受连接。

更多内容请阅读此处

再次感谢菲利普带领我走上正确的道路!

Phi*_*ßen 6

从上游读取响应标头时上游过早关闭连接

该错误肯定是在上游,这意味着在您的情况下,是与您的 Python 服务器的连接。502 表示从 Nginx 到其上游服务器之一的 TCP 连接已关闭(从 python 进程主动关闭,或在超时时由系统关闭)。

根据您的描述,Python 服务器可能无法并行和块处理足够的请求。只要你前面没有Nginx,你就不会注意到,也许只是请求很慢。有了 Nginx,情况就发生了变化,因为 Nginx 可以轻松处理大量请求,并且可能接受比其上游服务器(即您的 Python 服务器)可以跟上的更多请求。在这种情况下,上游服务器不会响应,最终套接字会关闭,这会迫使 Nginx 因 502(网关错误)而失败。

为了测试该理论,您可以比较向 Nginx 或直接向 Python 服务器发出多个请求时发生的情况。如果当您直接访问 Python 服务器时,请求被阻止并且服务速度变慢(但没有错误),但当您访问 Nginx 时,所有请求都立即被接受(但有些失败并显示 502),则可能是我所描述的情况。

在这种情况下,您可以尝试以下一些操作:

  • 确保 keep-alive 在 Nginx 上有效(无论如何这是一个好主意,并且应该限制对上游的并行请求的数量)。详细请看这个答案
  • (如果可能)更改Python服务器,以便它们可以处理更多并行请求
  • 确保服务器上的文件句柄没有用完,并监视系统上的 TPC 套接字数量(例如,使用sudo netstat -tulpan)。

我可能是错的,因为我在回答中做了很多猜测。尽管如此,我希望它能为您提供一些解决请求被关闭(或超时)原因的想法。