再说TCP神奇的40ms
版权声明:本文由安斌原创文章,转载请注明出处:
文章原文链接:https://www.qcloud.com/community/article/186
来源:腾云阁 https://www.qcloud.com/community
TCP是一个复杂的协议,每个机制在带来优势的同时也会引入其他的问题。 Nagel算法和delay ack机制是减少发送端和接收端包量的两个机制, 可以有效减少网络包量,避免拥塞。但是,在特定场景下, Nagel算法要求网络中只有一个未确认的包, 而delay ack机制需要等待更多的数据包, 再发送ACK回包, 导致发送和接收端等待对方发送数据, 造成死锁, 只有当delay ack超时后才能解开死锁,进而导致应用侧对外的延时高。 其他文字已经介绍了相关的机制, 已经有一些文章介绍这种时延的场景。本文结合具体的tcpdump包,分析触发delay ack的场景,相关的内核参数, 以及规避的方案。
背景
给redis加了一个proxy层, 压测的时候发现, 对写入命令,数据长度大于2k后, 性能下降非常明显, 只有直连redis-server的1/10. 而get请求影响并不是那么明显。
分析
观察系统的负载和网络包量情况, 都比较低, 网络包量也比较小, proxy内部的耗时也比较短。 无赖只能祭出tcpdump神奇, 果然有妖邪。

22号tcp请求包, 42ms后服务端才返回了ack。 初步怀疑是网络层的延时导致了耗时增加。Google和km上找资料, 大概的解释是这样: 由于客户端打开了Nagel算法, 服务端未关闭延迟ack, 会导致延迟ack超时后,再发送ack,引起超时。
原理
Nagel算法,转自维基百科
if there is new data to send
if the window size >= MSS and available data is >= MSS
send complete MSS segment now
else
if there is unconfirmed data still in the pipe
enqueue data in the buffer until an acknowledge is received
else
send data immediately
end if
end if
end if
简单讲, Nagel算法的规则是:
- 如果发送内容大于1个MSS, 立即发送;
- 如果之前没有包未被确认, 立即发送;
- 如果之前有包未被确认, 缓存发送内容;
- 如果收到ack, 立即发送缓存的内容。
延迟ACK的源码如下:net/ipv4/tcp_input.c
基本原理是:
- 如果收到的数据内容大于一个MSS, 发送ACK;
- 如果收到了接收窗口以为的数据, 发送ACK;
- 如果处于quick mode, 发送ACK;
- 如果收到乱序的数据, 发送ACK;
- 其他, 延迟发送ACK
其他都比较明确, quick mode是怎么判断的呢? 继续往下看代码:
影响quick mode的一个因素是 ping pong的状态。 Pingpong是一个状态值, 用来标识当前tcp交互的状态, 以预测是否是W-R-W-R-W-R这种交互式的通讯模式, 如果处于, 可以用延迟ack, 利用Read的回包, 将Write的回包, 捎带给发送方。
如上图所示, 默认pingpong = 0, 表示非交互式的, 服务端收到数据后, 立即返回ACK, 当服务端有数据响应时,服务端将pingpong = 1, 以后的交互中, 服务端不会立即返回ack,而是等待有数据或者ACK超时后响应。
问题
按照前面的的原理分析,应该每次都有ACK延迟的,为什么我们测试小于2K的数据时, 性能并没有受到影响呢?
继续分析tcpdump包:
按照Nagel算法和延迟ACK机制, 上面的交互如下图所示, 由于每次发生的数据都包含了完整的请求, 服务端处理完成后, 向客户端返回命令响应时, 将请求的ACK捎带给客户端,节约一次网络包。
再分析2K的场景:
如下表所示, 第22个包发送的数据小于MSS, 同时,pingpong = 1, 被认为是交互模式, 期待通过捎带ACK的方式来减少网络的包量。 但是, 服务端收到的数据,并不是一个完整的包,不能产生一次应答。服务端只能在等待40ms超时后,发送ACK响应包。
同时,从客户端来看,如果在发送一个包, 也可以打破已收数据 > MSS的限制。 但是,客户端受Nagel算法的限制, 一次只能有一个包未被确认,其他的数据只能被缓存起来, 等待发送。

