2

下面的 HttpServer 程序在没有 HTTP keepalive 的情况下可以轻松处理 8000 个请求/秒,但在使用 keepalive 的情况下只能处理 22 个请求/秒。

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class HSTest {
    public static void main(String[] args) throws IOException {
        HttpServer hs = HttpServer.create(new InetSocketAddress(30006), 1000);
        hs.createContext("/", new HttpHandler() {
            public void handle(HttpExchange he) throws IOException {
                byte[] FILE = "xxxxx".getBytes();       
                he.sendResponseHeaders(200, FILE.length);           
                OutputStream os = he.getResponseBody();
                os.write(FILE);
                os.flush();
                he.close();
            }
        });
        hs.start();
    }
}

这是keepalive的样子:

带有 HTTP keepalive 的 Wireshark 屏幕截图

请注意数据包 6、12 和 17 的巨大延迟。在第一个数据包之后,它们总是略高于 40 毫秒。相反,没有keepalive一切都很好:

没有 HTTP keepalive 的 Wireshark 截图

在第一个毫秒结束之前,这是 3 个完整的请求!

我在 debian sid Linux amd64 上使用 OpenJDK 8,客户端和服务器都在同一台机器上,并通过 localhost 接口进行通信。为了测试,我使用ab -n 100000 -c 1 http://localhost:30006/(no keepalive) 和ab -n 100000 -c 1 -k http://localhost:30006/(keepalive),以及 curl 和 chromium(默认情况下都使用 keepalive)。

那么是什么导致了 HTTP keepalive 请求的 40 毫秒延迟,以及如何使我的服务器更快?

4

1 回答 1

4

就像评论中暗示的那样,我认为这里关注的主要原因是,要求 HTTP 吞吐量在单个连接上非常高是不“正常的”(无需调整默认设置)。如果您在允许多个客户端时会得到类似的灾难性数字(例如-c 100ab 的标志),那将是一个不同的问题。KeepAlive 总体上具有在每个连接一个线程的服务器上占用线程的效果。

我认为您所观察到的与 TCP_NODELAY (Nagle 算法)有关,可能伴随着“延迟确认”。就您永远不会被它击中的数据包数量而言,no keepalive 情况足够短。

https://eklitzke.org/the-caveats-of-tcp-nodelay特别提到了 Linux http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7068416上“最多 40 毫秒”的延迟 用于在基本 Java HTTP 服务器中启用 TCP_NODELAY 的 Java 属性。如果启用此标志,我很有信心您会看到不同的行为。

另一种方法是将延迟确认超时更改为不同于 40 毫秒的时间。参见例如https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_MRG/1.3/html/Realtime_Tuning_Guide/sect-Realtime_Tuning_Guide-General_System_Tuning-Reducing_the_TCP_delayed_ack_timeout.html

于 2017-02-24T10:10:14.847 回答