为什么多 TCP 连接分块下载比单连接下载快?

我观察到,客户端机器从单一服务器使用 HTTP 下载一个文件: 1. 单连接下载,速度没有达到客户端网络的最大带宽; 2. 多连接同时下载,传输速度有极大的提高,带宽被占满。 假设如下前提: 1. 服务器是单一的,没有使用提供相同文件的其它服务器,也没有使用同域名的其它服务器; 2. 服务器不对单个连接限速。 那么,是什么导致多连接下载的速度大为提高呢?换一种说法,是什么原因导致单一 TCP 连接没有尽可能地利用带宽呢? 是…
关注者
902
被浏览
33313

8 个回答

简短版本:

TCP特性使得每个TCP连接可以得到均等的带宽。在多用户环境下,一个用户拥有越多TCP连接,获得的带宽越大。

具体来说:

这个涉及到了TCP的拥塞控制。

我们先看一下单TCP连接的拥塞控制。

这是一个TCP连接的发送窗口。

绿色部分为发送者已发送,且接收者已确认(ACKed)。
黄色部分为发送者已发送,但接收者尚未确认("in-flight")。
蓝色部分为可用但尚未发送。
灰色部分为不可用。

所以在RTT(round-trip time,来回通讯延迟)不变的情况下,cwnd这个变量基本决定传输速率。
发送者总会试图找到不丢包情况下的最大速率。按照TCP协议,在传输开始之后,每接收到一个确认(ACK)就会把cwnd这个变量增大一倍。所以TCP连接开始之后应该是这个样子。
刚开始的时候传输速率应该是指数被增长的,直到丢包发生。丢包会有两种情况:
1.当接收者发送给发送者的ACK丢失了,这时会触发超时(timeout)。
2.当发送者发送给接收者的数据包丢失了,发送者会收到接收者发来的重复ACK,如果发送者收到了3个重复的ACK,也会认为发生了丢包。

具体对这两种情况采取的措施略有不同,但粗略来说,变量cwnd会被减半,也就是说传输速率减半。然后cwnd会再次增大,直到下次丢包发生。所以忽略最开始,TCP的吞吐量应该是这样。

好,那么现在我们来看多TCP连接的拥塞控制。
我们假设有两条同样的TCP连接。在他们的连接中间有一个共用的瓶颈路由器,带宽为R。
假设这两条连接都需要传输足够大量的数据,那么不论他们谁先开始传输,最后一定会均分带宽。
因为如果总传输速率低于R的时候就会不断增大传输速率,某个连接在增大传输速率的时候发生丢包就会减半传输速率,最后趋于平衡。

所以k条经过同一节点TCP连接会平分带宽R,每条连接得到带宽R/k。

正因为如此,不论是以前的net vampire,还是现在的迅雷都采取增加并发连接数的方法来加快下载速度。

references:
1、2楼的回答都对,问题的关键,其实是在路由器上。

在不存在链路争用的情况下,单连接可以做到和多连接一样快。
例如,我这里局域网用的是百兆交换机,下载文件到内存,可以达到11.3MB/s:

百兆的理论速率是12.5MB/s(100Mbps),考虑到帧间隔、不同包长等因素,这个速率比较接近理论速率了。在此情况下,“多连接比单连接下载快”并不成立,或者说,只有很小的性能提升。

推而广之,假设你的PC和python.org的服务器之间的所有交换设备(路由器、防火墙、交换机等),都只为你的这个下载提供服务,等价于你独占这整个传输通道的全部带宽,此时,单连接下载也不会比多连接下载慢多少。

问题是,这些中间设备,通常服务于成千上百(万)的用户,带宽是供所有的用户共享使用的。路由器的带宽有限,无法保证每个连接都按照它所能支持的最大速率进行传输,即便不考虑路由器本身做的流量控制功能,单单这成百上千(万)的用户访问所形成的TCP连接之间的竞争,就会产生如1楼所说的,各连接均分整个带宽的情况。
因此,现实环境下,由于传输网络的带宽有限,通常各个连接会均分带宽,导致单连接下载时速率较低,而多连接下载时速率较高。