新算法的模拟代码明早再写。

一个大厂内部分享,讲师说TCP长肥管道无法填满,这是错误的。我曾经单流填满过一条200ms的5Gbps专线。

为什么大家碰到填充长肥管道难题后首先想到的都是rcvbuff不够而不是rwnd不够呢?显然是Linux TCP实现的误导。Linux TCP的rcvbuff决定了rwnd。

Linux TCP的rwnd不允许超过rcvbuff,参见 __tcp_select_window 和 tcp_rcv_space_adjust 这两个函数。rwnd的硬限制便阻止了程序以更快的速率读取数据,再猛的CPU也是浪费,rwnd决定了没有那么多数据可供读取。

打个比方,在一条0.5s(500ms)的10GBps(为了和主机单位统一,换算做大B)链路上,TCP接收端配置了10B的rcvbuff,其rwnd最大就是10B,这意味着1s(1 RTT)内,发送端只能发送10B,该连接的吞吐即被限制为10Bps,即便接收端有10GBps的接收能力也只能维持在可怜的10Bps,因为1s只能送过来这么多数据。
但实际上,10B的超小rcvbuff果真是吞吐能力的限制因素吗?

理想情况下,一条从socket send到socket recv的管道不需要任何buffer,但为了平滑到达率和socket read速率之间的统计波动,需要设置一些buffer,但肯定不需要BDP那么大:

论长肥管道的传输能力,关键在肥而不在长,接收端的接收能力需要和“肥”相匹配,与长无关。

因此,端到端传输能力取决于接收能力,而不是取决于rcvbuff的大小,rwnd应该基于接收能力计算而不是rcvbuff。

程序应该从协议栈用力吸数据。

换一句话就说明白了,网络传输能力取决于瓶颈带宽BltBW而不是路由器buffer。现在大家都认同BBR比CUBIC更合理,把这认同搬到端到端流控就是一个意思。既然BBR不以填充buffer为目标,rwnd也不应受rcvbuff的限制。

rcvbuff的作用是“暂存尚未被应用程序取走的积压数据”,而不是限制发送量。只要保证积压数据量维持在rcvbuff内即可。因此,合理的流控措施是,监测rcvbuff积压量或者积压率越过一定阈值,缩小rwnd进行源抑制。

如果应用程序发生了抖动降低了读取速率,rcvbuff开始堆积,至于rcvbuff需要多大,取决于接收端能以多快的速度抑制发送端,这个时间不会短于半个RTT。抖动处理应该整体考虑,rcvbuff溢出只是其中一环,类似于拥塞控制,需要启发式算法。

流控和拥塞控制是统一的,cwnd控制网络拥塞,rwnd控制程序降速,后者也是一种拥塞,网络拥塞交换机buffer排队,程序降速rcvbuff排队,本质是一回事。

我觉得正常理解流控就该是以上这个样子,反而Linux TCP的实现显得怪怪的。但大家都在Linux这个台面上工作,目之所及全是它,也就难免认为Linux都是正确的了。

跟同事及几个朋友深入聊过这个话题后,我决定挖一下坟,看看原始的TCP怎么说。从1974年原汁原味的RFC675。果然找到了证据:

下面这段更明显:

还给出了一个具体算法:

详情参见:Specification of Internet Transmission Control Program
最后这个算法很有趣,它可作为一个通配的自适应rwnd计算公式,省的去probe了:

其中F/B是rcvbuff的当前填充率,痛则不通,通则不痛,显然填充率越高越不好,填充率设为x,Wmax为允许的最大rwnd,a暂取2,这个公式就是:

W’ = W*(1-F/B)^a

显然,实际的rwnd可根据应用程序实际读的速率在0到Wmax之间自适应:

  • 程序读得慢了,rcvbuff堆积,x变大,rwnd变小。
  • 程序读得快了,rcvbuff清空,x变小,rwnd趋向于Wmax。

简单有效!

