2

我正在尝试让我正在编写的 HTTP 服务器在重负载下表现良好,但是我遇到了一些我不太理解的奇怪行为。

我的测试包括ab在环回接口上以 1000 ( ) 的并发级别使用(Apache 基准程序)ab -n 50000 -c 1000 http://localhost:8080/apa,同时跟踪服务器进程。Strace 既能很好地减慢处理速度,让问题很容易重现,也能让我在某种程度上调试服务器内部完成后的工作。tcpdump我还在测试运行时捕获网络流量。

发生的事情是ab在测试中停止运行一段时间,抱怨连接返回ECONNRESET,我觉得这有点奇怪。我可以很容易地接受连接超时,因为服务器可能根本没有带宽来处理它们,但不应该合理地返回ETIMEDOUT,或者即使ECONNREFUSED不是所有连接都可以被接受?

我使用 Wireshark 提取构成第一个连接的数据包返回ECONNRESET,它的简要数据包列表如下所示:( 此连接数据包列表 的整个tcpdump文件可在此处获得。)

从这个转储中可以看到,连接被接受(在几次SYN重传之后),然后请求被重传几次,然后服务器重置连接。我想知道,什么可能导致这种情况发生?通常,Linux 的 TCP 实现会在读取过程之前 ACK 数据,甚至选择接收数据,只要它们在 TCP 窗口中有空间,那么这里为什么不这样做呢?是否有某种共享缓冲区快用完了?最重要的是,为什么内核RST会突然响应一个数据包,而不是简单地等待并让客户端进一步重新传输?

作为记录,进程的 strace 表明它甚至从不接受来自此连接中的端口(端口 56946)的连接,所以这似乎是 Linux 自己做的事情。还值得注意的是,只要 ab 的并发级别足够低,服务器就可以很好地工作(它可以很好地工作到大约 100,然后在 100-500 之间的某个地方开始间歇性失败),并且它的请求吞吐量是相当恒定的无论并发级别如何(只要不被跟踪,它每秒处理 6000-7000 个请求)。我没有发现问题发生的频率与我的积压设置之间有任何特定的相关性listen()(我目前使用的是 128,但我尝试了高达 1024 似乎没有任何区别)。

万一这很重要,我在这个 AMD64 机器上运行 Linux 3.2.0。

4

1 回答 1

0
  1. 积压队列已满:因此SYN重新传输。

  2. 然后一个插槽变得可用:因此SYN/ACK.

  3. 然后 GET 被发送,然后是四次重传,我无法解释。

  4. 然后服务器放弃并重置连接。

我怀疑您的服务器中存在并发或吞吐量问题,这会阻止您足够快地接受连接。您应该有一个线程专门用于调用 accept() 并启动另一个线程来处理接受的套接字,或者将作业排队以将其处理到线程池。然后,我推测Linux 会重置积压队列中的连接以及正在接收 I/O 重试的连接,但这只是一个猜测。

于 2012-12-31T05:59:30.797 回答