上周文章转发朋友圈后,我补充了个评论,我不晓得为什么RDMA底层传输协议还在复用TCP那一套,只是为了重用而重用吗?完全可以重写的协议还在GBN,还在将SACK作为GBN的优化,沿着老路重走一遍…请用QUIC吧,但这话不能对RDMA说,它用不了QUIC,转念一想,广域网传输也不是非用QUIC替代TCP,剥离导致TCP性能缺陷的因素,学着QUIC的样子改掉它,依然留着TCP的躯壳,作为TCP-ng,岂不是鸠占鹊巢更美妙?抛砖引玉,写下本文。

TCP吞吐性能已经经不住优化了,因为它的固有缺陷来自于它的原始设计。

TCP术语太多,滑动窗口,慢启动,拥塞避免,快速重传,快速恢复,超时重传,几乎任何资料都不可避免地以上述术语为线索,TCP的复杂性,无论是协议还是实现,均来自于此。

如此复杂的协议,竟然仅仅可用(幸亏AIMD也能让它收敛),毫无效率可言,够了!

最初的设计中,TCP只有积累确认,为让TCP滑动窗口持续滑动,必须以dupACK识别丢包,然后GBN(go-back-N),其中N指示重传的数量,这是一个简洁的设计,但低效。TCP原始设计的状态机为:

以Linux TCP实现为例,关于这个状态机的各状态描述如下:

/* Linux NewReno/SACK/ECN state machine. * -------------------------------------- * * "Open"       Normal state, no dubious events, fast path. * "Disorder"   In all the respects it is "Open", *              but requires a bit more attention. It is entered when *              we see some SACKs or dupacks. It is split of "Open" *              mainly to move some processing from fast path to slow one. * "CWR"        CWND was reduced due to some Congestion Notification event. *              It can be ECN, ICMP source quench, local device congestion. * "Recovery"   CWND was reduced, we are fast-retransmitting. * "Loss"       CWND was reduced due to RTO timeout or SACK reneging. ... */

自SACK被引入直到RACK/BBR,围绕TCP原始设计的优化终于再也无法满足需求,并越来越成为吞吐性能提升的障碍。成为性能提升阻碍的原因不外乎:

  • 状态机依然根据原始设计转换,在非Open状态接管拥塞控制算法。

是时候拿掉这个状态机了,就像赶走牵引蒸汽机的马匹一样。

为此需要设计一个新协议。但evolution比revolution更容易被接受。新协议不是QUIC,而是TCP-ng。重用TCP协议头是它的最大特征。

大致介绍一下TCP-ng对TCP做了哪些扩展以及如何做的。

首先,将TCP协议中不合时宜的机制剥离,如果不晓得哪些是不合时宜的,看看QUIC的方式:

  • 收端不再支持reneging,内存已不再是瓶颈,手机内存动辄10G+。
  • SACK段数量不再受限,带宽已足够,不必再压缩协议头空间。
  • end-to-end越来越普遍得使用TLV而不再青睐定长的短协议头。

以上措施之外,需要增加的新机制:

  • 以发送顺序而不是序列号标识传输,分离end-to-end和传输逻辑。
  • 完备的不依赖TCP拥塞状态机的拥塞控制算法。

综上,TCP-ng需要做的是:

  • 取消reneging。QUIC不允许reneging。
  • 完全的SACK。QUIC即完全SACK。
  • 独立的传输。QUIC中的packet ID
  • 解放拥塞控制算法。

幸运的是,以Linux TCP为例,需要修改的地方非常少,分别来看就是:

  • 收端和发端删除reneging相关的代码。
  • 收端将所有SACK段放入payload。发端用payload解析出的SACK段扫描retrans rbtree。
  • 发送端实现完整的RACK,发送时不区分new data和retrans。
  • 取消拥塞状态机,cc算法根据采集带宽来自己决策。

取消reneging的风险是,乱序太多或RTT太抖动的弱网环境,收端内存占用会很大,空洞长时间无法填补,严重情况下会出现类DDoS症状。

取消拥塞状态机,TCP的复杂性就砍掉了大部分,背后的思想很简单:

  • 拥塞一定会带来测量吞吐及RTT的变化,与丢包无关。
  • 丢包一定可以靠RACK重传恢复。如下图:

