注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

FY

Johnson 's Blog

 
 
 

日志

 
 

TCP的Nagle算法和Delayed ACK机制导致从Windows Azure Table Service获取小数据记录的高延时  

2016-05-30 14:50:51|  分类: 网络 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
http://www.cnblogs.com/polymorphism/archive/2012/12/10/High_Latency_for_Small_Size_Entities_in_Table_Service.html

之前测试一个部署在Azure的Web Role,发现获从Table Service获取小数据记录的延迟反而比获取中等大小数据记录明显要大,经过一番调查,发现其实是由于TCP的Nagle算法和Delayed ACK机制同时作用导致的。

先介绍一个背景知识:当TCP连接建立起来后,对于每一个发送方的数据包(包头包含PSH标志位),接受方都应该发送一个确认包给发送方(包头包含ACK标志位)。

Nagle和Delayed ACK机制都是通过减少不必要的网络传输来缓解拥堵。

Nagle算法主要是针对这种情形:网络存在大量的数据段很小的TCP包,虽然数据段很小比如只有1字节,但因为TCP包头需要占用一定的字节数,所以发送这样的包时,大部分的传输开销花在包头上了,如果网络中有大量客户端都在频繁请求这样的小TCP包,就会造成拥堵。比如LINUX下的某些终端,每输入一个字符都会要求服务器端发送一次响应。

为了解决这个问题,Nagle算法会将小的发送请求缓冲,以期将待发送数据合并成一个完整大小的TCP包然后一次发送。它的逻辑是这样的:如果当前要发送的数据小于一个完整的TCP包数据段(Windows下是1460字节,其他系统是1448字节),发送将被延迟,数据将被缓存,直到:

  1. 有更多的数据需要发送,待发送数据凑齐一个完整的TCP包数据段大小

或者:

  2.  前一个数据包被客户端确认了(收到客户端发来的ACK包)

第一点很好理解。第二点其实是为了使Nagle算法自动适应当前网络条件。算法假设通常情况下,客户端收到数据都会立即发送确认包确认。所以当网络条件很差时,数据包和ACK包的传输会经历更长的时间,这样Nagle算法就会等待更长时间以收集更多数据,从而缓解拥堵。反之,如果前一个包的确认包很快就到达了,那说明当前网络状况很好,所以无需过多等待。打个比方就是:今天我们到北京了,发现北京的车很多,路上很堵,所以大家就迁就一下,尽量拼车走。下周我们到了某个美国小镇,发现路很宽,没什么车,所以你一个人爱怎么开就怎么开。

Delay ACK的机制是这样的:如果当前只需要发送一个确认包,那么客户端就hold on,直到:

  1. 有后续的包需要发送,例如一个或多个数据包/ACK包(客户端可能连续收到好几个数据包需要确认)。或者:
  2. 等待超过预设的timeout时间。(参见IETF RFC 1122 4.2.3.2  When to Send an ACK Segment,这个预设时间应该 < 500ms)

这个机制基于这样的假设:如果客户端没有其他任何数据需要发送,说明客户端与服务器端的交互已经结束了,所以这个ACK包晚一点发送无所谓。

这两个机制单独看都没有问题,但如果发送方采用了Nagle算法而接收方采用了Delayed ACK机制,问题就来了。举例如下:

假设客户端向服务器端请求2KB的数据。2KB = 2048 bytes,大于一个完整的数据段的大小(Windows下是1460字节,其他系统是1448字节)。于是,服务器端先发送一个完整大小的TCP包,传输了1460字节数据。剩下的2048 - 1460 = 588 字节数据小于一个完整的数据段,因此服务器端hold on,等待客户端的确认包。

客户端这边收到了1460字节数据,本来需要发送一个确认包,但因为Delayed ACK机制的存在,单个确认包不会被立即发送,因此客户端也开始等待。

这样服务器端和客户端就开始相互等待,直到客户端的Delay ACK等待超时,把确认包发出,服务器端收到确认包后把剩下的数据发送给客户端。于是,这2KB数据最终花了上百毫秒的时间完成传输,其中大部分时间在等待。

假设需要发送的数据总量为N字节,不难看出,只有当N不被1460整除且除以1460的商Q为奇数时,这种情况才会出现。假设商Q为偶数,那么数据可以被分为Q个满字节数的TCP包,和一个包含余数R个字节数据的TCP包,因为前Q个包都是满字节的,所以服务器端会一直发送。而客户端会针对每两个收到的数据包,发送一个确认包,因此当最后两个包发送完时,服务器端能收到客户端的一个确认包,从而把剩下的R个字节发送出去。而如果Q是奇数,最后一个满字节数据包发送完以后,就会出现前面例子的情况了。

Windows Azure用户可以通过关闭Storage Service的Nagle优化来避免这种情况的发生,参考这篇文章

How to turn off Nagling?

Since Nagling is on by default, the way to turn this off is by resetting the flag in ServicePointManager. The ServicePointManager is a .NET class that allows you to manage ServicePoint where each ServicePoint provides HTTP connection management. ServicePointManager also allows you to control settings like maximum connections, Expect 100, and Nagle for all ServicePoint instances. Therefore, if you want to turn Nagle off for just tables or just queues or just blobs in your application, you need to turn it off for the specific ServicePoint object in the ServicePointManager. Here is a code example for turning Nagle off for just the Queue and Table ServicePoints, but not Blob:

复制代码
// cxnString = "DefaultEndpointsProtocol=http;AccountName=myaccount;AccountKey=mykey"
CloudStorageAccount account = CloudStorageAccount.Parse(cxnString);
ServicePoint tableServicePoint = ServicePointManager.FindServicePoint(account.TableEndpoint);
tableServicePoint.UseNagleAlgorithm = false;
ServicePoint queueServicePoint = ServicePointManager.FindServicePoint(account.QueueEndpoint);
queueServicePoint.UseNagleAlgorithm = false;
复制代码

If you instead want to set it for all of the service points on a given role (all blob, table and queue requests) you can just reset it at the very start of your application process by executing the following: 

// This sets it globally for all new ServicePoints
ServicePointManager.UseNagleAlgorithm = false;  

 

 

参考:http://www.stuartcheshire.org/papers/NagleDelayedAck/

   Nagle’s Algorithm is Not Friendly towards Small Requests

        http://www.ietf.org/rfc/rfc1122.txt

        《TCP/IP详解,卷1:协议》

  评论这张
 
阅读(19)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017