新 TCP 流控

Posted dog250

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了新 TCP 流控相关的知识,希望对你有一定的参考价值。

前面提到 Linux TCP rwnd 算法的问题:
TCP滑动窗口辩证考
TCP rwnd算法挖坟

就是说 rwnd 受限于 sysctl_tcp_rmem[2]。长肥管道场景,若 sysctl_tcp_rmem[2] 不足,则无法填满管道。必须配置足够大的 sysctl_tcp_rmem[2] 以通告足够大的 rwnd。

现在换个视角重新评估这个问题。

小 rwnd 就一定意味着低吞吐吗?并不是!

吞吐是速率,而 rwnd 是数量,若要高吞吐,把时间因素考虑进去才正确。若 ACK 以非常密集的 pacing 背靠背持续到达,即便每个 ACK 仅通告1个 mss 的 rwnd,足够密集的 pacing 也能激发大吞吐。

rwnd 不应体现可发多少,应体现可发多快。显然 Linux TCP 将 rwnd 等价于“一个 RTT 内可发送的数据量”。一个 RTT 作为固化周期控制总量,这是古老的 rwnd 通告方式,现代方式应将“两次读数据间隔内可发送的数据量”作为 rwnd。

古老方式没有把“应用程序读”作为流控因素考虑进来,只简单地将“当前可用的 free space ”作为 rwnd 通告给发送端,至于是这些 free space 是如何 be free 的,who cares。

简单的 iperf 打流,若 sysctl_tcp_rmem[2] 足够大,接收端 CPU 利用率会很高,带宽会打满,若 sysctl_tcp_rmem[2] 很小,接收端 iperf 进程将长时间睡眠等待数据,CPU 得不到充分利用。

接收端虽有能力以更快的速度接收数据,但由于一个 RTT 只能送 rwnd 数据,而 rwnd 受限于 sysctl_tcp_rmem[2] ,它不够大时,任凭应用程序读能力再强,无数据可读也是巧妇难为无米之炊了。

古老方式将 rcvbuff 里的数据往应用程序里“推”,带宽受限于 rcvbuff 的大小,现代方式则是应用程序主动从发送端 “拉” 数据,带宽自适应接收应用程序的读能力。

不改变 rwnd 算法的前提下,我这里有一种现代方法。让“应用程序读”事件参与流控即可:

  • 当应用程序有能力继续读时,接收端 TCP 主动向发送端通告当前 rwnd。

这意味着应用程序有能力读数据但 rcvbuff 里无数据可读时,可以主动将当前 free space 作为 rwnd 通告给发送端“刺激”发送端发数据。此法允许接收端应用程序采用 busy poll 的方式主动从发送端吸数据,每次(或每几次) poll 不到数据时就通告一下 rwnd。

Linux TCP 滑动窗口是数量窗口,没考虑时间因素,即数据被读取的速率,因此没看 rcvbuff 堆积动态,仅看绝对值。队列堆积动态情况甚至可以检测到丢包,窗口滑不动了,就堆积了,这样该多好啊。Linux rwnd 算法有性能问题,但我之前那篇文字改了算法,复杂了,没必要,别的系统我不知道怎么实现的,但大致也差不多。本文列举了一个简单的方法,没有改计算公式,也不需要 probe,只增加一个主动通告 rwnd 即可。

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

以上是关于新 TCP 流控的主要内容,如果未能解决你的问题,请参考以下文章

TCP 糊涂窗口综合症(silly window syndrome)与 rate-based 流控

举一反三:TCP协议是如何实现网络级的流控的?

TCP系列35—窗口管理&流控—9紧急机制

TCP系列34—窗口管理&流控—8缓存自动调整

TCP系列36—窗口管理&流控—10linux下的异常报文系列接收

TCP的流控滑动窗口和拥塞窗口的简单介绍