vault backup: 2026-05-27 00:12:00
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
---
|
||||
tags: [计算机网络, 带宽, 延迟, RTT, 吞吐量, BDP]
|
||||
tags: [计算机网络, 带宽, 延迟, RTT, 吞吐量, BDP, Jitter, Goodput]
|
||||
create time: 2026-05-17 22:40
|
||||
---
|
||||
|
||||
@@ -29,26 +29,52 @@ create time: 2026-05-17 22:40
|
||||
> [!tip] bit vs Byte:记住除 8
|
||||
> 运营商说的 "100M 宽带" 是 **100 Mbps**。换算成下载速度约 `100 ÷ 8 ≈ 12.5 MB/s`。
|
||||
|
||||
### 延迟(Latency / Propagation Delay)
|
||||
### 延迟(Latency)
|
||||
|
||||
信号从发送端传播到接收端所需的时间,仅取决于**物理距离和介质光速**:
|
||||
一个数据包从发送到被接收所经历的**总时间**,由四部分组成:
|
||||
|
||||
$$\text{Prop. Delay} = \frac{\text{Distance}}{v}$$
|
||||
$$\text{Latency} = \text{传播延迟} + \text{传输延迟} + \text{排队延迟} + \text{处理延迟}$$
|
||||
|
||||
其中 $v$ 是传播速度。光纤中光速约为 $2 \times 10^8$ m/s(真空中光速的 2/3)。
|
||||
```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 |
|
||||
| TCP 握手 + TLS 1.3 | 1~2 RTT(额外 RTT × 加密计算时间) |
|
||||
|
||||
> [!tip] TCP + TLS 的额外延迟
|
||||
> 建立一个 HTTPS 连接还需要 **TCP 三次握手(1 RTT)+ TLS 1.3 握手(1 RTT)**,在数据发出前就已经"花掉"了 2 个 RTT。这也是 HTTP/2、连接复用和 TLS Session Resumption 存在的重要原因。
|
||||
|
||||
### RTT(Round-Trip Time)
|
||||
|
||||
从发送方发出数据包到收到确认应答的总时间。**RTT = 2 × 单向延迟 + 排队处理时间 + 传输时间**。
|
||||
从发送方发出数据包到收到确认应答的总时间。严格来说:
|
||||
|
||||
$$\text{RTT} = 2 \times (\text{传播延迟} + \text{传输延迟} + \text{排队延迟} + \text{处理延迟})$$
|
||||
|
||||
实际测量中,`ping` 工具测得的 RTT 主要反映传播延迟(往返),而 TCP 的 RTT 估算(用于计算 RTO)还需包含协议栈处理时间。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -60,6 +86,22 @@ flowchart LR
|
||||
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)
|
||||
|
||||
单位时间内**实际成功传输的数据量**,受限于最窄环节:
|
||||
@@ -86,6 +128,11 @@ flowchart LR
|
||||
> [!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)** 定义了链路上"在途"数据的最大量——这是维持满带宽所需的发送缓冲大小:
|
||||
@@ -138,28 +185,46 @@ flowchart TD
|
||||
|
||||
## Go 中的实践示例
|
||||
|
||||
```go
|
||||
// 设置 TCP 连接保持活跃,定期检测死链接
|
||||
tcp := net.ListenConfig{
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
return c.Control(func() {
|
||||
// 开启 keepalive,每 30s 探测一次
|
||||
syscall.SetsockoptInt(int(c.Fd()), syscall.SOL_SOCKET,
|
||||
syscall.SO_KEEPALIVE, 1)
|
||||
})
|
||||
},
|
||||
}
|
||||
### 测量 RTT(TCP 连接延迟)
|
||||
|
||||
// HTTP Transport 的连接池配置
|
||||
transport := &http.Transport{
|
||||
MaxIdleConns: 100, // 最多空闲连接数
|
||||
MaxIdleConnsPerHost: 10, // 每个 host 最多 10 个空闲
|
||||
IdleConnTimeout: 90 * time.Second, // 空闲超时释放
|
||||
```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/OSI与TCP-IP模型对比]] — 网络分层中各层的角色
|
||||
- [[hhs/NETWORK/TCP状态机详解]] — TCP 的拥塞控制直接影响吞吐量
|
||||
- [[hhs/NETWORK/TCP内核参数调优]] — BDP 对应内核参数 rmem/wmem
|
||||
- [[hhs/NETWORK/01-基础概念/01-OSI与TCP-IP模型对比]] — 网络分层中各层的角色
|
||||
- [[hhs/NETWORK/09-性能优化/01-TCP内核调优与连接复用]] — BDP 对应内核参数 rmem/wmem
|
||||
|
||||
Reference in New Issue
Block a user