计算 Link 吞吐量的正确方法

Proper way to calculate Link Throughput

我在网上阅读了一些文章,对一般的 TCP 和 UDP 有了很好的了解。但是,我仍然有一些疑惑,我肯定不是很清楚。

What is the proper way to calculate throughput ?

(Can't we just divide Total number of bytes received by total time taken ?)

What is that key feature in TCP that makes it have much much higher throughput than UDP ?

更新:

我知道 TCP 使用 windows 这只不过是在实际等待确认之前可以发送那么多的段。但我的疑问是,在 UDP 中,段是连续发送的,甚至不关心确认。所以 UDP 中没有额外的开销。那么,为什么TCP的吞吐量比UDP高很多呢?

最后,

这是真的吗?

TCP throughput = (TCP Window Size / RTT) = BDP / RTT = (Link Speed in Bytes/sec * RTT)/RTT = Link Speed in Bytes/sec

如果是这样,则 TCP 吞吐量始终等于已知 Link 速度。由于 RTT 相互抵消,TCP 吞吐量甚至不依赖于 RTT。

我在一些网络分析工具(如 iperf、passmark 性能测试等)中看到 TCP/UDP 吞吐量随块大小而变化。

How is throughput dependent on Block size ? Is Block size equals TCP window or UDP datagram size ?

计算吞吐量的正确方法是什么?

有多种方法,具体取决于您要测量的内容。正如您提到的,它们都归结为将一定数量的位(或字节)划分为一定的持续时间;不同的是您正在计算哪些位或(很少)您正在考虑测量持续时间的哪些时刻。

您需要考虑的因素有:

您在网络堆栈的哪一层测量吞吐量?

如果您在应用层进行测量,那么重要的是您将哪些有用的数据传输到另一个端点。例如,如果您正在传输 6 kB 的文件,则测量吞吐量时计算的数据量为 6 kB(即 6,000 字节,而不是位,并注意乘数 1000,而不是 1024;这些约定在网络中很常见).

这通常称为 goodput,它可能与传输层(如 TCP 或 UDP)实际发送的内容不同,原因有二:

1。由于 headers

造成的开销

网络中的每一层都向数据添加了一个 header,由于其传输时间而引入了一些开销。此外,传输层将您的数据分成多个部分;这是因为网络层(如在 IPv4 或 IPv6 中)的最大数据包大小称为 MTU, typically 1,500 B in Ethernet networks. This value includes the network layer header size (e.g. the IPv4 header, which is variable in length but usually 20 B long) and the transport layer header (for TCP, it is also variable in length but usually 40 B long). This leads to a maximum segment size MSS(数据字节数,没有 headers,在一个段中)为 1500 - 40 - 20 = 1440字节。

因此,如果我们要发送 6 kB 的 application-layer 数据,我们必须将其分成 6 个段,每个段 4 个 1440 字节和一个 240 字节。但是在网络层,我们最终发送了 6 个数据包,每个 1500 字节有 4 个,每个 300 字节有一个,总共 6.3 kB。

这里我没有考虑 link 层(如 Ethernet)添加自己的 header 并且可能还有一个后缀,这进一步增加了开销。对于以太网,以太网 header 为 14 个字节,可选的 VLAN 标记为 4 个字节,然后是 4 个字节的 CRC 和 12 个字节的间隙,每个数据包总共 36 个字节。

如果您考虑 fixed-rate link,比如说 10 Mb/s,根据您测量的内容,您将获得不同的吞吐量。通常您需要其中之一:

  • goodput,即应用层吞吐量,如果你想衡量的是应用性能。对于此示例,您将 6 kB 除以传输持续时间。
  • link-layer 吞吐量,如果您要衡量的是网络性能。对于此示例,您将 6 kB + TCP 开销 + IP 开销 + 以太网开销 = 6.3 kB + 5 * 36 B = 6516 B 除以传输持续时间。

重传开销

Internet 是一个 best-effort 网络,这意味着数据包将尽可能传送,但也可能被丢弃。在 TCP 的情况下,数据包丢失由传输层纠正;对于UDP,没有这样的机制,这意味着要么应用程序不关心是否某些部分数据没有被传递,要么应用程序在UDP之上实现自己的重传。

重传减少吞吐量有两个原因:

一个。有些数据需要重新发送,需要时间。这引入了一个延迟,它与发送方和接收方之间网络中最慢的 link 的速率成反比(a.k.a 瓶颈 link)。 b.检测到某些数据未交付需要从接收方到发送方的反馈。由于传播延迟(有时称为延迟;由光在电缆中的有限速度引起),反馈只能由发送者以一定的延迟接收,这进一步减慢了传输速度。在大多数实际情况下,这是对重传造成的额外延迟的最大贡献。

显然,如果您使用 UDP 而不是 TCP,并且您不关心数据包丢失,您当然会获得更好的性能。但是对于很多应用来说,数据丢失是不能容忍的,所以这样的测量是没有意义的。

有些应用程序确实使用 UDP 传输数据。一种是 BitTorrent,它可以使用 TCP 或他们设计的称为 uTP, which emulates TCP on top of UDP, but aims at being more efficient with many parallel connections. Another transport protocol implemented over UDP is QUIC 的协议,它也模拟 TCP 并通过单个连接提供多路复用多个并行传输,并提供前向纠错以减少重传。

我将稍微讨论一下前向纠错,因为它与您关于吞吐量的问题有关。一种简单的实现方式是将每个数据包发送两次;万一一个丢失了,另一个仍然有机会被接收。这将重传数量减少了一半,但由于您发送了冗余数据,因此您的吞吐量也减少了一半(请注意,网络或 link 层吞吐量保持不变!)。在某些情况下这很好;特别是在延迟非常大的情况下,例如在洲际或卫星 links 上。此外,存在一些数学方法,您不必发送完整的数据副本;例如对于您发送的每 n 个数据包,您都会发送另一个冗余数据包,即它们的 XOR(或其他一些算术运算);多余的丢了也没关系;如果n个数据包中有一个丢失了,你可以根据冗余的一个和另一个n-1重建它。因此,您可以将前向纠错引入的开销配置为您可以腾出的任何带宽量。

您是如何测量传输时间的

当发送方通过网络发送完最后一位时,传输是否完成,或者它是否还包括最后一位传送到接收方所花费的时间?此外,它是否包括接收方确认所有数据已成功接收且无需重传所需的时间?

这真的取决于你想测量什么。请注意,对于大型传输,在大多数情况下,额外的 round-trip-time 是微不足道的(除非您正在通信,例如,与火星上的探测器进行通信)。

TCP 的吞吐量比 UDP 高得多的关键特性是什么?

这不是真的,尽管这是一个常见的误解。

TCP除了在需要的时候重传数据外,还会调整自己的发送速率,这样就不会因为网络拥塞而导致丢包。调整算法经过几十年的完善,通常会很快收敛到网络支持的最大速率(实际上是瓶颈link)。因此,通常很难在吞吐量方面击败 TCP。

使用 UDP,发送方没有速率限制。 UDP 允许应用程序发送它想要的数据。但是如果你试图发送超过网络可以处理的数据,一些数据将会被丢弃,降低你的吞吐量,并且让你正在拥塞的网络的管理员非常生气。这意味着以高速率发送 UDP 流量是不切实际的(除非目标是对网络进行 DoS)。

一些 media applications 正在使用 UDP,但 rate-limiting 发送方的传输速度非常低。这通常用于 VoIP 应用程序或 Internet 广播,在这些应用程序中您需要非常低的吞吐量但延迟很低。我想这是 UDP 比 TCP 慢的误解的原因之一;事实并非如此,UDP 可以达到网络允许的速度。

正如我之前所说,有一些协议(例如 uTP 或 QUIC)在 UDP 上实现,其性能与 TCP 类似。

这是真的吗?

TCP throughput = (TCP Window Size / RTT)

没有丢包(和重传),这是正确的。

TCP throughput = BDP / RTT = (Link Speed in Bytes/sec * RTT)/RTT = Link Speed in Bytes/sec

仅当 window 大小配置为最佳值时才正确。 BDP/RTT 是网络中的最佳(最大可能)传输速率。大多数现代操作系统应该能够 auto-configure 优化它。

吞吐量如何取决于块大小?块大小等于 TCP window 还是 UDP 数据报大小?

我在 iperf documentation 中没有看到任何块大小。

如果您参考 TCP window 大小,如果它小于 BDP,那么您的吞吐量将不是最佳的(因为您浪费时间等待 ACK 而不是发送更多数据;如果需要我可以解释进一步)。如果它等于或高于 BDP,那么您将获得最佳吞吐量。

这取决于你如何定义"Throughput"。通常可以是以下之一。

  1. 固定时间内发送的字节数(或比特数);
  2. 固定时间内接收端发送和接收的字节数(或比特数);

当人们谈论吞吐量时,您可以将这些定义应用于每一层。在应用层,第二个定义是指字节真正被应用的接收端接收到。有些人将其称为 "goodput"。在传输层,比如 TCP,第二个定义意味着接收到相应的 TCP ACK。对我来说,大多数人应该只对接收端真正接收到的字节感兴趣。所以,第二个定义通常是人们所说的 "Throughput"。

现在,一旦我们对吞吐量有了明确的定义(第二个定义)。我们可以讨论如何正确测量吞吐量。

通常,人们使用 TCP 或 UDP 来衡量网络吞吐量。

TCP:人们通常只在发送端测量TCP吞吐量。对于接收端成功接收到的数据包,将发回ACK。因此,发送方本身将知道接收方发送和接收了多少字节。将这个数字除以测量时间,我们就会知道吞吐量。

但是,TCP吞吐量测量需要注意两点:

  1. 发送方在测量期间是否总是满缓冲区?即在测量期间,发送方应该总是有数据包要发送。这对于正确的吞吐量测量很重要。例如如果我将测量时间设置为 60 秒,但我的文件已在 40 秒内完成传输。然后有 20 秒网络实际上是空闲的。我会低估吞吐量。

  2. TCP 速率由其拥塞 window 大小、慢启动持续时间、发送方 window(和接收方 window)大小调节。这些参数的次优配置将导致低估 TCP 吞吐量。虽然大多数现代 TCP 实现应该对所有这些都有很好的配置,但测试人员很难 100% 确定所有这些配置都是最佳的。

由于TCP在网络吞吐量估算中的这些limitations/risks,相当多的研究人员会使用UDP来测量网络吞吐量。

UDP:由于UDP在成功接收数据包后没有ACK发回,因此人们必须测量接收端的吞吐量。或者,如果接收端不容易访问,人们可以比较发送端和接收端的日志来确定吞吐量。但是,一些吞吐量测量工具减轻了这种不便。例如,iperf 在其定制的有效负载中嵌入了序列号,因此它可以检测到任何丢失。此外,接收方的报告将发送给发送方以显示吞吐量。

因为 UDP 本质上只是将它所拥有的一切发送到网络而不是等待反馈。一旦测量,它的吞吐量(记住第二个定义)将是网络的实际容量(或带宽)。

因此,通常情况下,UDP 测量的吞吐量应该高于 TCP,尽管差异应该很小 (~5%-10%)。

UDP 吞吐量测量的一个最大缺点是,在使用 UDP 时还应确保发送方缓冲区必须已满。 (否则,它会导致像 TCP 一样低估吞吐量)。这一步会有点棘手。在 iperf 中,可以通过 -b 选项指定发送速率。在不同轮次的测试中增加 -b 值将收敛测量的吞吐量。比如在我的千兆以太网中,我首先在测试中使用-b 100k。测得的吞吐量为 100Kbps。然后我执行以下迭代以收敛最大吞吐量,这是我的以太网容量。

-b 1m --> 吞吐量:1Mbps

-b 10m --> 吞吐量:10Mbps

-b 100m --> 吞吐量:100Mbps

-b 200m --> 吞吐量:170Mbps

-b 180m --> throughput: 175Mbps (这应该和实际容量很接近)