我正在尝试使用我正在编写的HTTP服务器,以便在负载很重的情况下表现良好,但是我得到了一些我不太理解的奇怪行为。
我的测试包括在并发级别为1000(ab
)的环回接口上使用ab -n 50000 -c 1000 http://localhost:8080/apa
(Apache基准程序),同时对服务器进程进行扫描。 Strace既可以减慢处理速度,又可以很容易地重现问题,并允许我在一定程度上调试服务器内部结构。我还在测试运行时使用tcpdump
捕获网络流量。
当ab
停止运行一段时间进入测试时,会抱怨连接返回ECONNRESET
,我发现有点奇怪。我可以很容易地购买连接超时,因为服务器可能根本没有带宽来处理所有连接,但如果不能接受所有连接,那么不应该合理地返回ETIMEDOUT
甚至ECONNREFUSED
?
我使用Wireshark提取构成第一个连接的数据包以返回ECONNRESET
,其简短的数据包列表如下所示:
(此连接的整个tcpdump
文件可用here。)
正如您从此转储中看到的那样,接受连接(在几次SYN
重新传输之后),然后重新发送请求几次,然后服务器重置连接。我想知道,是什么原因导致这种情况发生?通常,Linux的TCP实现在读取过程之前确认数据,即使它们是TCP窗口中的空间,也选择接收它,那么为什么不在这里做呢?是否有某种共享缓冲区用完了?最重要的是,为什么内核突然响应RST
数据包,而不是简单地等待并让客户端进一步重新传输?
对于记录,进程的strace表明它甚至从未接受来自此连接中的端口的连接(端口56946),因此这似乎是Linux本身所做的事情。值得注意的是,只要ab的并发级别足够低(它可以很好地工作到大约100,然后在100-500之间的间歇性地开始失败),并且其请求吞吐量相当恒定,服务器工作得非常好。无论并发级别如何(只要它没有被束缚,它每秒处理6000-7000个请求之间的某个位置)。我没有发现问题发生的频率与我的积压设置listen()
之间有任何特定的相关性(我目前使用的是128,但我已经尝试过1024但没有看起来有所作为)。< / p>
如果重要,我在这台AMD64机器上运行Linux 3.2.0。
答案 0 :(得分:0)
积压队列已填满:因此SYN
重新传输。
然后一个插槽可用:因此SYN/ACK
。
然后发送了GET,接着是四次重传,我无法解释。
然后服务器放弃并重置连接。
我怀疑您的服务器中存在并发或吞吐量问题,导致您无法快速接受连接。除了调用accept()并启动另一个线程来处理接受的套接字或者将作业排队到线程池之外,你应该有一个专门做什么的线程。然后,我会推测 Linux重置连接中的连接,这些连接位于积压队列中,并且正在接收I / O重试,但这只是猜测。