【发布时间】:2012-12-15 03:39:12
【问题描述】:
我正在尝试让我正在编写的 HTTP 服务器在负载过重时表现良好,但我遇到了一些我不太理解的奇怪行为。
我的测试包括在并发级别为 1000 (ab -n 50000 -c 1000 http://localhost:8080/apa) 的环回接口上使用 ab(Apache 基准程序),同时跟踪服务器进程。 Strace 既能很好地减慢处理速度,使问题很容易重现,也能让我在某种程度上调试服务器内部完成后的工作。我还在测试运行时使用tcpdump 捕获网络流量。
发生的情况是ab 在测试中停止运行一段时间,并抱怨连接返回了ECONNRESET,我觉得这有点奇怪。我可以很容易地接受连接超时,因为服务器可能根本没有带宽来处理它们,但是如果不是所有连接都可以接受,那不应该合理地返回 ETIMEDOUT 甚至 ECONNREFUSED 吗?
我使用Wireshark提取构成第一个连接的数据包返回ECONNRESET,它的简要数据包列表如下所示:
(此连接的整个tcpdump 文件可用here。)
从这个转储中可以看到,连接被接受(经过几次SYN重传),然后请求被重传几次,然后服务器重置连接。我想知道,什么可能导致这种情况发生?通常,Linux 的 TCP 实现会在读取过程之前 ACK 数据,甚至选择接收数据,只要它们在 TCP 窗口中有空间,那么这里为什么不这样做呢?是否有某种共享缓冲区快用完了?最重要的是,为什么内核会突然响应RST 数据包,而不是简单地等待并让客户端进一步重新传输?
为了记录,进程的 strace 表明它甚至从不接受来自此连接中的端口(端口 56946)的连接,所以这似乎是 Linux 自己做的事情。还值得注意的是,只要 ab 的并发级别足够低,服务器就可以很好地工作(它可以很好地工作到大约 100,然后在 100-500 之间的某个地方开始间歇性失败),并且它的请求吞吐量是相当恒定的无论并发级别如何(只要不被跟踪,它每秒处理 6000-7000 个请求)。我没有发现问题发生的频率与我的积压设置为listen() 之间有任何特定的相关性(我目前使用的是 128,但我尝试了高达 1024 似乎没有任何区别)。
以防万一,我在这个 AMD64 机器上运行 Linux 3.2.0。
【问题讨论】:
标签: linux http networking tcp load-testing