本文由云+社区发表

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 sendif the window size >= MSS and available data is >= MSSsend complete MSS segment nowelseif there is unconfirmed data still in the pipeenqueue data in the buffer until an acknowledge is receivedelsesend data immediatelyend ifend ifend if

简单讲, Nagel算法的规则是:

  1. 如果发送内容大于1个MSS, 立即发送;
  2. 如果之前没有包未被确认, 立即发送;
  3. 如果之前有包未被确认, 缓存发送内容;
  4. 如果收到ack, 立即发送缓存的内容。

延迟ACK的源码如下:net/ipv4/tcp_input.c

基本原理是:

  1. 如果收到的数据内容大于一个MSS, 发送ACK;
  2. 如果收到了接收窗口以为的数据, 发送ACK;
  3. 如果处于quick mode, 发送ACK;
  4. 如果收到乱序的数据, 发送ACK;
  5. 其他, 延迟发送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的两端来入手。

服务端:

  1. 关闭tcp_delay_ack, 这样, 每个tcp请求包都会有一个ack及时响应, 不会出现延迟的情况。 操作方式: echo 1 > /proc/sys/net/ipv4/tcp_no_delay_ack 但是, 每个tcp请求都返回一个ack包, 导致网络包量的增加,关闭tcp延迟确认后, 网络包量大概增加了80%,在高峰期影响还是比较明显。

2.设置TCP_QUICKACK属性。 但是需要每次recv后再设置一次。 对应我们的场景不太适合,需要修改服务端redis源码。

客户端:

  1. 关闭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)); }
  2. 避免多次写, 再读取的场景, 合并成一个大包的写;避免一次请求分成多个包发送, 最开始发送的包小于一个MSS,对我们的场景, 把第22号包的1424个字节缓存起来, 大于一个MSS的时候,再发送出去, 服务端立即返回响应, 客户端继续发送后续的数据, 完成交互,避免时延。

此文已由作者授权腾讯云+社区发布


转载于:https://www.cnblogs.com/qcloud1001/p/10170254.html

我们来说一说TCP神奇的40ms相关推荐

  1. 再说TCP神奇的40ms

    TCP是一个复杂的协议,每个机制在带来优势的同时也会引入其他的问题. Nagel算法和delay ack机制是减少发送端和接收端包量的两个机制, 可以有效减少网络包量,避免拥塞.但是,在特定场景下, ...

  2. semantic ui框架学习笔记二

    评论组件 文档里的评论组件介绍的比较清晰.这里我就挑一个我喜欢的格式展示出来: <div class="ui comments"><h3 class=" ...

  3. 关于网络编程中MTU、TCP、UDP优化配置的一些总结

    首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层.  其中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data)在 ...

  4. PHP tcp短链接,http请求怎样实现TCP长连接、短连接

    HTTP连接分为长连接和短连接,而我们现在常用的都是HTTP1.1,因此我们用的都是长连接. 这句话其实只对了一半,我们现如今的HTTP协议,大部分都是1.1的,因此我们平时用的基本上都是长连接.但是 ...

  5. Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤...

    TCP和UDP是两个传输层协议,广泛应用于网络中不同主机之间传输数据.对任何程序员来说,熟悉TCP和UDP的工作方式都是至关重要的.这就是为什么TCP和UDP是一个流行的Java编程面试问题. Jav ...

  6. 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)

    原文见:http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/ from:ht ...

  7. Silverlight4中用net.tcp双工方式进行通信

    http://www.evget.com/zh-CN/Info/catalog/13737.html 先简单说一下,为了更好地实现双向通信,.NET Framework在 3.0的时候引入了一个全新的 ...

  8. 理解TCP的通信原理及IO阻塞

    通过上面这个简单的案例,基本清楚了在Java应用程序中如何使用socket套接字来建立一个基于tcp协议的通信流程.接下来,我们在来了解一下tcp的底层通信过程是什么样的 了解TCP协议的通信过程 首 ...

  9. 1万字30张图说清TCP协议

    本篇文章较长,大家先看下目录 1.简介 2.TCP协议头 3.TCP 数据包的编号(SEQ) 4.三次握手建立连接 5.四次挥手断开连接 6.TCP可靠性的保证 7.滑动窗口技术 9.窗口滑动的数据重 ...

最新文章

  1. eclipse保存自动组织导入、删除不必要的导入、格式化代码
  2. 谷歌向公众开放Fuchsia OS:支持手机电脑IoT,华为鸿蒙与之对标
  3. msclass 文字滚动_文字无缝循环滚动(标题向上滚动)
  4. hihoCoder #1954 : 压缩树(虚树)
  5. MIT自然语言处理第二讲:单词计数(第一、二部分)
  6. 经典C语言程序100例之六八
  7. Linux配置汇总上(北大青鸟Linux课程学习总结)
  8. 【推荐系统(一)】协同过滤之基于领域的方法(UserCF,ItemCF)
  9. react构建_您应该了解的有关React的一切:开始构建所需的基础知识
  10. 【NLP基础】NLP关键字提取技术之LDA算法原理与实践
  11. 2019.7.24循环结构以及昨天的预习题。
  12. Win10+VS2017+Ceres-Solver-1.13.0配置
  13. 破世界纪录了0.74秒!用代码实现自动扫雷!
  14. UML概要基础知识(待完善)
  15. linux ip被占用顶掉,记一次 Linux服务器被***后的排查思路
  16. 闭环整流电路matlab仿真,分享:基于双闭环的单相整流器原理简介及仿真验证
  17. 述职答辩提问环节一般可以问些什么_01、述职答辩操作流程指引
  18. django 常用static\media\邮箱\富文本编辑器配置(备忘)
  19. 研发路上的总结和思考 -----来自阿里巴巴中间插件----作者:石佳宁
  20. 判断当前手机设备的类型(安卓还是IOS)

热门文章

  1. selenium 隐藏窗口_anaconda下安装selenium包
  2. linux新建用户不显示,linux系统无法添加用户帐号的原因分析
  3. 雷军凌晨2点下班、刘强东睡4小时,这碗鸡汤程序员你必须干了
  4. layui框架的优缺点
  5. 15 张前端高清知识地图,强烈建议收藏
  6. 一位工作10年的前端总结的10个忠告
  7. QT子文件的建立和调用
  8. ubuntu中java环境配置_Ubuntu下java环境的搭建
  9. 新rust怎么拆除围墙_“问题围挡”拆除 街道变漂亮了
  10. android xml图片旋转,如何在Android中进行平滑的图像旋转?