Linux TCP实现了RACK之后,其实已经很完美了,启用RACK后,完全依赖RACK来mark lost,而不再使用oneshot的tcp_update_scoreboard,这表明Linux RACK-Based TCP已经完全基于时间序发包了,此前的scoreboard已经成了历史。

核心问题SACK段数量受限以及时间序发送问题已经解决,TCP-ng便得以快速滑动窗口,HoL得到极大缓解,剩下的就是细枝末节了。

TCP-ng的不足是,ACK依然无法和transmit相对应,造成DSACK误判,undo效率降低。
以Linux TCP实现为例,当前的undo操作依赖于:

tp->undo_retrans == 0

该字段在收到DSACK时递减。由于无法区分一次重传报文带来的DSACK还是两次重传中其中一次带来的DSACK,有可能会造成undo失败并影响重传效率:

  • 进入重传状态后,只要之前有丢失的重传依然未决,本次undo就会失败。
  • retrans_out占据inflight份额,重传窗口无法张开。

好在packets_out是准的,下一轮packets_out清零之时可顺便清除retrans_out,但迟到的DSACK会带来warning。所以我建议在RTO时无条件清除retrans_out。

彻底解决这个问题需要增加类似QUIC的packet id字段。为此,TCP-ng2我这么建议:

  • 将SACK option分裂为3个type:type1为packet number(8字节,必选); type2为SACK(in payload);type3为stream ID(4字节,可优化接收负载均衡,或自研网卡优化RSS)
  • ACK中SACK段格式为begin data-seq:begin packet-seq~end data-seq:end packet-seq的映射段,用于发端检测并对应DSACK。
  • data seq和packet seq全部采用字节单位,不影响TSO/GSO,GRO/LRO等offload机制的运行。

undo只是降低一些重传率,对整体的带宽利用率提高影响有限,且机制复杂,为了不引入更多复杂性从而引发额外问题,不建议实现undo。

TCP-ng重用TCP协议头及其大多数原有处理逻辑,其原因是:

  • 主观原因:我太懒惰且编程水平太差,重写一个新协议虽好看但beyond my ability。
  • 客观原因:TCP-ng兼容性极好。

TCP有诸多缺陷,设计一个针对性弥补这些缺陷的新协议并不是一件很难的事,但在工程和生态视角,将新协议部署落地就太难了,一个很简单的例子就是IPv6。

IPv4的问题众所周知,IPv6逐一针对性解决,可是IPv6的部署之路却很艰难。

与之类似,QUIC也一样。

妇孺皆知的是QUIC对状态防火墙不友好。何止状态防火墙,QUIC对所有途径的运营商设备都不友好:

  • UDP没有状态机,设备无法跟踪连接,便无法精确实施ACL,计费等关键动作。
  • QUIC over UDP,作为应用层协议迄今没有统一标准,且变化多端,设备商的固化升级成本太高。
  • QUIC协议并非没有生态,而是各大厂商自立门户,生态太多,无法协调。
  • QUIC用户态的cc算法很容易被不懂拥塞控制为何物的人乱搞,严重破坏互联网公平。

所以,我选择不修改TCP协议头的方式,所有的设备还是和原来一样运作,新协议完全透明经过。再也没有人说新协议不友好了。

下面是我之前写的一篇欺骗网络设备的内核插件,它可以将UDP假装成TCP:https://github.com/marywangran/pseudotcp-tunnel

最后,演示一个扩展TCP协议的实际例子。

当前主机性能相比1980年代已经大幅提升,进程容量大大增加,为提升主机搜索可用端口号的效率(connect/bind中的逻辑),需要扩展TCP端口号位宽。下面介绍如何不改变TCP协议头而将端口号扩展成24位:

  • 新端口号的低16位用TCP协议头中的端口号字段表示。
  • 新端口号的高8位用TCP协议头中2个新的8位自定义option表示。
  • 发送端自行拼接端口号组装数据包。
  • 接收端解封装端口号多路复用。

浙江温州皮鞋湿,下雨进水不会胖。

