vault backup: 2026-05-27 00:12:00

This commit is contained in:
hhs
2026-05-27 00:12:00 +08:00
parent 838e5e7824
commit 91b4fe3f36
9 changed files with 1116 additions and 180 deletions
@@ -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