人人都该懂点儿TCP---ACK延缓(转)

作者:Julia Evans

译者:赖信涛
原文链接:Why you should understand (a little) about TCP

译文链接:http://geek.csdn.net/news/detail/44474



即使你的工作也许不需要对TCP了如指掌,也不需要去了解具体的TCP/IP实例。你也应该懂一些基本的TCP知识,本文会告诉你为什么。

我以前在Recurse Center工作的时候,曾经用Python写过一个TCP栈(还写了一篇博文用Python实现TCP栈可以学到什么)。这是很有意思的一课,也基本上是我对TCP的所有了解了。

一年之后,工作上遇到了困难。有同事在Slack上问到:“嘿,我向NSQ推消息总是会有40ms的延迟,不知道为什么。”这个问题我思来想去,过了一个周,还是毫无头绪。

这里解释一下: NSQ是一个用来发消息的队列。发送方式是向localhost发出一个HTTP请求,这个动作不可能花费40ms,一定是出了错。但是NSQ不具备很高的CPU优先级,也没有占用大量内存,所以问题不是出在垃圾回收那边。

后来,我想起来一周之前读过的一篇文章——我们是如何在每一个POST请求上省出200ms的(In search of performance - how we shaved 200ms off every POST request)。这篇文章讨论了一开始每一个POST都会多花200ms的原因,多少有些诡异。下面是这篇文章中的内容。

ACK延迟和TCP_NODELAY

Ruby的Bet::HTTP将POST请求分成两个TCP包——一个header,一个body.curl,相比之下,将它们组合成一个倒是更加合适。不过更糟的是,Net:HTTP没有给它打开的TCP socket设置TCP_NODELAY,所以发送第一个包之后,要等到确认才会发送第二个。归根结底,这是Nagle算法导致的。

连接的另一端,HAProxy要选择用何种方式确认这两个包。在1.4.18(正式我们使用的版本),它使用的是TCP延时确认,延时确认在Nagle算法中表现很糟糕,导致请求在这个地方暂停了,直至超时。

我来总结一下这段话:

  • TCP是将你要发送的数据打包的算法
  • 他们的HTTP需要用两个小包发送POST请求

整个过程就像下面这样:

application:嗨!给你第一个包 
HAProxy:嘘……我们要等第二个包 
HAProxy:对了,我们要给他个确认,不过没什么大不了的,等会再说 
application:嘘……我们等到第一个包的确认再发第二个,也许网络堵车了,再等一会 
HAProxy:烦死了,我们发第一个包的确认吧 
application:收到确认,发第二个包!!!! 
HAProxy:搞定!

这段时间内,HAProxy和application都在消极地等待,直到超过200ms。application等待是因为Nagle算法,HAProxy等待是因为延迟ACK。

据我所知,延迟的ACK在所有Linux系统都是默认打开的。所以这不是特例,只要你发送的数据多于一个TCP包,你也会碰上这种事。

终于搞定了问题

读了这篇文章之后,觉得没什么了不起的。但是在我们的神秘40ms挣扎了许久,我想起来这篇文章。

我想:这可能是我的问题吗?可能吗??可能吗?!我给团队发了一封邮件说“可能是我疯了,不过,有可能是TCP的问题。”

于是我将TCP_NODELAY打开,然后——BOOM!

所有的40ms延迟统统消失了,这个世界完美了。我真是个天才!

ACK延迟应该完全关闭吗

提一个小插曲,我在HN上看到了这条评论

真正的问题处在ACK延迟上。200ms延时设定是糟糕的主意,1985年在伯克利搞BSD的那帮人,根本不理解这个问题。ACK延迟是赌应用层一定会在200ms之内收到回复。虽然几乎每次都输,但是ACK延迟依然在用。

他在评论中讨论了ACK是成本很低的,这中做法所导致的问题比它解决的问题要严重的多。

如果你不懂TCP,就搞不定这个问题

以前我总认为TCP是相当底层的东西,我永远不需要去了解它。虽然差不多是这样,但是实际生活中,你依然可能遇见和TCP算法相关的Bug,这时候懂一些TCP的知识就至关重要了。(本文也可以引申为,系统调用,操作系统这些都很重要,这个道理适用于很多东西。)

ACK延时/TCP_NODELAY很糟糕——它可能对任何写HTTP请求代码的人造成影响。但是你不必成为系统编程方面的天才,懂一点TCP就帮我搞定了这个问题,也让我意识到,出现这个问题我也有责任。我也在用strace,strace万岁!

时间: 2024-11-13 12:53:06

人人都该懂点儿TCP---ACK延缓(转)的相关文章

人人都该懂点儿TCP(转)

作者:Julia Evans 译者:赖信涛原文链接:Why you should understand (a little) about TCP 译文链接:http://geek.csdn.net/news/detail/44474 即使你的工作也许不需要对TCP了如指掌,也不需要去了解具体的TCP/IP实例.你也应该懂一些基本的TCP知识,本文会告诉你为什么. 我以前在Recurse Center工作的时候,曾经用Python写过一个TCP栈(还写了一篇博文用Python实现TCP栈可以学到什

