- 浏览: 214363 次
- 性别:
- 来自: 深圳
-
文章分类
最新评论
-
jongde1:
Axure太难学了,分享mockplus工具,有兴趣可以去了解 ...
Axure RP 原型设计工具 -
di1984HIT:
这里面提到了好几种解决办法。
Spring AOP对日志记录、Exception日志记录 -
di1984HIT:
学习一下。
spring struts2 零配置 -
di1984HIT:
不错,不错啊
Struts2防止表单重复提交 -
di1984HIT:
kettle怎么样啊。
Kettle初探
网络编程中Nagle算法和Delayed ACK的测试
Nagle算法的立意是良好的,避免网络中充塞小封包,提高网络的利用率。但是当Nagle算法遇到delayed ACK悲剧就发生了。Delayed ACK的本意也是为了提高TCP性能,跟应答数据捎带上ACK,同时避免糊涂窗口综合症,也可以一个ack确认多个段来节省开销。
悲剧发生在这种情况,假设一端发送数据并等待另一端应答,协议上分为头部和数据,发送的时候不幸地选择了write-write,然后再read,也就是先发送头部,再发送数据,最后等待应答。发送端的伪代码是这样
接收端的处理代码类似这样:
writev是系统调用,在Java里是用到GatheringByteChannel.write(ByteBuffer[] srcs, int offset, int length)方法来做聚集写。这里可能还有一点值的提下,很多同学看java nio框架几乎都不用这个writev调用,这是有原因的。主要是因为Java的write本身对ByteBuffer有做临时缓存,而writev没有做缓存,导致测试来看write反而比writev更高效,因此通常会更推荐用户将head和body放到同一个Buffer里来避免调用writev。
下面我们将做个实际的代码测试来结束讨论。这个例子很简单,客户端发送一行数据到服务器,服务器简单地将这行数据返回。客户端发送的时候可以选择分两次发,还是一次发送。分两次发就是write-write-read,一次发就是write-read-write-read,可以看看两种形式下延迟的差异。注意,在windows上测试下面的代码,客户端和服务器必须分在两台机器上,似乎winsock对loopback连接的处理不一样。
服务器源码:
服务端绑定到本地8000端口,并监听连接,连上来的时候就阻塞读取一行数据,并将数据返回给客户端。
客户端代码:
客户端通过一个writeSplit变量来控制是否分开写head和body,如果为true,则先写head再写body,否则将head加上body一次写入。客户端的逻辑也很简单,连上服务器,发送一行,等待应答并打印RTT,循环10次最后关闭连接。
首先,我们将writeSplit设置为true,也就是分两次写入一行,在我本机测试的结果,我的机器是ubuntu 11.10:
可以看到,每次请求到应答的时间间隔都在40ms,除了第一次。linux的delayed ack是40ms,而不是原来以为的200ms。第一次立即ACK,似乎跟linux的quickack mode有关,这里我不是特别清楚,有比较清楚的同学请指教。
接下来,我们还是将writeSplit设置为true,但是客户端禁用nagle算法,也就是客户端代码在connect之前加上一行:
再跑下测试:
这时候就正常多了,大部分RTT时间都在1毫秒以下。果然禁用Nagle算法可以解决延迟问题。
如果我们不禁用nagle算法,而将writeSplit设置为false,也就是将head和body一次写入,再次运行测试(记的将setTcpNoDelay这行删除):
结果跟禁用nagle算法的效果类似。既然这样,我们还有什么理由一定要禁用nagle算法呢?通过我在xmemcached的压测中的测试,启用nagle算法在小数据的存取上甚至有一定的效率优势,memcached协议本身就是个连续的请求应答的模型。上面的测试如果在 windows上跑,会发现RTT最大会在200ms以上,可见winsock的delayed ack超时是200ms。
最后一个问题,什么情况下才应该禁用nagle算法?当你的应用不是这种连续的请求——应答模型,而是需要实时地单向发送很多小数据的时候或者请求是有间隔的,则应该禁用nagle算法来提高响应性。一个最明显是例子是telnet应用,你总是希望敲入一行数据后能立即发送给服务器,然后马上看到应答,而不是说我要连续敲入很多命令或者等待200ms才能看到应答。
上面是我对nagle算法和delayed ack的理解和测试,有错误的地方请不吝赐教。
转载:http://www.iteye.com/topic/1110883
Nagle算法的立意是良好的,避免网络中充塞小封包,提高网络的利用率。但是当Nagle算法遇到delayed ACK悲剧就发生了。Delayed ACK的本意也是为了提高TCP性能,跟应答数据捎带上ACK,同时避免糊涂窗口综合症,也可以一个ack确认多个段来节省开销。
悲剧发生在这种情况,假设一端发送数据并等待另一端应答,协议上分为头部和数据,发送的时候不幸地选择了write-write,然后再read,也就是先发送头部,再发送数据,最后等待应答。发送端的伪代码是这样
write(head); write(body); read(response);
接收端的处理代码类似这样:
read(request); process(request); write(response);
writev是系统调用,在Java里是用到GatheringByteChannel.write(ByteBuffer[] srcs, int offset, int length)方法来做聚集写。这里可能还有一点值的提下,很多同学看java nio框架几乎都不用这个writev调用,这是有原因的。主要是因为Java的write本身对ByteBuffer有做临时缓存,而writev没有做缓存,导致测试来看write反而比writev更高效,因此通常会更推荐用户将head和body放到同一个Buffer里来避免调用writev。
下面我们将做个实际的代码测试来结束讨论。这个例子很简单,客户端发送一行数据到服务器,服务器简单地将这行数据返回。客户端发送的时候可以选择分两次发,还是一次发送。分两次发就是write-write-read,一次发就是write-read-write-read,可以看看两种形式下延迟的差异。注意,在windows上测试下面的代码,客户端和服务器必须分在两台机器上,似乎winsock对loopback连接的处理不一样。
服务器源码:
package net.fnil.nagle; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress(8000)); System.out.println("Server startup at 8000"); for (;;) { Socket socket = serverSocket.accept(); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); while (true) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = reader.readLine(); out.write((line + "\r\n").getBytes()); } catch (Exception e) { break; } } } } }
服务端绑定到本地8000端口,并监听连接,连上来的时候就阻塞读取一行数据,并将数据返回给客户端。
客户端代码:
public static void main(String[] args) throws Exception { // 是否分开写head和body boolean writeSplit = false; String host = "localhost"; if (args.length >= 1) { host = args[0]; } if (args.length >= 2) { writeSplit = Boolean.valueOf(args[1]); } System.out.println("WriteSplit:" + writeSplit); Socket socket = new Socket(); socket.connect(new InetSocketAddress(host, 8000)); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String head = "hello "; String body = "world\r\n"; for (int i = 0; i < 10; i++) { long label = System.currentTimeMillis(); if (writeSplit) { out.write(head.getBytes()); out.write(body.getBytes()); } else { out.write((head + body).getBytes()); } String line = reader.readLine(); System.out.println("RTT:" + (System.currentTimeMillis() - label) + " ,receive:" + line); } in.close(); out.close(); socket.close(); } }
客户端通过一个writeSplit变量来控制是否分开写head和body,如果为true,则先写head再写body,否则将head加上body一次写入。客户端的逻辑也很简单,连上服务器,发送一行,等待应答并打印RTT,循环10次最后关闭连接。
首先,我们将writeSplit设置为true,也就是分两次写入一行,在我本机测试的结果,我的机器是ubuntu 11.10:
WriteSplit:true RTT:8 ,receive:hello world RTT:40 ,receive:hello world RTT:40 ,receive:hello world RTT:40 ,receive:hello world RTT:39 ,receive:hello world RTT:40 ,receive:hello world RTT:40 ,receive:hello world RTT:40 ,receive:hello world RTT:40 ,receive:hello world RTT:40 ,receive:hello world
可以看到,每次请求到应答的时间间隔都在40ms,除了第一次。linux的delayed ack是40ms,而不是原来以为的200ms。第一次立即ACK,似乎跟linux的quickack mode有关,这里我不是特别清楚,有比较清楚的同学请指教。
接下来,我们还是将writeSplit设置为true,但是客户端禁用nagle算法,也就是客户端代码在connect之前加上一行:
Socket socket = new Socket(); socket.setTcpNoDelay(true); socket.connect(new InetSocketAddress(host, 8000));
再跑下测试:
WriteSplit:true RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:1 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world
这时候就正常多了,大部分RTT时间都在1毫秒以下。果然禁用Nagle算法可以解决延迟问题。
如果我们不禁用nagle算法,而将writeSplit设置为false,也就是将head和body一次写入,再次运行测试(记的将setTcpNoDelay这行删除):
WriteSplit:false RTT:7 ,receive:hello world RTT:1 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world RTT:0 ,receive:hello world
结果跟禁用nagle算法的效果类似。既然这样,我们还有什么理由一定要禁用nagle算法呢?通过我在xmemcached的压测中的测试,启用nagle算法在小数据的存取上甚至有一定的效率优势,memcached协议本身就是个连续的请求应答的模型。上面的测试如果在 windows上跑,会发现RTT最大会在200ms以上,可见winsock的delayed ack超时是200ms。
最后一个问题,什么情况下才应该禁用nagle算法?当你的应用不是这种连续的请求——应答模型,而是需要实时地单向发送很多小数据的时候或者请求是有间隔的,则应该禁用nagle算法来提高响应性。一个最明显是例子是telnet应用,你总是希望敲入一行数据后能立即发送给服务器,然后马上看到应答,而不是说我要连续敲入很多命令或者等待200ms才能看到应答。
上面是我对nagle算法和delayed ack的理解和测试,有错误的地方请不吝赐教。
转载:http://www.iteye.com/topic/1110883
发表评论
-
Linux下部署多个Tomcat多个域名
2015-12-12 19:02 3704一、安装JDK 1、安装jdk-7u79-linux-x64. ... -
linux下安装swftools和openOffice
2015-07-03 17:09 757最近公司实现一个仿豆丁网百度文库阅读器的功能,需要用到两个软件 ... -
redis Java develop
2014-10-23 18:01 6671. http://javacrazyer.iteye.com ... -
验证码 原理 破解
2014-08-20 17:52 635验证码 原理 破解 reference: http://bl ... -
HttpClient 学习经验
2014-08-14 11:01 692HttpClient学习经验 HttpCl ... -
P2P resources
2013-12-09 18:24 9881.P2P导航收录 http://www.p2peye.com ... -
运用加密技术保护Java源代码
2013-06-08 08:38 1131运用加密技术保护Java源代码 http://www.ibm ... -
log4j.properties配置详解
2013-03-15 17:00 0log4j.properties配置详解 Log4J的配置文 ... -
Struts 2 studing
2012-12-28 17:28 7461. Struts 2的基石——拦截器(Interceptor ... -
J2EE项目异常处理
2012-12-26 11:08 1130J2EE项目异常处理 为什 ... -
如何将基于 Struts、Spring 和 Hibernate 的应用从 Tomcat 迁移到 WebSphere Application Server
2012-12-21 10:28 1228引言 现在很多的企业都 ... -
详解spring事务属性
2012-12-20 10:22 854Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我 ... -
Java List Copy,Remove容易出现的问题
2012-11-15 03:08 1057懒程序员,在代码越写越多的情况下,总想着使用把代码精简一 ... -
MySQL---ORACLE序列解决方案
2012-11-13 00:55 1208MySQL自增长与Oracle序列的区别: 自增长只能用于表 ... -
使用反射循环查找所有父类属性
2012-11-02 01:28 2146使用反射循环查找所有父类属性 ... -
list,set,map,数组间的相互转换
2012-11-02 01:25 968list,set,map,数 ... -
java bean自动进行rowMapper or handler的类
2012-10-20 03:14 1353一般情况下在进行jdbc编程的时候避免不了的要写n多的bean ... -
URL encoding 乱码处理
2012-10-10 15:53 900搞了两三天的乱码处理,试了很多方法,过滤器啊,编码转换啊,试来 ... -
JAVA 按任意角度旋转图片,并生成新的旋转后图片
2012-07-11 11:03 3700JAVA 按任意角度旋转图片,并生成新的旋转 ... -
QR Code
2012-06-12 12:29 01. 在线生成QR Code 网站 http://www. ...
相关推荐
但当Nagle算法和delayed ACK相遇时,可能会出现一种被称为“头部-主体”阻塞的情况。 例如,在上述实验模型中,发送端先发送头部数据,然后是主体数据,接着等待接收端的应答。接收端收到头部后,由于主体数据尚未...
19、延迟确认(delayed ack) 20、拥塞控制 21、HTTP 协议基础 22、HTTP2 协议基础篇 23、HTTP2 协议进阶篇 24、Wireshark 抓取 HTTPS 包的 N 种方法 25、Select、Epoll 底层原理(上) 26、Select、Epoll 底层原理...
- Nagle算法:用于减少发送小数据包的数量,通过缓冲区数据来合并为较大的数据包进行传输。 - 延迟应答(Delayed ACK)机制:接收方延迟发送ACK以减少ACK包的数量,提高网络效率。 网络协议分析的重点总结在于...
Nagle算法在一些场景下的确能提高网络利用率、降低包处理(客户端或服务器)主机资源消耗并且工作得很好,但是在某些场景下却又弊大于利,要说清楚这个问题需要引入另一个概念,即延迟确认(Delayed ACK)。
- Nagle算法:为了减少网络中的小数据包,TCP可能会合并多个小的数据段,只在缓冲区达到一定大小或达到特定时间间隔时才发送。 - Delayed ACK(延迟确认):为了减少网络开销,TCP可能延迟发送确认,直到有数据需要...
- **Nagle算法**:鼓励发送小的数据块,减少网络中的小碎片,提高效率。 - **延迟确认(Delayed ACK)**:为了节省带宽,接收方可能会等待一段时间再发送ACK,而不是立即发送。 6. **TCP的异常处理**: - **超时...
最后,考虑到性能,TCP的缓冲区管理和Nagle算法、TCP的延迟确认(Delayed ACK)、SO_REUSEADDR选项、SO_LINGER选项以及非阻塞I/O(O_NONBLOCK标志)等都是优化网络通信效率的关键点。 通过深入学习这些概念并实践书...
此外,Nagle算法和延迟数据发送(TCP DELAYED ACK)的使用也需要根据具体场景来考虑。 七、进程与线程管理 理解进程和线程的创建、调度、同步和通信机制,对于优化多线程程序至关重要。合理设计线程池、使用锁和...
- **延迟确认计时器 (Delayed Ack Timer)**:用于控制确认消息的发送频率。 #### 问题 5-11:TCP 和 UDP 是否都需要计算往返时间 RTT? **解答要点:** - **TCP** 需要计算 RTT 来调整重传计时器和拥塞窗口大小。 -...