39

我们正在并行开发 Python Web 服务和客户端网站。当我们从客户端向服务发出 HTTP 请求时,一个调用会在 socket.py 中持续引发一个 socket.error,如下所示:

(104,'对等方重置连接')

当我用wireshark收听时,“好”和“坏”的反应看起来非常相似:

  • 由于 OAuth 标头的大小,请求被分成两个数据包。该服务使用 ACK 响应两者
  • 服务发送响应,每个标头一个数据包(HTTP/1.0 200 OK,然后是 Date 标头等)。客户端用 ACK 响应每个。
  • (好请求)服务器发送一个FIN、ACK。客户端以 FIN、ACK 响应。服务器响应 ACK。
  • (错误请求)服务器发送 RST、ACK,客户端不发送 TCP 响应,客户端引发 socket.error。

Web 服务和客户端都在运行 glibc-2.6.1 的 Gentoo Linux x86-64 机器上运行。我们在同一个 virtual_env 中使用 Python 2.5.2。

客户端是一个 Django 1.0.2 应用程序,它调用 httplib2 0.4.0 来发出请求。我们使用 OAuth 签名算法对请求进行签名,OAuth 令牌始终设置为空字符串。

该服务正在运行 Werkzeug 0.3.1,它使用 Python 的 wsgiref.simple_server。我通过 wsgiref.validator 运行 WSGI 应用程序,没有任何问题。

看起来这应该很容易调试,但是当我在服务端跟踪一个好的请求时,它看起来就像是错误的请求,在 socket._socketobject.close() 函数中,将委​​托方法变成了虚拟方法。当 send 或 sendto(不记得是哪个)方法被关闭时,发送 FIN 或 RST,客户端开始处理。

“对等连接重置”似乎将责任归咎于服务,但我也不信任 httplib2。客户有错吗?

** 进一步调试 - 看起来像 Linux 上的服务器 **

我有一台 MacBook,所以我尝试在一台上运行该服务,在另一台上运行客户端网站。Linux 客户端调用 OS X 服务器时没有错误 (FIN ACK)。OS X 客户端调用带有错误的 Linux 服务(RST ACK 和 (54, 'Connection reset by peer'))。因此,它看起来像是在 Linux 上运行的服务。是 x86_64 吗?一个糟糕的 glibc?wsgiref? 还在找...

** 进一步测试 - wsgiref 看起来很不稳定 **

我们已经使用 Apache 和 mod_wsgi 投入生产,并且连接重置已经消失。请参阅下面的答案,但我的建议是记录连接重置并重试。这将使您的服务器在开发模式下运行良好,并在生产中稳定运行。

4

4 回答 4

27

我遇到过这个问题。请参阅Python“对等连接重置”问题

您(很可能)遇到了基于 Python Global Interpreter Lock 的小时间问题。

您可以(有时)通过time.sleep(0.01)战略性放置来纠正此问题。

“在哪里?” 你问。打败我。这个想法是在客户端请求中和围绕客户端请求提供一些更好的线程并发性。尝试在发出请求之前将其放置,以便重置 GIL 并且 Python 解释器可以清除任何挂起的线程。

于 2008-12-20T22:18:15.750 回答
11

不要将 wsgiref 用于生产。使用 Apache 和 mod_wsgi 或其他东西。

我们继续看到这些连接重置,有时是频繁的,使用 wsgiref(werkzeug 测试服务器使用的后端,可能还有 Django 测试服务器等其他服务器)。我们的解决方案是记录错误,循环重试调用,并在十次失败后放弃。httplib2 尝试了两次,但我们需要更多。它们似乎也成束出现——增加 1 秒的睡眠时间可能会解决问题。

通过 Apache 和 mod_wsgi 运行时,我们从未见过连接重置。我不知道他们有什么不同,(也许他们只是掩盖了他们),但他们没有出现。

当我们向本地开发社区寻求帮助时,有人确认他们看到很多使用 wsgiref 的连接重置在生产服务器上消失了。那里有一个错误,但很难找到它。

于 2009-01-27T00:37:29.857 回答
3

通常情况下,如果您进行不逗留的关闭(即,如果尚未发送和确认数据可以被堆栈丢弃的数据),您将获得 RST;如果您允许关闭,您将获得正常的 FIN逗留(即关闭等待传输中的数据被确认)。

也许您需要做的就是将您的套接字设置为 linger,以便您消除在套接字上完成的非延迟关闭和 ACK 到达之间的竞争条件?

于 2008-12-21T12:44:18.997 回答
2

我遇到了同样的问题,但是使用发布到 nginx+uwsgi 后端的 python-requests 客户端上传一个非常大的文件。

最终的原因是后端对上传的最大文件大小的上限低于客户端尝试发送的上限。

该错误从未出现在我们的 uwsgi 日志中,因为此限制实际上是由 nginx 强加的。

提高 nginx 中的限制消除了错误。

于 2018-10-15T23:52:03.133 回答