可是为什么Linux却采用了一种截然不同的错误方式计算rwnd呢?我想是因为RFC675太陈年了,一般都以RFC793为准,但RFC793并没详细描述rwnd的计算。根本没几个人知道RFC675。

拥塞算法一直都希望用buffer堆积来识别拥塞并计算cwnd,但buffer堆积是端到端不可见的,不得不让RTT参与间接度量buffer堆积,但依然测不准。对于流控而言,rcvbuff堆积则是真实可观测的,流控范畴的拥塞控制便可用更加直接的方式:

  • rcvbuff在堆积,降速,rcvbuff在清空,加速。

说了这么多,最终还是要落地。我不怎么会编程,自己在填充一条长肥管道时只能采用手工hack的方式,如果要正式修改Linux内核TCP实现,我没能力也没兴趣,看到这篇文字的工人如果有兴趣可以实现上述那个公式,替换掉 rwnd = min(sysctl_tcp_rmem[2], copied_to_user) 这个算法:

rwnd = Wmax * (1 - queue_len/rcvbuff_size)^2。

若queue_len等于rcvbuff_size,则丢掉新收的skb。

好办法!具体的测试程序明天再写(我不会编程,只能写个简单的模拟,置入内核太麻烦,无能为力),今天先MARK。

若要这个新算法高效工作,需要TCP pacing。pacing是一种现代的传输方式,而burst则属于传统。参考下面的论文深入了解:
Understanding the Performance of TCP Pacing
最重要的一张图:

按照排队理论定性理解上图,但不要按照排队理论去计算,现实网络并不符合泊松分布。

长肥管道高利用率的关键是pacing,pacing匹配接收端的处理速率,有效减少对rcvbuff的依赖,和BBR模型一致。减少对buffer的依赖,是pacing相对于burst更现代的原因。

多思考一点,能否将RFC675中计算rwnd的公式反过来用于网络拥塞控制呢?完全可以,但需要改一改。由于端到端无法直接测量buffer用量,只能用RTT间接体现,这是什么?这不就是Vegas吗?BBR吸取了时延算法的精髓,将时延用作分母来测量带宽,这一切都来自历史源头,RFC675。

周末了,总结一下rwnd新算法。主要是挖了一下RFC675这座老坟,证明最初的TCP就是按照程序的读取能力自适应rwnd的,而不是按rcvbuff的硬限制确定rwnd,这是一个自然而然的想法。RFC675根本就没有几个人知道,RFC793倒是妇孺皆知,但793却没有描述rwnd算法,加上Linux太流行了,Linux当然说什么就是什么咯。但无论Linux再“正确”,它计算rwnd的算法也是错误的。自然而然的rwnd算法和河流类似,在上海不管是长江还是川杨河,都会满满流量自然汇入东海,入海口没有任何buffer,在山区山洪流入小溪的场景却相反,山洪在汇入小溪的地方会形成堰塞湖,这是一个巨大的buffer,让小溪慢慢消化,若堰塞湖溢出,将会带来灾难。今天先写个笔录,明天写个测试程序。

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

