Files
cs-note/hhs/NETWORK/01-基础概念/04-带宽延迟RTT与吞吐量.md
T
2026-05-27 00:12:00 +08:00

231 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [计算机网络, 带宽, 延迟, RTT, 吞吐量, BDP, Jitter, Goodput]
create time: 2026-05-17 22:40
---
# 带宽、延迟、RTT、吞吐量
## 概述
理解网络性能的核心指标,是优化应用的前提。带宽决定"管道有多粗",延迟决定"跑一程要多久",RTT 是往返一次的时间,而吞吐量是实际能搬多少数据。它们之间的关系经常影响系统架构设计。
## 核心定义
### 带宽(Bandwidth)
单位时间内能传输的**最大比特数**,通常用 bps(bits per second)表示:
```
1 Gbps = 10⁹ bits/s = 125 MB/s(注意:bit vs Byte)
```
| 链路类型 | 理论带宽 | 实际可用 |
|----------|---------|---------|
| 千兆以太网 (GbE) | 1 Gbps | ~940 Mbps(协议开销) |
| Wi-Fi 6 (802.11ax) | 9.6 Gbps | ~1.2–2 Gbps(理论峰值) |
| SATA III | 6 Gbps | 600 MB/s 实际 |
| PCIe 4.0 x16 | 32 Gbps | ~3.9 GB/s |
> [!tip] bit vs Byte:记住除 8
> 运营商说的 "100M 宽带" 是 **100 Mbps**。换算成下载速度约 `100 ÷ 8 ≈ 12.5 MB/s`。
### 延迟(Latency)
一个数据包从发送到被接收所经历的**总时间**,由四部分组成:
$$\text{Latency} = \text{传播延迟} + \text{传输延迟} + \text{排队延迟} + \text{处理延迟}$$
```mermaid
flowchart LR
A["传播延迟<br/>Propagation"] --> B["传输延迟<br/>Transmission"]
B --> C["排队延迟<br/>Queuing"]
C --> D["处理延迟<br/>Processing"]
style A fill:#DDA0DD,color:#000
style B fill:#87CEEB,color:#000
style C fill:#FFD700,color:#000
style D fill:#98FB98,color:#000
```
| 延迟类型 | 公式 | 取决于 | 典型值 |
|---------|------|--------|--------|
| **传播延迟** | $\frac{\text{Distance}}{v}$ | 物理距离、介质 | 光纤中 $v \approx 2 \times 10^8$ m/s(真空中光速的 2/3) |
| **传输延迟** | $\frac{\text{Packet Size}}{\text{Bandwidth}}$ | 数据包大小、链路带宽 | 1500B 以太网帧在 1Gbps 链路上 ≈ 12 μs |
| **排队延迟** | 不确定 | 路由器拥塞程度 | 空闲时 ≈ 0,拥塞时可达数百 ms |
| **处理延迟** | 不确定 | 路由器/交换机性能 | 通常 < 1 ms |
> [!question] 这四类延迟,哪个最"不可控"?
> 排队延迟。传播延迟由物理距离决定(选不了机房位置就改不了),传输延迟由包大小和带宽决定,处理延迟通常很小。但排队延迟随网络拥塞程度剧烈波动——这也是为什么它直接关联**抖动(Jitter)** 和 **丢包**。
| 场景 | 典型单向延迟(主要贡献:传播延迟) |
|------|---------|
| 同机房内 | 0.1–1 ms |
| 同城(同一城市数据中心) | 1–5 ms |
| 跨省(国内) | 20–40 ms |
| 跨洋(中美) | 80–150 ms |
| 卫星轨道(LEO) | 20–40 ms |
> [!tip] TCP + TLS 的额外延迟
> 建立一个 HTTPS 连接还需要 **TCP 三次握手(1 RTT)+ TLS 1.3 握手(1 RTT)**,在数据发出前就已经"花掉"了 2 个 RTT。这也是 HTTP/2、连接复用和 TLS Session Resumption 存在的重要原因。
### RTT(Round-Trip Time)
从发送方发出数据包到收到确认应答的总时间。严格来说:
$$\text{RTT} = 2 \times (\text{传播延迟} + \text{传输延迟} + \text{排队延迟} + \text{处理延迟})$$
实际测量中,`ping` 工具测得的 RTT 主要反映传播延迟(往返),而 TCP 的 RTT 估算(用于计算 RTO)还需包含协议栈处理时间。
```mermaid
flowchart LR
A["t=0ms: 发送 SYN"] -->|"传播+路由器处理"| B["t=5ms: 到达服务端"]
B -->|"处理+准备响应"| C["t=5.1ms: 服务端回发 SYN-ACK"]
C -->|"传播+路由器处理"| D["t=10.2ms: 客户端收到 → RTT = 10.2ms"]
style A fill:#DDA0DD,color:#000
style D fill:#98FB98,color:#000
```
### 抖动(Jitter)
连续数据包之间延迟的**变化量**。即使平均延迟很低,抖动大也会严重影响体验:
$$\text{Jitter} = |\text{RTT}_n - \text{RTT}_{n-1}|$$
| 应用类型 | 对抖动的敏感度 | 说明 |
|---------|--------------|------|
| 语音通话 / 视频会议 | 🔴 极高 | 抖动 > 30ms 就会出现卡顿、断续 |
| 在线游戏 | 🔴 高 | 操作响应不稳定,玩家体验崩塌 |
| 文件下载 | 🟢 无所谓 | 只关心总吞吐量,不在乎每个包的到达节奏 |
| HTTP API 调用 | 🟡 中等 | 长尾延迟影响 P99 响应时间 |
> [!question] 如何对抗抖动?
> 答案是**接收端缓冲(Jitter Buffer)**。音视频应用会在接收端先攒一小段数据再播放,用少量额外延迟换取平滑输出。WebRTC 的 jitter buffer 通常 20–200ms。
### 吞吐量(Throughput)
单位时间内**实际成功传输的数据量**,受限于最窄环节:
$$\text{Throughput} = \min(\text{带宽}, \text{拥塞窗口限制}, \text{应用处理能力})$$
实际吞吐量永远 ≤ 带宽。常见瓶颈:
```mermaid
flowchart LR
A["磁盘IO<br/>可能 < 网卡"] --> B["TCP收发缓冲区"]
B --> C["网络带宽"]
C --> D["对端带宽"]
D --> E["对端CPU/应用"]
F["中间路由拥塞"] -.-> C
G["丢包重传"] -.-> C
style C fill:#FFD700,color:#000
style F fill:#FF6B6B,color:#fff
style G fill:#FF6B6B,color:#fff
```
> [!question] 为什么我的千兆网卡只跑到 100MB/s?
> 因为千兆以太网理论上限是 `1Gbps ÷ 8 = 125MB/s`,去掉以太网帧头、IP 头、TCP 头等协议开销后,纯 Payload 大约 **94 MB/s**。如果还用了 HTTPS/TLS,CPU 加解密还会进一步限制吞吐量。
> [!info] Goodput vs Throughput:别搞混
> **Throughput**(吞吐量)是单位时间内传输的**总数据量**(含协议头)。**Goodput**(有效吞吐量)是应用层实际收到的**有效数据量**,要扣除所有协议头、重传包、确认包等开销。
> $$\text{Goodput} < \text{Throughput} \leq \text{Bandwidth}$$
> 用 `iperf3` 测出来的通常是 throughput;你的文件下载速度反映的更接近 goodput。
## 带宽时延积(BDP)
**BDP(Bandwidth-Delay Product)** 定义了链路上"在途"数据的最大量——这是维持满带宽所需的发送缓冲大小:
$$\text{BDP} = \text{Bandwidth} \times \text{RTT}$$
### 实际意义
假设带宽 1 Gbps,RTT = 100 ms:
$$\text{BDP} = 10^9 \text{ bps} \times 0.1s = 10^8 \text{ bits} = 12.5 \text{ MB}$$
这意味着:
- TCP 发送窗口至少要有 **12.5 MB**,才能填满这条管道
- 如果窗口太小,TCP 会频繁停下来等 ACK,吞吐量上不去
- 这就是 Linux 的 `net.core.rmem_max` / `wmem_max` 要调大的原因
```mermaid
flowchart TD
Pipe["管道: 1Gbps, RTT=100ms<br/>BDP = 12.5MB"]
Small["发送窗口 1MB ❌<br/>只能填 8% 管道 → 吞吐量 ≈ 80Mbps"]
Big["发送窗口 25MB ✅<br/>填满管道 → 吞吐量 ≈ 1Gbps"]
Pipe --> Small
Pipe --> Big
style Small fill:#FF6B6B,color:#fff
style Big fill:#98FB98,color:#000
```
### 各场景 BDP 速查
| 链路 | 带宽 | RTT | BDP |
|------|------|-----|-----|
| 局域网 | 1 Gbps | 0.5 ms | 62.5 KB |
| 同机房 | 10 Gbps | 1 ms | 1.25 MB |
| 同省 | 1 Gbps | 20 ms | 2.5 MB |
| 跨洋 | 100 Mbps | 150 ms | 1.875 MB |
## 延迟 vs 带宽的典型对比
| 场景 | 带宽瓶颈还是延迟瓶颈? | 说明 |
|------|---------------------|------|
| 大文件传输 | 带宽 | 传输时间长,RTT 占比小 |
| 小请求/高频交互(RPC) | 延迟 | 每个请求 2~3 RTT,带宽几乎不占 |
| 视频流 | 带宽 | 持续大量数据传输 |
| DNS 查询 | 延迟 | 单次查询仅几十字节 |
| Web 首屏加载 | 两者兼有 | TCP+TLS握手(延迟)+ HTML/CSS/JS 下载(带宽) |
## Go 中的实践示例
### 测量 RTT(TCP 连接延迟)
```go
// 测量一次 TCP 连接的 RTT —— 最直接的延迟指标
func measureRTT(addr string) (time.Duration, error) {
start := time.Now()
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
if err != nil {
return 0, err
}
conn.Close()
return time.Since(start), nil // TCP 握手完成 ≈ 1 RTT
}
```
### 按 BDP 调大 TCP 缓冲区
```go
// 高带宽长延迟链路(如跨洋 100Mbps, RTT 150ms)的 BDP = 1.875MB
// 系统默认的 TCP 窗口(128KB~256KB)远远不够
transport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
d := net.Dialer{}
conn, err := d.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tcpConn := conn.(*net.TCPConn)
// 根据 BDP 设置读写缓冲区(2MB,略大于 BDP)
tcpConn.SetReadBuffer(2 << 20)
tcpConn.SetWriteBuffer(2 << 20)
return tcpConn, nil
},
}
```
> [!tip] 为什么不直接用系统默认窗口?
> Linux 默认 `tcp_rmem` 的最大值通常是 6MB,但单连接的初始窗口只有 ~128KB。对于高 BDP 链路,窗口增长(慢启动)到填满管道需要好几个 RTT,前几秒吞吐量会远低于带宽上限。应用层手动设大缓冲区 + 启用窗口缩放(`tcp_window_scaling`)可以加速这个过程。
## 关联笔记
- [[hhs/NETWORK/01-基础概念/01-OSI与TCP-IP模型对比]] — 网络分层中各层的角色
- [[hhs/NETWORK/09-性能优化/01-TCP内核调优与连接复用]] — BDP 对应内核参数 rmem/wmem