一个简单的http请求 怎么延迟这么大?
问题出在哪里:TCP协议有一个TCP_NODELAY 参数会引发延迟。
调用方使用 Apache HTTPClient tcpNoDelay 默认 true ,
被调用方使用HTTP服务,用的JDK自带的HttpServer 在ServerConfig 中发现 noDelay 默认 false
static { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { ServerConfig.idleInterval = Long.getLong("sun.net.httpserver.idleInterval", 30L) * 1000L; ServerConfig.clockTick = Integer.getInteger("sun.net.httpserver.clockTick", 10000); ServerConfig.maxIdleConnections = Integer.getInteger("sun.net.httpserver.maxIdleConnections", 200); ServerConfig.drainAmount = Long.getLong("sun.net.httpserver.drainAmount", 65536L); ServerConfig.maxReqHeaders = Integer.getInteger("sun.net.httpserver.maxReqHeaders", 200); ServerConfig.maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime", -1L); ServerConfig.maxRspTime = Long.getLong("sun.net.httpserver.maxRspTime", -1L); ServerConfig.timerMillis = Long.getLong("sun.net.httpserver.timerMillis", 1000L); ServerConfig.debug = Boolean.getBoolean("sun.net.httpserver.debug"); ServerConfig.noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay"); return null; } }); }
解决:后端HTTP服务,加上启动项“Dsun.net.httpserver.nodelay=true”参数,问题解决。
原因:
1.TCP_NODELAY 是什么?
在socket编程中,TCP_NODELAY是用来控制是否开启Nagle算法的。true 表示关闭 Nagle算法 false则表示打开。
2.Nagle算法是什么?
Nagle算法是一种通过减少发送网络数据包数量来提高TCP/IP网络效率的方法。
思路:如果一个请求很小1字节 发送这1字节有效数据的数据包需要40字的包头(IP头部20字节,TCP头部20字节),这种方式利用率很低。
Nagle做法:
如果发送内容大小>= 1MSS立刻发送 ,(MSS 为 TCP 数据包每次能够传输的最大数据分段)
如果之前的包没有被ACK 立即发送,
如果之前报被ACK 缓存发送部分,
如果收到ACK立刻发送缓存内容。
3.Delayed ACK是什么呢?
思路:TCP 为了保证传输的可靠性,规定接收到数据包时候向对方发送一个确认,只发送一个确认代价比较高 跟发1字节的请求一个道理。
TCP Delayed ACK(延迟确认) :将几个ACK组合在一起的单个响应,或者将ACK与响应数据一起发送给对方,从而减少协议开销。
具体做法:
当有响应数据发送时,ACK会随响应数据一起发送给对方。
如果没有响应数据,ACK将延迟发送,看是否有其他响应数据一起发送, linux上这个延迟是40ms.
如果等待发送ACK期间对方的第二个数据包又到达了,则立即发送ACK,这时如果第三个数据包相继到达 是否发送ACK 要看前两条
4.Nagle 和 Delayed ACK一起会发生什么?
A 使用Nagle B 使用Delayed ACK
A 向 B 发送一个包 由于B Delayed ACK 就等着 A再发 这时候 A 也在等着B返回ACK 导致白白等40ms。