首页 > 编程知识 正文

经典福克斯性能排行,经典日系性能车

时间:2023-05-05 11:59:33 阅读:52478 作者:3530

就是理解TCP。 最常见的TCP性能问题是,一个PHP服务通过Nginx封装后续tair,并允许其他APP应用程序通过http协议访问Nginx对tair进行获取和设置操作

上线后测试一切正常,每次操作数毫秒,但有时某个APP的value为300K,此时set一次需要300毫秒以上。 在没有并发压力的单线程上进行一次操作也需要这么长时间,这个延迟没有道理,是不能接受的。

问题的原因是,TCP协议为了进行一些带宽利用率、性能方面的优化,进行了一些特殊的处理。 例如延迟确认和Nagle算法。

究其原因,在让大家了解TCP的基本概念后,可以在实战中了解一些TCP其他方面的性能和影响。

什么是延迟确认? 在我前面的TCP介绍文章中,TCP是可靠的传输,可靠的核心是在收到数据包后回复ack告诉对方已经到达。

请看一个例子:

截图中的nignx(8085端口)收到http请求,立即向客户端返回了ack数据包,然后向客户端返回了http响应。 请注意,返回的ack包的长度为66,实际内容的长度为0。 ack信息位于TCP标头中。 也就是说,这里将66字节的空数据包发送给客户端,告诉客户端我收到了你的请求。

这里没有问题。 逻辑上是正确的。 符合TCP核心确实传输的意思。 但是,存在带宽效率不高的问题。 那个可以优化吗?

这里的优化是延迟访问。

所谓delay ack,不是收到包就马上ack,而是稍等(例如40毫秒),如果在这40毫秒内正好有一个包被发送到客户端,我这个ack包就会一起发送。 (顺风风车、http reponse包无需增加尺寸。 )这样可以节省资源,当然,如果在此时间过后仍未向客户端发送数据包(例如,nginx过程需要40毫秒或更长时间),则此ack也会发送到客户端。 (即使是空的,如果客户端认为丢包,也必须重新发送http请求。 )。

假设此时还在等待ack数据包延迟发送的同时,从客户端接收到了另一个数据包。 如果此时服务器收到两个ack数据包,则操作系统会立即将这两个ack数据包加在一起,并将一个ack数据包返回给客户端,并告知客户端前两个数据包已到达。

也就是说,当delay ack打开时。 ack不立即发送,而是等待40毫秒。 在等待的时候,ack包里有顺风风车的话就可以乘坐。 或者把两个ack包起来自己包车也马上发车。如果再等40毫秒以上还不顺利的话,自己开车也发车。

因为屏幕快照中的Nginx没有打开delay ack,所以红框ack可以完全与“绿框”(http response )一起发送到客户端,但没有。 红框ack马上坐出租车逃跑了

Nagle算法下的伪代码是Nagle算法的基本逻辑。 摘自维客:

ifthereisnewdatatosendifthewindowsizegt;=MSS and available数据is gt;=msssendcompletemsssegmentnowelseifthereisunconfirmeddatastillinthepipeenqueuedatainthebufferuntilanacknowledgeisreceivedels els els els endifendif此代码表示如果接收窗口大于MSS,发送的数据大于MSS,则立即发送。

总结Nagle算法的逻辑是,如果发送的数据包很小(小于MSS ),而且对方收到了发送的数据包还没有回复,我也不着急发送,等上一个数据包的回复收到后再发送。 这将优化带宽利用率。 几年前的带宽资源是宝贵的。 此外,Nagle算法还用于优化tcp传输效率。

如果客户端启用了Nagle并在服务器端启用了delay ack,会发生什么?

假如client要发送一个http请求给server,这个请求有1600个bytes,握手的MSS是1460,那么这1600个bytes就会分成2个TCP包,第一个包1460,剩下的140bytes放在第二个包。第一个包发出去后,server收到第一个包,因为delay ack所以没有回复ack,同时因为server没有收全这个HTTP请求,所以也没法回复HTTP response(server等一个完整的HTTP请求,或者40毫秒的delay时间)。client这边开启了Nagle算法(默认开启)第二个包比较小(140<MSS),第一个包的ack还没有回来,那么第二个包就不发了,等!互相等!一直到Delay Ack的Delay时间到了!

这就是悲剧的核心原因。

再来看一个经典例子和数据分析

这个案例来自:http://www.stuartcheshire.org/papers/nagledelayedack/

案例核心奇怪的问题是,如果传输的数据是 99,900 bytes,速度5.2M/秒; 

原因就是:

99,900 bytes = 68 full-sized 1448-byte packets, plus 1436 bytes extra100,000 bytes = 69 full-sized 1448-byte packets, plus   88 bytes extra

99,900 bytes:

68个整包会立即发送,因为68是偶数,对方收到最后两个包后立即回复ack(delay ack凑够两个也立即ack),那么剩下的1436也很快发出去(根据nagle算法,没有没ack的包了,立即发)

100,000 bytes:

前面68个整包很快发出去也收到ack回复了,然后发了第69个整包,剩下88bytes根据nagle算法要等一等,server收到第69个ack后,因为delay ack不回复(手里只攒下一个没有回复的包),所以client、server两边等在等,一直等到server的delay ack超时了。

挺奇怪和挺有意思吧,作者还给出了传输数据的图表:

这是有问题的传输图,明显有个平台层,这个平台层就是两边在互相等,整个速度肯定就上不去。

如果传输的都是99,900,那么整个图形就很平整:

回到前面的问题

服务写好后,开始测试都没有问题,rt很正常(一般测试的都是小对象),没有触发这个问题。后来碰到一个300K的rt就到几百毫秒了,就是因为这个原因。

另外有些http post会故意把包头和包内容分成两个包,再加一个Expect参数之类的,更容易触发这个问题。

这是修改后的C代码

   struct curl_slist *list = NULL;    //合并post包    list = curl_slist_append(list, "Expect:");      CURLcode code(CURLE_FAILED_INIT);    if (CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_URL, oss.str().c_str())) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout)) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &amp;write_callback)) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L)) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_POST, 1L)) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, pooh.sizeleft)) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback)) &amp;&amp;            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_READDATA, &amp;pooh)) &amp;&amp;                            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L)) &amp;&amp; //1000 ms curl bug            CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list))                            ) {            //这里如果是小包就不开delay ack,实际不科学            if (request.size() &lt; 1024) {                    code = curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1L);            } else {                    code = curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 0L);            }            if(CURLE_OK == code) {                    code = curl_easy_perform(curl);            }

上面中文注释的部分是后来的改进,然后经过测试同一个300K的对象也能在几毫米以内完成get、set了。

尤其是在Post请求将HTTP Header和Body内容分成两个包后,容易出现这种延迟问题

总结

这个问题确实经典,非常隐晦一般不容易碰到,碰到一次决不放过她。文中所有client、server的概念都是相对的,client也有delay ack的问题。 Nagle算法一般默认开启的

此文来自阿里巴巴同事:蛰剑

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。