TCP rwnd算法挖坟相关推荐

  1. TCP BBR算法与Reno/CUBIC的对比

    我一再强调,BBR算法是个分界点,所有的TCP拥塞控制算法,被分为BBR之前和BBR之后的(其实发现,这并不是我个人的观点,很多人都这么认为,所有想写本文探个究竟).当然这里的"所有&quo ...

  2. 维密求变,“自救”还是“挖坟”?

    文|佘凯文 来源 | 螳螂财经(ID:TanglangFin) 看来继今年的"维密秀"被取消后,明年会不会有也很难说了! 前不久,接连两条关于维密的消息被爆出,又一次将维密推上了舆 ...

  3. TCP 漕河泾算法(tcp_caohejing)

    题目没意义,要说意义,大致类似于 Vegas,Reno,Tahoe,Westwood,地名. 周三傍晚发一则朋友圈: 总之,名字就是个名字,跟 tcp_vegas,tcp_reno,tcp_tahoe ...

  4. 【RFC6582 TCP快速恢复算法的NewReno修改】(翻译)

    原文 https://datatracker.ietf.org/doc/html/rfc6582  The NewReno Modification to TCP's Fast Recovery Al ...

  5. 百度贴吧挖坟实时监控 python版

    有人挖坟会挖坟后即刻删掉自己的回复.让吧务不知道是谁把坟贴挖上来. 代码如下 ''' # -*- coding: utf-8 -*- 这段代码实现的是实时监控,一旦发现有挖坟者,自动在屏幕上显示.并且 ...

  6. ue4 怎么修改骨骼动画_【2017 GDC挖坟】守望先锋动画制作管线(下篇)

    写在前面的话:GDC总是可以挖掘到很多值得学习的分享,今天拆解一下2017GDC上关于动画管线的分享,里面很多东西值得借鉴.思考,文中偶尔会有一点自己的想法.总结,欢迎大佬吐槽.提意见.(文章很长,多 ...

  7. Scalable TCP拥塞算法

    Scalable TCP(STCP)拥塞控制算法,在每个RTT周期内,如果没有发生拥塞,将在接收到每个ACK报文后,将拥塞窗口增加0.01(a值). cwnd = cwnd + 0.01 如果在一个R ...

  8. cubic算法优化_安卓cpu优化tcp拥塞算法cubic和reno怎么选择?

    上述具体的论文可以参考:CUBIC: A New TCP-Friendly High-Speed TCP Variant 1. tcp cubic数学模型 CUBIC在设计上简化了BIC-TCP的窗口 ...

  9. cubic算法优化_安卓cpu优化 tcp拥塞算法cubic和reno怎么选择

    上述具体的论文可以62616964757a686964616fe59b9ee7ad9431333365643662参考:CUBIC: A New TCP-Friendly High-Speed TCP ...

最新文章

  1. python文本处理实例_Python 文件处理的简单示例
  2. 详解让人闹心的C++语句 cout<<“Hello“<<endl;
  3. 【控制】《多智能体系统的动力学分析与设计》徐光辉老师-第9章-不确定分数阶系统的包含控制
  4. register_chrdev深入分析
  5. Python字符串常用函数详解
  6. 最简单的教程:在Ubuntu操作系统里安装Docker
  7. frontpage编辑html,怎样用FrontPage软件编辑HTML帖子 | 音画代码学堂 - 中国音画家园 - Po...****...
  8. 第一章 Linux系统简介
  9. NodeJS的安装与使用
  10. textarea内容有换行时存入数据库丢失问题的解决 (转载)
  11. php通过smtp发送邮件源码_PHP SMTP发送邮件函数
  12. 【葫芦娃团队】无人转会申请
  13. 真正好的东西,就会脱颖而出
  14. (一)Linux 常用命令
  15. 平面一般力系最多可以求解_利用平面任意力系的平衡方程最多可求解几个未知量(  )。...
  16. 大麦 Android 选座场景性能优化全解析
  17. 手机连Fiddler后,仍然不能上网的解决办法
  18. 通过google的gson把xml转成json
  19. 宋叔日记--新手级别入门全能赚钱软件!
  20. Oracle中创建和使用触发器Trigger

热门文章

  1. SaaSpace:2022年十大最好的免费动画软件
  2. 搭建linux服务器网络代理
  3. 华为代理服务器相关配置
  4. 第一个Python程序-HelloWorld与Python解释器
  5. Qomo OpenProject Field Test 4发布!
  6. 北京大学计算机语言学考博,北京大学中文系语言学及应用语言学考博经验贴(理论语言学)...
  7. pycharm配置robot framework
  8. 补第十五周leetcode算法博客
  9. Win10 突然蓝屏安全模式进不了,没有别的电脑和装机U盘,怎么把资料临时导出来?
  10. linux怎么清除防火墙规则,linux怎么查看防火墙是否开启并清除防火墙规则?