【发布时间】:2015-03-12 05:08:17
【问题描述】:
我正在构建一个 Web 服务器应用程序,该应用程序使用 HTTP 1.1 协议和分块传输编码,根据请求将不同大小的文件从服务器发送到客户端。
我正在使用 Java Sockets/ServerSockets 来处理连接。我正在使用从socket.getOutputStream() 获得的输出流向客户端发送数据。注意:我没有将套接字的输出流包装在 BufferedOutputStream 中。
(我正在使用chrome调试器来分析资源时序)
我看到的问题是,一个大小为 1285 字节的文件(加上标头和块编码)需要 50 毫秒以上的时间让 chrome 接收请求的第一个字节。 (Chrome 报告的 TTFB 约为 50 毫秒),然后是传输的快速剩余部分(1-2 毫秒)(总传输时间约为 52 毫秒)
但是如果我将文件的大小增加到 1286 字节,TTFB 会显着降低到约 1 毫秒。 (总传输时间 ~3ms)
我尝试在沿途的不同点强制flushOutputStream,包括在请求标头之后、在块之后,甚至在每个点尝试多次flush 调用只是为了好玩。
我的问题:为什么与任何大于或等于 1286 字节的文件相比,小文件的传输时间要长这么多?我可以做些什么来解决这个性能问题?
我的理论:尽管 Java 调用了 flush(),但底层套接字实现中的某些东西忽略了对 flush 底层套接字缓冲区的 Java 请求。
【问题讨论】:
-
这可能是因为你总是先测试小文件,然后测试大文件,它可能正在尝试建立连接,你可以换一种方式尝试(先发送大文件,然后发送小文件)稍后),看看你是否得到相同的结果?
-
我刚刚更新了问题以澄清这是一个 Web 服务器类型的应用程序,因此文件是在不同时间请求的。 chrome 调试器将连接开销拆分为图表的一个单独部分,因此我看到的等待时间不包括任何一个文件的任何连接开销。
-
我建议添加一个
BufferedOutputStream,并删除除最后一个之外的所有刷新,重要的指标不是第一个字节的时间,而是最后一个字节的时间。 -
我更新了问题以显示每个场景中的“总传输时间”。不幸的是,在混合中添加
BufferedOutputStream只会增加响应的额外延迟。因为在这种情况下,我既有本机套接字缓冲,也有 java 流缓冲。 -
就代码而言,只有一个
flush。其他东西只是为了测试。将尝试打开TCP_NODELAY。