人人都必需懂的OSI参考模型,到底是什么玩意儿

在很久很久以前,企业级通讯设备的协议是不互通的.HP,IBM等厂商都根据自己的协议生产了不同的软硬件.这样做也是因为数据通讯的保密性,但是这样做有一个弊端,就是不同品牌的设备之间相互通讯非常困难. 举个例子,以前的中国,阎锡山为了做山西土皇帝,山高皇帝远,在自己势力范围内建造窄轨铁路,蒋介石国军的火车无法进入山西境内,无法便利调动军队.物资,实现一人独大的军阀割据格局.以互联网的眼光看,如果标准轨道铁路网是一个互联网,那阎锡山的窄轨铁路就是一个自我封闭的局域网,为了打破这种非标准化的私有标准,需

人人都能懂的原型对象

提到JS中的对象,我们就不得不提JS对象中的原型.我们知道,JS是可以面向对象编程的语言,通常在面向对象中,继承关系都是通过类来实现的.但是,请记住,在JS中,并没有类的概念.在JS的设计之初就没有类,那么在JS中,继承是通过什么来实现的呢?答案就是原型. 每一个构造函数都有一个与之相关联的对象,该对象称之为原型对象.每个实例对象都能共享其原型对象上的属性和方法.原型对象的作用主要用来实现属性的继承,让实例对象能共享原型对象的属性,减少内存分配.所以,在上一节中,我们想在每个Person对象中共

人人都应该懂点密码学

你可以从别人那里汲取某些思想,但必须用你自己的方式加以思考,在你的模子里铸成你思想的砂型.--兰姆 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 点关注,不迷路!!! ?上次say&see了密码学的DES算法,接下来就有人私信说是一开始就直接讲算法有点难理解,想让我给打打底,这么说当然没问题,那以后我们就每周一篇,从最基础的东西讲起,下面我还会附上一张基础的知识框架图,感兴趣的盆友来看一看,

密歇根大学 - 人人都懂的编程课(Python)

人人都懂的编程课(Python) Week03 Exercise Rewrite your pay program using try and except so that your program handles non-numeric input gracefully. Enter Hours: 20 Enter Rate: nine Error, please enter numeric input

从程序员到项目经理(4):程序员加油站 -- 不是人人都懂的学习要点

学习是一种基础性的能力.然而,“吾生也有涯,而知也无涯.”,如果学习不注意方法,则会“以有涯随无涯,殆矣”. 一.学习也是一种能力 看到这个标题,有人会说:“学习,谁不会?”的确,学习就像吃饭睡觉一样,是人的一种本能,人人都有学习的能力.我们在刚出生的时候,什么也不知道,是一张真正的白纸,我们靠学习的本能,学会了走路.说话.穿衣服…后来,我们上学了,老师把书本上的知识一点一点灌输到我们的脑子里,我们掌握的知识越来越多,与此同时,我们学习能力却好像越来越差了,习惯了被别人喂饱,似乎忘记了怎么来喂自

从程序员到项目经理之程序员加油站 -- 不是人人都懂的学习要点(转发)

学习是一种基础性的能力.然而,“吾生也有涯,而知也无涯.”,如果学习不注意方法,则会“以有涯随无涯,殆矣”. 一.学习也是一种能力 看到这个标题,有人会说:“学习,谁不会?”的确,学习就像吃饭睡觉一样,是人的一种本能,人人都有学习的能力.我们在刚出生的时候,什么也不知道,是一张真正的白纸,我们靠学习的本能,学会了走路.说话.穿衣服…后来,我们上学了,老师把书本上的知识一点一点灌输到我们的脑子里,我们掌握的知识越来越多,与此同时,我们学习能力却好像越来越差了,习惯了被别人喂饱,似乎忘记了怎么来喂自

人人都看得懂的正则表达式

正则表达式可以帮助我们更好的描述复杂的文本格式.一旦你描述清楚了这些格式,那你就可以利用它们对文本数据进行检索.替换.提取和修改操作. 下面有一个正则表达式的简单例子.第一步先要引入有关正则式的命名空间: using System.Text.RegularExpressions; 第二步就是用指定的正则式构建一个正则表达式对象,下面的正则式是用来搜索长度为10的a-z的英文字母: Regex obj = new Regex("[a-z]{10}"); 最后,根据正则式在指定数据中检索匹

【总结整理】用户的需求分析:问对问题才能找准用户需求----摘自《人人都是产品经理》

用户的需求分析:问对问题才能找准用户需求(一) Geek 微信公众号:产品Ren 2018-10-18 7888 66 18 零基础学产品,BAT产品总监带,2天线下集训+1年在线课程,全面掌握优秀产品经理必备技能.了解详情 释放双眼,带上耳机,听听看~! 00:00 00:00 在需求收集的过程中,首先需要问对一个好问题,只有带着合理&有效的问题才能得到正确的答案. 我之前看了很多产品经理的书,记得大部分书上边都写着产品经理应该是一个全才,他们需要懂社会学.心理学.统计学等等一系列的知识. 那