触发场景
一次tcp请求的数据, 不能在服务端产生一次响应,或者小于一个MSS
规避方案
只有同时客户端打开Nagel算法, 服务端打开tcp_delay_ack才会导致前面的死锁状态。 解决方案可以从TCP的两端来入手。
服务端:
- 关闭tcp_delay_ack, 这样, 每个tcp请求包都会有一个ack及时响应, 不会出现延迟的情况。 操作方式:
echo 1 > /proc/sys/net/ipv4/tcp_no_delay_ack
但是, 每个tcp请求都返回一个ack包, 导致网络包量的增加,关闭tcp延迟确认后, 网络包量大概增加了80%,在高峰期影响还是比较明显。
- 设置TCP_QUICKACK属性。 但是需要每次recv后再设置一次。 对应我们的场景不太适合,需要修改服务端redis源码。
客户端:
- 关闭nagel算法,即设置socket tcp_no_delay属性。
static void _set_tcp_nodelay(int fd) {
int enable = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable));
}
- 避免多次写, 再读取的场景, 合并成一个大包的写;避免一次请求分成多个包发送, 最开始发送的包小于一个MSS,对我们的场景, 把第22号包的1424个字节缓存起来, 大于一个MSS的时候,再发送出去, 服务端立即返回响应, 客户端继续发送后续的数据, 完成交互,避免时延。
参考资料:
http://jerrypeng.me/2013/08/mythical-40ms-delay-and-tcp-nodelay/
http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201231214038740/
http://blog.chinaunix.net/uid-28387257-id-3658980.html
https://github.com/torvalds/linux/blob/master/net/ipv4/tcp_input.c
再说TCP神奇的40ms的更多相关文章
- 我们来说一说TCP神奇的40ms
本文由云+社区发表 TCP是一个复杂的协议,每个机制在带来优势的同时也会引入其他的问题. Nagel算法和delay ack机制是减少发送端和接收端包量的两个机制, 可以有效减少网络包量,避免拥塞.但 ...
- semantic ui框架学习笔记二
评论组件 文档里的评论组件介绍的比较清晰.这里我就挑一个我喜欢的格式展示出来: <div class="ui comments"> <h3 class=" ...
- [转帖]关于网络编程中MTU、TCP、UDP优化配置的一些总结
关于网络编程中MTU.TCP.UDP优化配置的一些总结 https://www.cnblogs.com/maowang1991/archive/2013/04/15/3022955.html 感谢原作 ...
- TCP/IP具体解释--TCP/UDP优化设置总结& MTU的相关介绍
首先要看TCP/IP协议,涉及到四层:链路层,网络层.传输层,应用层. 当中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data)在应 ...
- tcp/ip 性能优化问题的思考学习
首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层. 其中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data)在 ...
- Nagle算法
简介 Nagle算法是以他的发明人John Nagle的名字命名的,它用于自动连接许多的小缓冲器消息:这一过程(称为nagling)通过减少必须发送包的个数来增加网络软件系统的效率.Nagle算法于1 ...
- Nagle 算法
1. Nagel算法 TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认.为了尽可能的利用网络带宽,TCP总是希望尽可能的发 ...
- TCP_NODELAY算法使用事项
当有一个TCP数据段不足MSS,比如要发送700Byte数据,MSS为1460Byte的情况.nagle算法会延迟这个数据段的发送,等待,直到有足够的数据填充成一个完整数据段.也许有人会问,这有什么影 ...
- TCP_NODELAY和TCP_CORK nagle算法和cork算法
TCP_NODELAY 默认情况下,发送数据採用Nagle 算法.这样尽管提高了网络吞吐量,可是实时性却减少了,在一些交互性非常强的应用程序来说是不同意的.使用TCP_NODELAY选项能够禁止Nag ...
随机推荐
- 2016年12月4日 星期日 --出埃及记 Exodus 20:25
2016年12月4日 星期日 --出埃及记 Exodus 20:25 If you make an altar of stones for me, do not build it with dress ...
- Linux基本配置
Linux发行版:centos 6.5 配置yum源 wget http://mirrors.163.com/.help/CentOS6-Base-163.repo -P /etc/yum.repos ...
- 【Java】聊聊常用的摘要算法,比如MD5
摘要算法的特性 摘要算法的目的的将信息进行简单地摘要,将任意长的信息摘要成固定长的信息.比如MD5,将任意长的信息摘要成128位的摘要. 不可逆的,将报文摘要成一段信息后,无法通过摘要信息还原会报文. ...
- CAGradientLayer
参考: CAShapeLayer和CAGradientLayer 一 简介 1,CAGradientLayer,处理颜色渐变: 2,CAGradientLayer的渐变色可以做隐式动画: 3,大部分情 ...
- MTK+高通方案商
1.德信无线通讯科技有限公司 点击打开链接 2.深圳优美科技
- JAVA 语言基础——运算符
1.赋值运算符 赋值运算符"=",是一个能对两个操作数进行处理的二元运算符. 比如: int a = 12; //声明int型变量a int b= 34; //声明int型变量b ...
- Atlassian如何实施DevOps
DevOps是推动开发和运维团队之间沟通和协作的手段.它不是一个工具或产品.相反,其成功的首要因素就是文化.目的是更快的创新和更好的客户体验. "2015年DevOps状态报告"调 ...
- .Net需要掌握的知识
一.C#开发 1.C#基础 变量定义 如何变量的初始化 变量的作用域 常量 字符串处理 使用正则表达式 什么是CTS类型?数据类型如何分类以及各个数据类型范围 类型的转化分类 显式转换何隐式转化如何区 ...
- Shell概述
一,Shell原理
- So easy Webservice 8.spring整合CXF 发布WS
1.添加jar包(cxf的jar包中包含了spring的jar包),添加spring配置文件 2.web.xml中配置CXFServlet,过滤WS服务的地址 <!-- 配置CXFServlet ...