该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-07-02
Tcp/ip 协议第一卷里面对这一块有比较详细的说明。。。
|
|
返回顶楼 | |
发表时间:2011-07-02
最典型的两个应用场景是telnet和ftp的实现。
|
|
返回顶楼 | |
发表时间:2011-07-02
dennis_zane 写道 taolei0628 写道 taolei0628 写道 dennis_zane 写道 taolei0628 写道 用java Socket没有对Socket的OutputStream/InputStream直接操作的,前面都要封装个BufferedOutputStream/BufferedInputStream。
TCP Delay不过就是要解决小数据合并的问题,这个问题完全可以在java里自己解决,而且效果更好。 Socket的服务器编程里几乎一律关掉TCP Delay。 人家的内核里做的事情,你能在应用层做的更好?没开玩笑吧。我测试的结果也证明开启比不开启更好。 内核会根据各种因素做出判断是否立即发送数据,加上拥塞控制之类,nagle算法只是其中一个考虑因素。当然,应用层可以做的事情是每次发送尽量都以发送缓冲区的大小写入数据。 这里的例子是故意设计出来,看看nagle+delayed ack会造成什么后果,也告诉大家避免write-write-read这样的编程方式。 你也太迷信内核了吧。谁能掌握更多的细节信息,谁才能优化得更好,而不是内核就一定比应用更好。 Socket上是流化的数据,而实际通讯数据时要有分隔的。内核能知道数据流上哪里是一个完整的请求而需要立即发送,哪里不是完整的请求需要合并吗?内核只能靠猜测或适当的延时来合并数据,这势必会照成小数据块请求被拖延一定时间。而应用作为数据的发送者对这些细节最清楚,在需要合并的时候它自己合并,该需要立即发送的时候,也不会有延迟。 你测试的结果也可能测试程序本身需要靠tcp delay优化,自己并没有做关闭tcp delay后的优化。 再补充上面的问题,为什么文章作者提到JavaNIO没有那样的问题?socket内核里收发数据也区分socket是同步的还是异步的吗?我甚至不确定系统内核有没有线程的概念。 哦,我就是文章作者。NIO怎么会没有这样的问题,问题同样存在。 内核并不是靠猜测来决定是否合并数据,这完全有一套规则,你要不知道可以看TCP/IP卷一或者RFC。应用层的合并有好处,但不能替代nagle算法,事实上应用自己的合并并不会直接影响到内核的分片,应用能做的事情很有限,就是我刚才提到,以发送缓冲区的大小发送数据从而提高吞吐量。 人家协议栈考虑的因素比你全面,合并不合并自有一套规则,目的就是提高网络的利用率。当然,你要说你比搞TCP协议和协议栈实现的人牛叉,那我还能说啥? 另外,我的测试就是基于NIO,我文章里提了,就是以xmemcached这个实际应用做压测看到的结果。 你就是作者啊,首先还是感谢你分享知识。 你说人家协议栈考虑的问题比应用全面,这能说明什么呢? 你能证明吧tcp delay关了就不考率那些问题了吗? 你想想如果内核作者能把优化做到最好,为什么不问问那些内核作者为什么留给应用那么多配置参数可选择?为什么在你的内核里自动都优化了? 如果都认为内核能把优化都做好了,为什么那些应用(服务器)还要修改这些配置,甚至还要把这些配置参数再次暴露出来留给实际运行环境中再去调整? Socket性能优化是集中在如何利用好有限的网络资源上,应用程序效率再低也不会慢到比网络还慢,在哪里做优化并不能绝对的认为内核就一定比应用效率高,而是双方结合的事情。 怎样理解TCP上的数据流?你认为在TCP内核层次上可能知道在数据流上哪里是一个完整的请求需要立即发送,哪里是一个不完整的请求数据需要缓存合并? 先不论技术水平,如果你是个底层服务的作者,你需要考虑各种各样的应用特点和应用环境,但是(1)能把所有的应用需求和应用环境都考虑完整吗?(2)即使考虑完整了,能把这些问题都在底层服务这个层次都自动解决好吗?(3)有解决太多问题的必要吗?要解决太多的问题意味着大量的代码、更低的效率、和复杂的使用方式。 比较聪明的做法、事实上底层服务提供者也都是这么做的,定义各种配置参数留给应用自己选择,把这些配置参数的预设值设定在一个经过验证的满足普遍需求的水平上,而不能保证这些都是最优的。你想想那些所谓“XX优化大师”都经常排上用场,难道你就认为这些"XX优化大师"的作者们具备了写操作系统的水平? |
|
返回顶楼 | |
发表时间:2011-07-02
扯太远了,你说应用可以做的更好,那请给出数据,证明你能做的更好。当然,我文中已经提了,在某些场景下是需要禁止nagle算法,而大多数主动禁止nagle算法的地方都是误用,可以避免禁止这个选项来达到更好的效果。
至于我理解不理解tcp流,就不需要您操心了。就此打住。 |
|
返回顶楼 | |
发表时间:2011-07-02
dennis_zane 写道 扯太远了,你说应用可以做的更好,那请给出数据,证明你能做的更好。当然,我文中已经提了,在某些场景下是需要禁止nagle算法,而大多数主动禁止nagle算法的地方都是误用,可以避免禁止这个选项来达到更好的效果。
至于我理解不理解tcp流,就不需要您操心了。就此打住。 先不管应用系统能不能做到更好,但操作系统提供的功能及其配置一定不是最优的,它只是适合大部分普通应用场景。好在系统尽可能提供各种配置参数以及扩展、定制能力,让应用程序有机会优化。 |
|
返回顶楼 | |
发表时间:2011-07-03
dennis_zane 写道 扯太远了,你说应用可以做的更好,那请给出数据,证明你能做的更好。当然,我文中已经提了,在某些场景下是需要禁止nagle算法,而大多数主动禁止nagle算法的地方都是误用,可以避免禁止这个选项来达到更好的效果。
至于我理解不理解tcp流,就不需要您操心了。就此打住。 跟你扯近一点 什么情况下才应该禁用nagle算法?当你的应用不是这种连续的请求——应答模型,而是需要实时地单向发送很多小数据的时候或者请求是有间隔的,则应该禁用nagle算法来提高响应性。 这是你的原话。后面举了个例子说telnet需要禁用delay。你不会以为只有少数像telnet这样的应用应用才需要禁用delay吧? 什么叫连续的请求应答模型?请求发送完了不等待应答就发送下一个请求?这样的应用多吗?绝大部分应用要等待应答返回后根据应答结果再做出选择发送下一个请求的。如果开了delay,这200毫秒的延时意味着每秒最多有5次访问,这种蜗牛速度不是大部分应用能够接受的。 我们再说连续发送请求的情况。这种情况开delay是会有点儿用处。为什么说delay用处有限,那是因为即使是开了delay,也不应用就不需要创建自己的缓冲来合并成批的发送请求。前者比后者多出了N次的write操作,即使最终发送的数据都是合并发送的,先合并在write要比write N次在系统缓冲区里合并快得多。应用自己的缓冲只不过是个bytearray,而系统缓冲区得buffer可能会比bytearray重得多(不要再跟我说人家开发系统驱动的牛X到比我在java里写个bytearray要快),而且每次write还有经历java-jni,userenv-systemenv的两次转换/切换。换句话说,连续发送请求一样需要应用自己缓冲才会性能更好。这种情况下可以开delay,但既然应用已经自己缓冲了,delay能带来的效果是有限的。 你说大多数禁止nagle算法的地方都是误用。我不了解你工作的环境,你们那里的应用都是怎么写的。既然系统暴露这个TcpNoDelay参数给应用,应用同样也会把这个选择机会留给实际运行环境。但基于我上面说的,大多数应用会缺省地关闭delay。无论如何也谈不上误用,因为缺省参数是经过测试后设置的,如果实际环境开delay表现会好,那就打开,没有什么误用不误用的说法。应用(服务器)暴露那么多配置参数,就是给你调优用的。难道你们写的应用都是写死在程序里? |
|
返回顶楼 | |
发表时间:2011-07-03
最后修改:2011-07-03
taolei0628 写道 跟你扯近一点 什么情况下才应该禁用nagle算法?当你的应用不是这种连续的请求——应答模型,而是需要实时地单向发送很多小数据的时候或者请求是有间隔的,则应该禁用nagle算法来提高响应性。 这是你的原话。后面举了个例子说telnet需要禁用delay。你不会以为只有少数像telnet这样的应用应用才需要禁用delay吧? 什么叫连续的请求应答模型?请求发送完了不等待应答就发送下一个请求?这样的应用多吗?绝大部分应用要等待应答返回后根据应答结果再做出选择发送下一个请求的。如果开了delay,这200毫秒的延时意味着每秒最多有5次访问,这种蜗牛速度不是大部分应用能够接受的。 很惭愧地说,我们的应用大多数是这种应用,请求可以并发发送,人家HTTP都支持pipeline呢。如果要等应答返回再发送请求,那么请求完全是个串行的过程,这种协议设计从一开始就应该避免。我不知道这种应用有多少,可能你们那这种应用比较多。 taolei0628 写道 我们再说连续发送请求的情况。这种情况开delay是会有点儿用处。为什么说delay用处有限,那是因为即使是开了delay,也不应用就不需要创建自己的缓冲来合并成批的发送请求。前者比后者多出了N次的write操作,即使最终发送的数据都是合并发送的,先合并在write要比write N次在系统缓冲区里合并快得多。应用自己的缓冲只不过是个bytearray,而系统缓冲区得buffer可能会比bytearray重得多(不要再跟我说人家开发系统驱动的牛X到比我在java里写个bytearray要快),而且每次write还有经历java-jni,userenv-systemenv的两次转换/切换。换句话说,连续发送请求一样需要应用自己缓冲才会性能更好。这种情况下可以开delay,但既然应用已经自己缓冲了,delay能带来的效果是有限的。 哦,我从来没有说过应用层不需要做缓冲,请别延伸。尽量以发送缓冲区大小的数据来发送,这是我的原话,别再误解了。在这种情况下也不应当禁用nagle,应用层缓存没办法做到每次发送都以固定大小发送,发送数据有大有小,nagle算法在有MSS大小数据可发的时候不起作用,当数据太小并有未确认分段的时候起作用,让TCP栈帮你做决定,以最大化地利用网络。 误用不误用,在我看来与TCP协议设计的本意相违背,并且禁用该选项并非唯一选择的情况下,我认为是误用。 |
|
返回顶楼 | |
发表时间:2011-07-03
学到了知识,感谢lz分享。
|
|
返回顶楼 | |
发表时间:2011-07-03
应用把参数写死那是你们的事儿,如果说你们的大多数应用是delay参数写死的、都是连续发送的,我不会说什么。你不要认为实际上大多数应用是这样。是不是连续发送是由客户端决定的,需要连续发送而不必立即等待应答的应用不多。
连续发送时delay是起一定作用,但作用有限,我是这么说的吧。批量发送的数据块通常已经很大,delay能够参与合并、发挥作用的几率不大。用delay可以提高的效率有限,在我这里的应用几乎可以忽略不计,其他应用我不敢保证,那要看实际测试。不过像你的demo让应用只依赖delay发挥作用的程序什么问题也说明不了。 你研究了半天下了多多数应用都是误用的结论,不是不可以。不过最好是你做过一些真正的应用,而不是只会写一些demo。 你为什么不想想人家为什么缺省设置不用delay,或者直接把它关掉?别人开发完的应用不测试吗?如果开了delay会有性能提高,人家不用delay?你想当然的认为别人没有考虑过用不用delay的问题?别太学术化,你把一样东西说的再好,实际应用当中也要发挥作用才行。 |
|
返回顶楼 | |
发表时间:2011-07-03
最后修改:2011-07-03
taolei0628 写道 应用把参数写死那是你们的事儿,如果说你们的大多数应用是delay参数写死的、都是连续发送的,我不会说什么。你不要认为实际上大多数应用是这样。是不是连续发送是由客户端决定的,需要连续发送而不必立即等待应答的应用不多。
连续发送时delay是起一定作用,但作用有限,我是这么说的吧。批量发送的数据块通常已经很大,delay能够参与合并、发挥作用的几率不大。用delay可以提高的效率有限,在我这里的应用几乎可以忽略不计,其他应用我不敢保证,那要看实际测试。不过像你的demo让应用只依赖delay发挥作用的程序什么问题也说明不了。 你研究了半天下了多多数应用都是误用的结论,不是不可以。不过最好是你做过一些真正的应用,而不是只会写一些demo。 你为什么不想想人家为什么缺省设置不用delay,或者直接把它关掉?别人开发完的应用不测试吗?如果开了delay会有性能提高,人家不用delay?你想当然的认为别人没有考虑过用不用delay的问题?别太学术化,你把一样东西说的再好,实际应用当中也要发挥作用才行。 我再回您句,nagle默认是启用的吧,我们的参数有没有写死你怎么知道,我做的应用是不是真实的应用,我的老板知道,不需要向您汇报。如果您是想向我布道,出门左转县政府,无需来这个帖子教导我。 |
|
返回顶楼 | |