由浅入深网络协议——从一个文件的传输流程来看TCP的流量控制和拥塞控制

    不知道你有没有这样的疑惑,在你下载一个文件的过程中,为什么开始的传输速率慢,后面越来越快,最后又稳定在一个固定的值,中间的原理是什么呢?本文将会从原理上讲述一下典型的TCP流量控制和拥塞控制算法,虽然TCP的流量控制和拥塞控制已经是一个老生常谈的问题了,但现在很多网上给出的相关说明都是基于很老的TCP版本或者资料来进行的说明,在实际应用中会给人很多的疑惑。因此,本文会以一个文件传输的实例,向你阐述流量控制和拥塞控制在一个TCP传输过程中扮演什么样的角色。本文为系列文章第一篇,从tcp_reno来向大家阐述tcp的历史发展过程(tcp_tahoe实在太老了),后续会慢慢讲到tcp_vegas,以及较新的一些拥塞算法如:cubic,PPR(Proportional Rate Reduction),BBR等。

    本文适用读者:

        1.对于TCP的流量控制和拥塞控制有一点基本的概念,但对于其具体情况较为模糊

        2.对于拥塞控制的慢启动,拥塞避免,快速重传,流量控制的滑动窗口有一定基本概念

        3.希望了解在TCP数据传输过程中会面临哪些问题

    首先,我们给出一个笼统一些的说法,让你对流量控制和拥塞控制有一个基本的概念:

        1.TCP的流量控制是保证端到端的数据传输能够达到整个传输流程的最佳状态。

        2.TCP的拥塞控制是为了保证整个网络运行在最佳状态。

    OK,现在我们提出一个最简单的问题。

问题1

    盗用一个经典的拥塞控制的图:

                         

    我们看到,在一个tcp传输过程中,cwnd的值不会稳定在一个恒定的值,而会呈现一个锯齿状形式的波动,那为什么我们在下载一个文件(忽略P2P传输)的过程中下载速率会显得那么稳定呢?

问题2

    盗用一个经典的流量的控制的滑动窗口的图

                         

    可以看到,接收方通过ACK来告知发送端下一次可以发送的数据大小,大量的博客会告诉你,这个rwnd的最大值是65536字节,那么问题来了,当收发两端的时延很长时,比如RTT达到s的量级后,怎么保证数据的高速传输呢?(目前的TCP版本即使是RTT很长也能保证很快的传输速率)。

场景复现

    场景一(高速无丢包):我们来模拟一个高速传输且时延很长的情景,局域网内两台linux主机(内核版本低,使用tcp_reno)通信,通过tc命令将收发时延设置为0.5s,即一个RTT为1s,通过scp命令来传输一个70M的文件,然后我们来看看传输速度。根据慢启动算法,当cwnd小于定义的门限时,会在1个RTT内,将cwnd的值乘以2。由于本例中1个RTT为1s,因此,我们以1s为单位来观测传输速率。

    在无丢包环境:

    传输速率 16KB/s -> 33KB/s -> 70KB/s ->148KB/s ->302KB/s->610KB/s ->1.2MB/s ->1.3MB/s ->1.35MB/s ->1.4MB/s ->

 1.5MB/s ->1.6MB/s ->...1.8MB/s ->传输完成

    我们可以看到,忽略scp传输速度的统计误差,初始传输速率一直接近2的幂次方上涨,当超过ssthresh后,开始线性增加(这里稍微提一下,经典的cwnd变化图一般会用cwnd=cwnd*2或者cwnd=cwnd+1等方式来描述拥塞窗口的变化,此时cwnd的单位是MSS,当cwnd与rwnd相比较时,还是偏向于使用Byte为单位)。非常符合慢启动及拥塞避免的过程,但是问题来了,按照问题1的说明,传输速率也一直很稳定,并没有乘法减小的过程呢?同时根据问题2,rwnd的最大值为64K,一个RTT最大的数据传输也就只有64K了,怎么达到的1.8MB/s呢?

    首先解决问题1,在一个TCP的传输流程中,实际的发送窗口大小为min(cwnd,rwnd),而cwnd的降窗过程是当判定链路发生丢包(收到3个D-ACK,这里不再说tcp_tahoe的处理)才开启的,那么也就意味着,在我们的scp过程中,经过了慢启动过程,部分拥塞避免过程,后续的窗口大小已经几乎由rwnd来决定了,那么也就意味着,在我们的传输链路中,由于局域网无丢包(连接少,链路好),cwnd将处于并将长期处于拥塞避免状态,这个时候rwnd早已小于cwnd,cwnd增长对传输速率已经几乎无影响了,这也就形成了我们看到的传输速率稳定的现象。

    再来看问题2,先说下65536这个值是怎么来的,最早TCP协议涉及用来大范围网络传输时候,其实是没有超过56Kb/s的​连接速度的。因此,TCP包头中只保留了16bit用来标识窗口大小,允许的最大缓存大小不超过64KB。为了打破这一限制,RFC1323规定了TCP窗口尺寸选择,是在TCP连接开始的时候三步握手的时候协商的,会协商一个Window size scaling factor,之后交互数据中的是Window size value,所以最终的窗口大小是二者的乘积,我们来抓个包看一下:

    

    也就是说,新的tcp版本为了提升传输速率,提供了一个乘积因子,保证了传输速率能打到GB的量级,但是这个扩展相对也很简单,就是Window size scaling factor这个值在握手成功后是不可更改的,关于其具体说明存在于RFC1323中。

    我们现在知道,calculated window size才是实际传输过程中窗口的大小,那么这个值是怎么确定的呢?这里引入一个BDP(bandwidth-delay product,带宽时延积)的概念,这个概念很好理解,网络就像一个管道,管道的具体容量是多大呢?根据初中数学我们就能算出其具体容量为横截面乘以其长度,这里的带宽就是横截面,长度就是时延,于是BDP反映了一个通信收发两端在链路上的整体容量,忽略操作系统内核对于buffer区的处理速度的影响,为保证最佳吞吐率,那么一个窗口的大小最合适就是等于BDP的大小了,当然实际情况下还会做更多的考虑。这里再聊一下初始窗口的确定,根据我们前面的分析,传输的初始阶段,实际窗口大小是由cwnd决定,而cwnd通过慢启动不断以2的幂次方递增,cwnd的初始值这些年还是有很多变化,在Linux3.0以前,其确定方案为:min(4 * MSS, max(2 * MSS, 4380)),而以太网的MSS一般为1460Byte,也就是说其cwnd初始值为3个MSS,在Linux3.0以后,Google给的提案《An Argument for Increasing TCP's Initial Congestion Window》被采纳,初始窗口设为10个MSS,当然这个值也是可以在Linux中自己手动设定的。

 

    

    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值