TCP吞吐性能优化的吐槽与拯救相关推荐

  1. Web 性能优化:HTTP

    个人博客 在策略层面,(四维空间针对指定问题绝对复杂性的)普适优化手段最终都是在两种维度之间进行取舍转换: 当时间更宝贵时,用空间换时间: 当空间更宝贵时,用时间换空间. Web 性能优化:TCP W ...

  2. TCP接收端优化吞吐性能的把戏

    惯常TCP吞吐优化均在发送端激进传输,比如一个报文发两遍,盲目扩大cwnd此类.将这种动作称作"猛推",就必然存在是"猛拉",即在接收端做一些把戏. 还有一天放 ...

  3. 记一次单机系统的性能优化:最后竟是 TCP 的锅

    前言 这篇文章的主题是记录一次 Python 程序的性能优化,在优化的过程中遇到的问题,以及如何去解决的.为大家提供一个优化的思路,首先要声明的一点是,我的方式不是唯一的,大家在性能优化之路上遇到的问 ...

  4. 如何进行TCP性能优化

    本次和大家聊一下TCP性能优化. TCP全称为Transmission Control Protocol,每一个IT人士对TCP都有一定了解.TCP协议属于底层协议,对于大部分研发人员来说,这是透明的 ...

  5. 拯救你的年底 KPI:前端性能优化

    前言 性能优化 ,每个工程师跑不掉的一个话题.这里是本人总结的一些优化手法,希望对大家有所帮助,感谢各位大哥???? 演示demo 在线预览: http://118.25.49.69:8085/ fe ...

  6. 何崚谈阿里巴巴前端性能优化最佳实践

    转载:http://www.infoq.com/cn/interviews/hl-alibaba-front-end-performance-optimization 大家好,我现在在阿里巴巴园区采访 ...

  7. lwip协议栈优化_干货分享 | KNI性能优化实践

    友情提示:全文5000多文字,预计阅读时间15分钟 文章源自现网实践对支撑及用户态/内核态网络报文交换场景的认识,欢迎有Linux/FreeBSD内核.网络协议栈.DPDK优化实践经验的同学留言探讨- ...

  8. 43 | 套路篇:网络性能优化的几个思路(上)

    上一节,我们了解了 NAT(网络地址转换)的原理,学会了如何排查 NAT 带来的性能问题,最后还总结了 NAT 性能优化的基本思路.我先带你简单回顾一下. NAT 基于 Linux 内核的连接跟踪机制 ...

  9. Linux问题分析与性能优化

    目录 排查顺序 方法论 性能分析工具 CPU分析思路 内存分析思路 IO分析思路 网络分析思路 基准测试工具 参考 排查顺序 整体情况: top/htop/atop命令查看进程/线程.CPU.内存使用 ...

最新文章

  1. handler消息机制入门
  2. 从认证到调度,K8s 集群上运行的小程序到底经历了什么?
  3. jsp项目在idea需要导入什么依赖_Java开发工具IntelliJ IDEA配置项目系列教程(五):模块依赖...
  4. python flag函数_Python(函数基础,阶段总联系)
  5. 文档模式引起的浏览器兼容问题
  6. 基于linux智能家居系统设计,基于Linux的智能家居的设计(2)
  7. 一文梳理多任务学习(MMoE/PLE/DUPN/ESSM等)
  8. 谁来执行Rebalance以及管理consumer的group呢?
  9. MarkDown学习指南(一)
  10. 作为软件工程师,如何进行知识管理
  11. 简单了解cms(内容管理系统)
  12. java实现psd格式图片读入
  13. chrome浏览器加载图片失败问题
  14. qq邮箱mx服务器,QQ域名邮箱管理系统MX记录是什么?怎么添加设置?
  15. 物联网 DFrobot 掌控版的使用 智能灯和MQTT
  16. 单独上线音乐直播APP,“LOOK直播”能给网易云音乐带来什么?
  17. 浙江大学-翁凯 C语言进阶,编程题
  18. 电路中的VCC是什么意思?
  19. 电气EPlan软件第一章到第五章的学习
  20. 基于EasyDarwin开源流媒体服务器框架实现EasyNVR H5无插件直播流媒体服务器方案

热门文章

  1. 使用 VMware 16 RHEL7.7 虚拟机静默安装 Oracle 19c RAC
  2. 斗鱼直播地址抓取——转载
  3. 学java应该学什么
  4. 海思3559A平台4GB LPDDR配置方案
  5. 顺序表的建立及基本操作
  6. 怎么用计算机自己做动画片,大师为你详解动画怎么制作
  7. 计算向量相似度 ---余弦相似度
  8. ai智能电话机器人语音识别技术
  9. JavaScript系列之详解原型和原型链
  10. 一个定制CFileDialog对话框的实例