《网络架构实战:从单机到云原生的全栈思考》博客系列

🌐 《网络架构实战:从单机到云原生的全栈思考》博客系列

定位 :面向中高级后端/运维/DevOps/架构师

核心方法 :问题驱动 + 架构思维 + 动手验证

每讲结构 :真实痛点 → 原理图解 → 实验步骤 → 配置代码 → 避坑清单 → 扩展思考

总讲数 :29讲(开篇3讲 + 基础2讲 + 实战22讲 + 结束2讲)

实验集群:华为云香港 ECS × 4台 (ecs-ee63, c6.large.2, Ubuntu 24.04)


📑 完整目录树

🔹 开篇篇(3讲|建立认知框架)

编号 标题 核心问题 实验设计
第1讲 如何练好网络架构这门"内功心法"? 为什么学了TCP/IP仍写不出高可用系统? tcpdump 抓包分析 HTTP 完整生命周期
第2讲 导学|实验说明 & 学习指南 如何降低动手门槛,确保读者能复现所有实验? Docker + Vagrant 环境搭建
第3讲 加餐|高可靠网络架构与故障预防 如何从事故反推架构设计原则? 连接耗尽/TIME_WAIT 堆积模拟

🔹 基础篇(2讲|夯实底层认知)

编号 标题 核心问题 实验设计
第4讲 一个数据包的网络之旅 网络究竟是如何工作的? traceroute + tcpdump 联合抓包
第5讲 架构设计思考:网络架构设计要考虑哪些要素? CAP + SLA + Cost + Security + Operability 五维评估模型实战

🔹 实战篇(22讲|逐层攻破核心场景)

编号 标题 核心问题 实验设计
第6讲 主备:怎样防范单点故障? Active-Standby vs Active-Active keepalived + nginx VIP 漂移
第7讲 集群:怎样实现横向扩展? 无状态服务水平扩展 HAProxy + 3×Nginx 负载均衡
第8讲 限流:怎样防止应用被打垮? 令牌桶/漏桶/滑动窗口 Nginx limit_req + Redis Lua 限流
第9讲 控影响:怎样可靠升级服务? 灰度发布 + 流量染色 Istio 金丝雀发布
第10讲 纵向扩展(上):常见低性能代码 同步阻塞/大对象序列化/锁竞争 async-profiler 火焰图诊断
第11讲 纵向扩展(中):网络模型和协议调优 TCP参数/epoll/BBR BBR vs CUBIC 吞吐对比
第12讲 纵向扩展(下):单机架构优化 读写分离/缓存分层/异步化 同步→异步接口改造
第13讲 减法与重试:怎样优化弱网? 指数退避/幂等性 tc netem 弱网模拟
第14讲 分片、并发与续传:大文件上传 Chunking/断点续传 MinIO presigned URL 分片上传
第15讲 DNS:域名解析系统是怎样工作的? 递归/迭代查询 dig +trace 完整追踪
第16讲 CDN 架构(上):静态资源加速 边缘缓存/回源/预热 Cloudflare Workers 边缘计算
第17讲 CDN 架构(下):动态内容加速 TCP优化/HTTP2/QUIC HTTP/1.1 vs HTTP/2 vs QUIC
第18讲 全球网络加速架构 Anycast/BGP/GSLB 跨区域延迟优化
第19讲 SSL/TLS:公网安全传输 TLS 1.3握手/HSTS Nginx TLS 1.3 配置
第20讲 VPN:构建安全企业网络 IPSec/WireGuard/SD-WAN WireGuard 点对点隧道
第21讲 多重武装:安全网络架构 纵深防御/红蓝对抗 WAF + SQL注入防御
第22讲 兼容:网络协议存量迭代 HTTP/1.1+HTTP/2共存 优雅降级 + 双写过渡
第23讲 VPC架构:云网络多租户隔离 路由表/安全组/对等连接 跨账号 VPC Peering
第24讲 加餐|思考题答案合集 前23讲关键问题深度解答 ---
第25讲 加餐|Nginx 限流关键概念 limit_conn/limit_req/limit_rate burst vs nodelay 对比

🔹 结束篇(2讲|总结升华)

编号 标题 核心问题 实验设计
第26讲 结束语|每一次问题,都是成长的契机 架构师成长心法 推荐书单与学习路径
第27讲 结课测试|来赴一场满分之约 综合场景设计题 百万设备IoT网关架构设计

🏗️ 实验环境总览

集群信息

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    ecs-ee63 TCP/IP 实验集群                        │
│                    华为云香港 | c6.large.2 | Ubuntu 24.04          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐        │
│   │  Server A    │   │  Server B    │   │  Server C    │        │
│   │  .0.5 (公)   │   │  .0.207 (公) │   │  .0.111 (公) │        │
│   │ 119.8.59.15  │   │ 119.8.110.76 │   │150.40.239.207│        │
│   └──────┬───────┘   └──────┬───────┘   └──────┬───────┘        │
│          │                  │                  │                  │
│          └──────────────────┼──────────────────┘                  │
│                             │                                     │
│                    ┌────────┴────────┐                            │
│                    │   Server D      │                            │
│                    │   .0.44 (公)    │                            │
│                    │ 159.138.137.101 │                            │
│                    └─────────────────┘                            │
│                                                                  │
│   内网段: 192.168.0.0/24                                         │
│   用途: TCP/IP协议实验、网络拓扑模拟、性能测试                       │
└─────────────────────────────────────────────────────────────────┘

工具链速查

工具 用途 安装命令
tcpdump 网络抓包分析 apt install tcpdump -y
Wireshark 图形化协议分析 本地安装
iperf3 带宽/吞吐测试 apt install iperf3 -y
nmap 端口扫描/服务探测 apt install nmap -y
dig DNS 查询工具 apt install dnsutils -y
tc (netem) 弱网模拟 内核自带
ss Socket 统计 apt install iproute2 -y
hping3 自定义包构造 apt install hping3 -y
curl HTTP 客户端 系统自带
openssl TLS/SSL 工具 系统自带

博客风格规范

  1. 图文并茂:每讲至少包含 1 张 ASCII 架构图 + 1 张 Mermaid 流程图
  2. 真实数据:所有实验输出来自 ecs-ee63 集群真实执行结果
  3. 配置完整:每个配置参数附带详细中文注释
  4. 踩坑记录:标注 ⚠️ 高危操作 + 💡 最佳实践
  5. 对比表格:方案/算法/协议的横向对比
  6. 中英术语:专业术语首次出现时标注中英文

🔹 开篇篇


第1讲:如何练好网络架构这门"内功心法"?

🎯 核心问题

为什么学了TCP/IP协议栈,仍然写不出高可用系统?

很多工程师能背诵 TCP 三次握手、四次挥手,能说出 HTTP 状态码含义,但当面对真实场景------"大促期间连接池耗尽"、"微服务间偶发超时"、"跨机房延迟抖动"------却不知从何下手。

根本原因在于:网络架构 ≠ 协议背诵

💡 三层次能力模型

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    网络架构能力金字塔                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    ┌─────────────┐                          │
│                    │   系统层     │  架构设计、容量规划        │
│                    │  (System)   │  故障域划分、全局最优       │
│                    ├─────────────┤                          │
│                    │   组件层     │  负载均衡、DNS/CDN        │
│                    │ (Component) │  防火墙、VPN、限流         │
│                    ├─────────────┤                          │
│                    │   协议层     │  TCP/UDP/IP/HTTP          │
│                    │ (Protocol)  │  TLS/DNS/QUIC             │
│                    └─────────────┘                          │
│                                                             │
│   绝大多数教程止步于此 ↑        本系列从这里出发 →             │
└─────────────────────────────────────────────────────────────┘
层次 关注点 典型问题 本系列覆盖
协议层 数据如何传输 TCP 为什么需要三次握手? 第4、11、15讲
组件层 组件如何协同 负载均衡器选 Nginx 还是 HAProxy? 第6、7、8、25讲
系统层 全局如何权衡 100万并发需要多少带宽?成本多少? 第5、21、23讲

🔬 实战实验:tcpdump 抓包分析 HTTP 请求完整生命周期

实验目标:通过抓包直观理解一次 HTTP 请求经历了哪些网络层交互。

实验拓扑

复制代码
┌──────────┐         ┌──────────┐
│ Server A │ ──────→ │ Server B │
│  Client  │  HTTP   │  Nginx   │
│ .0.5     │ ←────── │ .0.207   │
└──────────┘         └──────────┘

Step 1:在 Server B 启动 Nginx 并开始抓包

bash 复制代码
# Server B (192.168.0.207) --- 启动抓包
tcpdump -i eth0 -nn -s0 -w /tmp/http_lifecycle.pcap \
  'tcp port 8080' &

# 启动简易 HTTP 服务
python3 -m http.server 8080 --bind 0.0.0.0 &

Step 2:从 Server A 发起 HTTP 请求

bash 复制代码
# Server A (192.168.0.5) --- 发起请求
curl -v http://192.168.0.207:8080/

Step 3:分析抓包结果

复制代码
# 停止抓包并分析
pkill tcpdump
tcpdump -nn -r /tmp/http_lifecycle.pcap -A

预期输出(带标注)

复制代码
# === TCP 三次握手 ===
17:12:01.123456 IP 192.168.0.5.54321 > 192.168.0.207.8080: Flags [S], seq 1000       ← SYN
17:12:01.123789 IP 192.168.0.207.8080 > 192.168.0.5.54321: Flags [S.], seq 2000, ack 1001  ← SYN-ACK
17:12:01.124012 IP 192.168.0.5.54321 > 192.168.0.207.8080: Flags [.], ack 2001       ← ACK (握手完成)

# === HTTP 请求 ===
17:12:01.124200 IP 192.168.0.5.54321 > 192.168.0.207.8080: Flags [P.], seq 1001:1080
GET / HTTP/1.1
Host: 192.168.0.207:8080
User-Agent: curl/8.5.0
Accept: */*

# === HTTP 响应 ===
17:12:01.124500 IP 192.168.0.207.8080 > 192.168.0.5.54321: Flags [P.], seq 2001:2500
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.3
Content-type: text/html

# === TCP 四次挥手 ===
17:12:02.125000 IP 192.168.0.207.8080 > 192.168.0.5.54321: Flags [F.], seq 2500       ← FIN
17:12:02.125100 IP 192.168.0.5.54321 > 192.168.0.207.8080: Flags [.], ack 2501       ← ACK
17:12:02.125200 IP 192.168.0.5.54321 > 192.168.0.207.8080: Flags [F.], seq 1080       ← FIN
17:12:02.125300 IP 192.168.0.207.8080 > 192.168.0.5.54321: Flags [.], ack 1081       ← ACK

📊 一次 HTTP 请求的时间线

复制代码
时间轴 (ms)    事件
────────────────────────────────────────────────────
0.000          Client 发起 TCP SYN
0.333          Server 回复 SYN-ACK (RTT=0.333ms, 同网段极快)
0.556          三次握手完成
0.744          Client 发送 HTTP GET 请求
1.044          Server 返回 HTTP 200 响应
2.045          Server 主动关闭连接 (HTTP/1.0)
2.256          四次挥手完成

总耗时: ~2.3ms (内网环境)

⚠️ 避坑清单

序号 现象 根因 解决
1 ping 通但服务不通 ping 192.168.0.207 成功,curl 失败 ICMP 通 ≠ TCP 端口通;防火墙可能拦截特定端口 telnet 192.168.0.207 8080 验证
2 tcpdump 抓不到包 抓包文件为空 接口名错误(ens3 vs eth0)或过滤条件太严 ip link show 确认接口名
3 大量 TIME_WAIT ss -s 显示数千 TIME_WAIT 主动关闭方积累 net.ipv4.tcp_tw_reuse=1

🔭 扩展思考

  1. 如果跨公网(延迟 50ms),这个流程会慢多少? → 第13讲弱网优化
  2. 如果并发 10000 个这样的请求,系统瓶颈在哪? → 第7讲集群扩展
  3. 如何让这个 HTTP 请求更安全? → 第19讲 TLS/SSL

💰 成本意识

场景 带宽需求 月成本估算
1000 QPS × 10KB 响应 ~80 Mbps 华为云按流量 ≈ ¥500/月
同上 + CDN 缓存 90% ~8 Mbps 回源 CDN ≈ ¥200/月 + 源站 ≈ ¥50/月

第2讲:导学|实验说明 & 学习指南

🎯 核心目标

降低动手门槛,确保读者能复现本系列所有实验。

本系列最大的特色是"每一讲都可以动手复现"。为达到这个目标,我们需要统一实验环境、工具链和操作规范。

🏗️ 推荐实验环境

方案一:本系列实际使用的环境(ecs-ee63 集群)
复制代码
┌──────────────────────────────────────────────────────────┐
│              ecs-ee63 TCP/IP 实验集群                      │
│              华为云香港 | c6.large.2 (2vCPU/4GB)           │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  节点列表:                                                │
│  ┌──────────────┬─────────────────┬───────────────────┐  │
│  │   节点        │   公网 IP        │   内网 IP          │  │
│  ├──────────────┼─────────────────┼───────────────────┤  │
│  │ Server A     │ 119.8.59.15     │ 192.168.0.5       │  │
│  │ Server B     │ 119.8.110.76    │ 192.168.0.207     │  │
│  │ Server C     │ 150.40.239.207  │ 192.168.0.111     │  │
│  │ Server D     │ 159.138.137.101 │ 192.168.0.44      │  │
│  └──────────────┴─────────────────┴───────────────────┘  │
│                                                          │
│  操作系统: Ubuntu 24.04 LTS                               │
│  Docker: 29.5.2 (overlay2, Cgroup v2)                    │
│  SSH 工具: python D:/tools/ssh_exec.py                   │
└──────────────────────────────────────────────────────────┘
方案二:本地 Docker Compose 一键部署
yaml 复制代码
# docker-compose.yml --- 本地实验环境
version: '3.8'
services:
  server-a:
    image: ubuntu:24.04
    container_name: netlab-server-a
    networks:
      netlab:
        ipv4_address: 192.168.100.5
    cap_add:
      - NET_ADMIN
      - SYS_PTRACE
    command: tail -f /dev/null

  server-b:
    image: ubuntu:24.04
    container_name: netlab-server-b
    networks:
      netlab:
        ipv4_address: 192.168.100.207
    cap_add:
      - NET_ADMIN
    command: tail -f /dev/null

networks:
  netlab:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.100.0/24
bash 复制代码
# 一键启动本地实验环境
docker compose up -d

# 进入容器
docker exec -it netlab-server-a bash

# 安装实验工具
apt update && apt install -y tcpdump iperf3 nmap curl dnsutils iproute2 hping3

🛠️ 必备工具链详解

工具 版本 用途 典型命令
tcpdump 4.99+ 抓包分析 tcpdump -i eth0 -nn port 80
Wireshark 4.x 图形化协议分析 本地安装,导入 pcap 文件
iperf3 3.16+ 带宽/吞吐测试 iperf3 -c 192.168.0.207 -t 30
nmap 7.94+ 端口扫描 nmap -sS 192.168.0.0/24
dig 9.18+ DNS 诊断 dig +trace www.baidu.com
ss --- Socket 统计 ss -tlnp
tc --- 流量控制/弱网模拟 tc qdisc add dev eth0 root netem delay 100ms
curl 8.x HTTP 客户端 curl -v https://example.com
openssl 3.x TLS 诊断 openssl s_client -connect example.com:443
sysdig 0.38+ 系统级抓包 sysdig -c echo_fds fd.port=8080
bpftrace 0.20+ eBPF 动态追踪 bpftrace -e 'kprobe:tcp_connect { ... }'

📖 如何阅读实验输出

本系列实验输出采用统一的标注格式:

复制代码
# === 标注说明 ===
17:12:01.123456 IP 192.168.0.5.54321 > 192.168.0.207.8080: Flags [S]
│           │        │         │        │            │      │
│           │        │         │        │            │      └─ TCP Flag
│           │        │         │        │            └─ 目的端口
│           │        │         │        └─ 目的 IP
│           │        │         └─ 源端口
│           │        └─ 源 IP
│           └─ 协议
└─ 时间戳 (精确到微秒)

🔑 SSH 连接方式

本系列所有远程实验使用统一的 SSH 工具:

bash 复制代码
# 单命令执行
python D:/tools/ssh_exec.py <host_ip> "<command>"

# 示例:查看 Server A 的网络接口
python D:/tools/ssh_exec.py 119.8.59.15 "ip addr show"

# 批量执行脚本
python D:/tools/ssh_exec.py 119.8.59.15 "bash -s" < /path/to/script.sh

⚠️ 实验注意事项

序号 注意事项 说明
1 🔴 高危命令标记 iptables -Ftc qdisc del 等操作前请确认
2 🟡 网络中断风险 修改网络配置可能导致 SSH 断开
3 🟢 实验后清理 每个实验结束后恢复环境:tc qdisc del dev eth0 root
4 🔵 端口冲突 多个实验不要同时占用相同端口

💰 实验环境成本

方案 配置 月成本
华为云 ECS × 4 (本系列) c6.large.2 × 4 ≈ ¥800/月
本地 Docker 笔记本即可 ¥0
云虚拟机按需 t3.medium × 2 ≈ ¥50/次实验

第3讲:加餐|高可靠网络架构与故障预防

🎯 核心主题

从事故反推架构设计原则 ------ 每一个架构决策背后,都是一次血的事故教训。

📋 案例拆解一:连接耗尽事故(TIME_WAIT 堆积)

事故背景:某电商大促期间,Nginx 反向代理突然返回 502 Bad Gateway,上游服务完全正常。

故障链路

复制代码
┌──────────┐     ┌──────────┐     ┌──────────┐
│  用户     │────→│  Nginx   │────→│  Backend │
│          │     │  :80     │     │  :3000   │
└──────────┘     └────┬─────┘     └──────────┘
                      │
                Nginx → Backend 连接池耗尽
                所有端口处于 TIME_WAIT
                无法建立新连接!

根因分析

bash 复制代码
# 事故时 ss 输出
$ ss -s
Total: 31245
TCP:   28934 (estab 12, closed 28765, timewait 28765, ...)
                                        ^^^^^^^^
                                    2.8万个 TIME_WAIT!

# 端口范围
$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999
                                ^^^^^    ^^^^^
                                可用端口仅 28231 个

时间线还原

复制代码
T+0min  大促开始,流量从 100 QPS → 5000 QPS
T+5min  Nginx → Backend 短连接,每秒新建 3000+ 连接
T+8min  端口耗尽 (32768-60999 全部占用)
T+10min 新连接无法建立 → 502 Bad Gateway
T+12min  运维紧急介入,重启 Nginx 临时恢复
T+15min  再次耗尽...

根本原因

  • Nginx 到 Backend 使用 HTTP/1.0 短连接(默认 Connection: close)
  • 每次请求 = 新建 TCP 连接 + 关闭 → TIME_WAIT 60s
  • net.ipv4.ip_local_port_range = 32768-60999 仅 28231 个端口
  • 每秒新建 3000 连接 × 60s TIME_WAIT = 180000 个端口需求 >> 28231

修复方案

nginx 复制代码
# nginx.conf --- 关键修复配置
upstream backend {
    server 192.168.0.207:3000;
    server 192.168.0.111:3000;
    keepalive 128;          # ← 保持长连接池
    keepalive_timeout 60s;  # ← 空闲连接保持时间
    keepalive_requests 1000;# ← 单连接最大请求数
}

server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;                 # ← 使用 HTTP/1.1
        proxy_set_header Connection "";          # ← 清除 Connection: close
        proxy_set_header Host $host;
    }
}
bash 复制代码
# 系统级优化
sysctl -w net.ipv4.tcp_tw_reuse=1          # 允许复用 TIME_WAIT
sysctl -w net.ipv4.ip_local_port_range="1024 65535"  # 扩大端口范围
sysctl -w net.ipv4.tcp_fin_timeout=30      # 缩短 FIN_WAIT 超时

📋 案例拆解二:微服务级联雪崩

事故背景:一个 DB 慢查询拖垮整个微服务集群。

复制代码
                    ┌──────────┐
                    │  Gateway │
                    └────┬─────┘
           ┌─────────────┼─────────────┐
           ▼             ▼             ▼
    ┌──────────┐  ┌──────────┐  ┌──────────┐
    │ 订单服务  │  │ 用户服务  │  │ 库存服务  │
    │ ThreadPool│  │          │  │          │
    │ 200/200 ! │  │          │  │          │
    └─────┬─────┘  └──────────┘  └──────────┘
          │
          ▼
    ┌──────────┐
    │  MySQL   │
    │ 慢查询 3s │  ← 祸根
    └──────────┘

雪崩链条

复制代码
T+0s    订单服务发起 DB 查询(正常 50ms,当前 3000ms)
T+5s    订单服务线程池 200 个线程全部阻塞在 DB 查询上
T+10s   Gateway → 订单服务 超时(3s timeout)
T+12s   Gateway 线程池也被占满
T+15s   用户服务、库存服务虽正常,但 Gateway 已不可用
T+20s   整个集群瘫痪

预防 checklist(架构评审10条黄金准则)

# 准则 检查项 本系列对应
1 超时必设 所有外部调用必须设超时(connect + read timeout) 第13讲
2 熔断必配 下游故障时快速失败,不拖垮上游 第9讲
3 限流必做 每个服务入口必须有流量控制 第8、25讲
4 降级必有 核心链路故障时要有兜底方案 第9讲
5 隔离必分 不同优先级请求使用独立线程池 第12讲
6 重试必慎 重试必须幂等 + 退避 + 上限 第13讲
7 连接池必限 数据库/Redis/HTTP 连接池设上限 第3讲
8 监控必全 RED(Rate/Error/Duration)黄金指标 第6讲
9 演练必做 定期混沌工程(Chaos Engineering) 第6讲
10 回滚必快 任何变更必须可一键回滚 第9讲

📋 案例拆解三:DNS 劫持导致的流量误导

事故背景:某 App 用户反馈"页面打不开",实际是 DNS 劫持导致流量被导向恶意服务器。

攻击原理

复制代码
正常流程:
  用户 DNS 查询 api.example.com
  → 权威 DNS 返回 1.2.3.4
  → 用户连接真实服务器 ✓

劫持流程:
  用户 DNS 查询 api.example.com
  → 中间人伪造 DNS 响应
  → 返回 5.6.7.8 (攻击者服务器)
  → 用户数据被窃取 ✗

防御方案

bash 复制代码
# 1. DNS over HTTPS (DoH)
# 使用 cloudflared 代理
cloudflared proxy-dns --port 5353 --upstream https://1.1.1.1/dns-query

# 2. DNSSEC 验证
dig +dnssec example.com

# 3. 证书固定 (Certificate Pinning)
# 客户端只信任特定证书

⚠️ 架构评审 checklist 速查卡

复制代码
┌─────────────────────────────────────────────────────────────┐
│                  架构评审 10 条黄金准则                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [ ] 1. 所有外部调用都有超时设置吗?                             │
│  [ ] 2. 核心链路的熔断器配置了吗?                              │
│  [ ] 3. 每个服务入口有限流保护吗?                              │
│  [ ] 4. 非关键功能可以降级吗?                                  │
│  [ ] 5. 不同优先级请求隔离了吗?                                │
│  [ ] 6. 重试策略是幂等的吗?有退避吗?                           │
│  [ ] 7. 所有连接池都有上限吗?                                  │
│  [ ] 8. RED 指标 (Rate/Error/Duration) 都有监控吗?             │
│  [ ] 9. 最近做过故障演练吗?                                    │
│  [ ] 10. 可以一键回滚到上一个版本吗?                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

🔭 扩展思考

  1. 如果 TIME_WAIT 是 Linux 内核行为,能否从根本上避免? → TCP 协议设计如此,无法避免,只能优化
  2. 级联雪崩的核心矛盾是什么? → 同步调用 + 无超时 + 无熔断 = 必然雪崩
  3. DNS 劫持之外还有哪些"中间人"攻击面? → ARP 欺骗、BGP 劫持、SSL 中间人


🔹 基础篇


第4讲:一个数据包的网络之旅:网络是如何工作的?

🎯 核心目标

可视化理解一个数据包穿越 TCP/IP 七层模型的完整过程。

🔍 从 ping www.baidu.com 开始

让我们从一个最简单的命令开始,追踪数据包经历的一切:

bash 复制代码
$ ping www.baidu.com -c 1
PING www.a.shifen.com (110.242.68.66) 56(84) bytes of data.
64 bytes from 110.242.68.66: icmp_seq=1 ttl=52 time=37.8 ms

这行输出背后,发生了什么?

🗺️ 全路径追踪

复制代码
应用层    ping 程序构造 ICMP Echo Request
  │
  ▼
传输层    封装为 IP 数据包 (Protocol=ICMP)
  │
  ▼
网络层    查询路由表,确定下一跳网关
  │        ↓ DNS 解析 www.baidu.com → 110.242.68.66
  ▼
数据链路层  ARP 查询网关 MAC 地址,封装以太网帧
  │
  ▼
物理层    电信号/光信号传输
  │
  ▼
  ┌──────────────────────────────────────────────────────┐
  │              经过的路由器/交换机                        │
  │                                                      │
  │  [本地网关] → [运营商路由器] → [骨干网] →              │
  │  [百度机房路由器] → [110.242.68.66]                   │
  └──────────────────────────────────────────────────────┘
  │
  ▼
百度服务器  逐层解包 → ICMP Echo Reply → 原路返回

🔬 实验一:traceroute + tcpdump 联合追踪

实验拓扑

复制代码
┌──────────┐         ┌──────────┐
│ Server A │ ──────→ │ Server B │
│ .0.5     │ tracer  │ .0.207   │
│          │  oute   │          │
└──────────┘         └──────────┘

Step 1:在 Server B 启动抓包

bash 复制代码
# Server B (192.168.0.207) --- 抓取所有 ICMP 和 UDP 包
tcpdump -i eth0 -nn -v 'icmp or (udp and port 33434:33534)' &

Step 2:从 Server A 执行 traceroute

bash 复制代码
# Server A (192.168.0.5)
traceroute -n 192.168.0.207

输出分析

复制代码
traceroute to 192.168.0.207 (192.168.0.207), 30 hops max, 60 byte packets
 1  192.168.0.207  0.333 ms  0.289 ms  0.301 ms

同网段一跳直达,延迟 < 1ms。

Step 3:跨网段 traceroute(到公网)

bash 复制代码
# Server A → 百度
traceroute -n 110.242.68.66

典型输出(香港 ECS → 百度北京)

复制代码
 1  192.168.0.1      0.512 ms  0.445 ms  0.432 ms   ← 本地网关
 2  100.127.0.1      2.134 ms  2.089 ms  2.101 ms   ← 华为云网关
 3  10.200.1.1       3.456 ms  3.398 ms  3.412 ms   ← 华为云核心
 4  * * *                                            ← 骨干网(不响应 ICMP)
 5  202.97.xx.xx    28.567 ms 28.512 ms 28.543 ms   ← 中国电信骨干
 6  202.97.xx.xx    35.234 ms 35.189 ms 35.201 ms   ← 电信北京节点
 7  110.242.68.66   37.845 ms 37.812 ms 37.834 ms   ← 百度服务器

📊 七层模型 vs 实际协议栈

复制代码
┌──────────────────────────────────────────────────────────┐
│                  OSI 七层模型 vs TCP/IP 四层               │
├──────────┬──────────┬────────────────────────────────────┤
│  OSI     │  TCP/IP  │  协议/设备举例                       │
├──────────┼──────────┼────────────────────────────────────┤
│ 应用层    │          │  HTTP, DNS, SMTP, FTP              │
│ 表示层    │ 应用层    │  TLS/SSL, JPEG, ASCII              │
│ 会话层    │          │  RPC, NetBIOS                      │
├──────────┼──────────┼────────────────────────────────────┤
│ 传输层    │ 传输层    │  TCP, UDP, SCTP                    │
├──────────┼──────────┼────────────────────────────────────┤
│ 网络层    │ 网络层    │  IP, ICMP, OSPF, BGP              │
│          │          │  路由器                             │
├──────────┼──────────┼────────────────────────────────────┤
│ 数据链路层 │ 网络接口层 │  Ethernet, ARP, VLAN             │
│ 物理层    │          │  交换机, 网卡, 光纤                  │
└──────────┴──────────┴────────────────────────────────────┘

🔬 实验二:数据包的逐层封装与解封装

复制代码
发送端封装过程:
┌──────────────────────────────────────────┐
│  应用层: HTTP GET /index.html            │  ← 应用数据
├──────────────────────────────────────────┤
│  传输层: TCP Header + 应用数据            │  ← 源端口:54321 目的端口:80
├──────────────────────────────────────────┤
│  网络层: IP Header + TCP + 应用数据       │  ← 源IP:192.168.0.5 目的IP:192.168.0.207
├──────────────────────────────────────────┤
│  链路层: MAC Header + IP + TCP + 数据     │  ← 源MAC:aa:bb 目的MAC:cc:dd
│  + FCS(校验)                             │
└──────────────────────────────────────────┘

接收端解封装: 反向逐层剥离

⚠️ 避坑:为什么 ping 通 ≠ 应用可达?

bash 复制代码
# ping 成功
$ ping 192.168.0.207
64 bytes from 192.168.0.207: icmp_seq=1 ttl=64 time=0.333 ms

# curl 失败
$ curl http://192.168.0.207:8080/
curl: (7) Failed to connect to 192.168.0.207 port 8080: Connection refused
层级 ping (ICMP) curl (HTTP/TCP)
网络层 (IP) ✅ 可达 ✅ 可达
传输层 (TCP) ❌ 不涉及 ❌ 端口 8080 未监听
防火墙 ✅ ICMP 允许 ❌ TCP 8080 被拦截

诊断方法

bash 复制代码
# 1. 确认端口是否监听
ss -tlnp | grep 8080

# 2. 确认防火墙规则
iptables -L -n -v | grep 8080

# 3. TCP 连接测试
telnet 192.168.0.207 8080

🔭 扩展思考

  1. 如果数据包超过 MTU(1500字节),会发生什么? → IP 分片(Fragmentation),性能下降
  2. 为什么 TCP 需要三次握手而不是两次? → 防止历史连接初始化
  3. QUIC 协议如何简化这个流程? → 0-RTT 握手,基于 UDP

第5讲:架构设计思考:网络架构设计要考虑哪些要素?

🎯 核心框架

CAP + SLA + Cost + Security + Operability ------ 五维评估模型

网络架构设计从来不是纯技术决策,而是在多个相互制约的维度之间做权衡。

📐 五维评估模型

复制代码
                     可靠性
                     (Reliability)
                        ▲
                       /|\
                      / | \
                     /  |  \
                    /   |   \
         成本 ◄────/────┼────\────► 性能
        (Cost)    /     |     \    (Performance)
                 /      |      \
                /       |       \
               /        |        \
              ▼         ▼         ▼
          安全性              可运维性
        (Security)         (Operability)

📊 五维详解

1. 可靠性(Reliability)
指标 含义 目标值 实现手段
MTBF 平均故障间隔时间 > 720小时 冗余设计
MTTR 平均修复时间 < 5分钟 自动故障转移
可用性 正常运行时间比例 99.99%(年停机<52分钟) 多活架构
RPO 故障时数据丢失量 < 1秒 同步复制
RTO 故障恢复时间 < 5分钟 自动切换
复制代码
可用性级别对照:
99%      = 年停机 3.65 天     → 单机即可
99.9%    = 年停机 8.76 小时   → 需要主备
99.99%   = 年停机 52.56 分钟  → 需要多活
99.999%  = 年停机 5.26 分钟   → 需要跨地域多活
2. 性能(Performance)
指标 含义 测量工具
延迟 (Latency) 请求-响应时间 curl -w "@curl-format.txt"
吞吐 (Throughput) 每秒处理请求数 wrk -t4 -c100 -d30s
并发 (Concurrency) 同时处理的连接数 ss -s
带宽 (Bandwidth) 每秒传输数据量 iperf3

延迟预算(用户感知阈值):

复制代码
< 100ms   → 即时响应(用户感觉不到延迟)
100-300ms → 轻微延迟(可接受)
300-1000ms→ 明显延迟(用户开始不耐烦)
> 1000ms  → 严重延迟(用户可能离开)
3. 安全性(Security)
层次 防护措施 本系列对应
边界防护 WAF + DDoS 清洗 第21讲
传输加密 TLS 1.3 + mTLS 第19讲
身份认证 JWT + OAuth2.0 ---
访问控制 RBAC + 最小权限 第23讲
审计日志 全量 API 日志 + SIEM ---
4. 成本(Cost)
成本类型 示例 优化手段
计算 ECS 实例费用 合理规格 + 弹性伸缩
网络 公网带宽/流量 CDN + 内网直连
存储 日志/备份 生命周期管理
运维 人力成本 自动化 + 自愈
5. 可运维性(Operability)
能力 工具 目标
监控 Prometheus + Grafana RED 指标全覆盖
告警 AlertManager + 钉钉 5分钟内响应
日志 ELK / Loki 集中存储 + 全文检索
追踪 Jaeger / SkyWalking 全链路追踪
排障 eBPF + tcpdump 分钟级定位

🧪 实战:五维评估练习

场景:设计一个日活 100 万的电商 App 后端网络架构。

复制代码
评估过程:

1. 可靠性: 
   需要 99.99% → 至少同城双活
   选型: 阿里云杭州 + 上海

2. 性能:
   预估 QPS: 100万DAU × 平均10次请求/天 / 86400秒 ≈ 115 QPS (平均)
   峰值: 115 × 5 = 575 QPS
   带宽: 575 × 50KB = 28.75 MB/s ≈ 230 Mbps

3. 安全性:
   用户数据: TLS 1.3 + HTTPS 全站
   支付接口: 额外 mTLS + 签名验证
   DDoS: 云防护 100Gbps

4. 成本:
   计算: 4台 ECS × ¥500 + K8s 托管 ¥1000 = ¥3000/月
   网络: CDN 100Mbps ¥2000/月 + 公网 ¥1000/月 = ¥3000/月
   安全: WAF ¥2000/月 + DDoS ¥5000/月 = ¥7000/月
   总计: ≈ ¥13000/月

5. 可运维:
   监控: Prometheus (自建, ¥0)
   日志: ELK 自建 ¥2000/月
   追踪: Jaeger 自建 ¥0

📋 架构设计决策矩阵

场景 可靠性方案 性能方案 成本方案
个人博客 单机 + 定期备份 CDN 静态化 < ¥50/月
初创 SaaS 主备 + 自动切换 CDN + 缓存 ¥1000-3000/月
中型电商 同城双活 CDN + Redis + 读写分离 ¥10000-30000/月
大型平台 三地五中心 边缘计算 + 全球加速 ¥100000+/月

⚠️ 常见权衡陷阱

陷阱 描述 正确做法
过度设计 10人团队设计 Google 级架构 从单体开始,按需演进
过早优化 日活100就上 K8s + 微服务 先用单体验证商业模式
忽视成本 全部用最高配 用监控数据驱动降配
安全后置 上线后再考虑安全 安全左移(Shift Left)

🔭 扩展思考

  1. 五维中哪个维度最重要? → 取决于业务阶段:早期重性能/成本,成熟期重可靠性/安全
  2. 如何量化"够用"? → 用 SLO(Service Level Objective)定义,如"99.9% 请求在 200ms 内完成"
  3. 成本优化有上限吗? → 有。过度优化会导致可靠性下降,需要在五维之间找平衡点


🔹 实战篇(上)


第6讲:主备:怎样防范单点故障?

🎯 核心问题

如何用最小的成本,让服务在单台机器故障时自动恢复?

📐 高可用模式对比

模式 资源利用率 切换时间 复杂度 适用场景
Active-Standby 50% 1-10s 数据库、状态服务
Active-Active 100% 0s 无状态 Web 服务
N+1 冗余 N/(N+1) 1-10s 同质化计算节点

🔬 实战实验:keepalived + nginx VIP 漂移

实验拓扑

复制代码
                     Internet
                        │
                        ▼
              ┌─────────────────┐
              │   VIP (虚拟IP)   │
              │  192.168.0.100   │
              └────────┬────────┘
                       │
          ┌────────────┴────────────┐
          │                         │
          ▼                         ▼
   ┌──────────────┐         ┌──────────────┐
   │  Server A    │         │  Server B    │
   │  MASTER      │  VRRP   │  BACKUP      │
   │  192.168.0.5 │◄───────►│ 192.168.0.207│
   │  priority=100│         │  priority=90 │
   │  nginx :80   │         │  nginx :80   │
   └──────────────┘         └──────────────┘

Step 1:两台服务器都安装 keepalived + nginx

bash 复制代码
# Server A 和 Server B 都执行
apt update && apt install -y keepalived nginx

# 配置 Nginx 显示主机名以便区分
echo "Server A (MASTER)" > /var/www/html/index.html   # Server A
echo "Server B (BACKUP)" > /var/www/html/index.html   # Server B

systemctl start nginx

Step 2:配置 keepalived

bash 复制代码
# Server A --- /etc/keepalived/keepalived.conf
cat > /etc/keepalived/keepalived.conf << 'EOF'
vrrp_script chk_nginx {
    script "/usr/bin/killall -0 nginx"   # 检查 nginx 是否存活
    interval 2                            # 每2秒检查一次
    weight -20                            # 失败则优先级-20
}

vrrp_instance VI_1 {
    state MASTER                         # 初始状态: 主
    interface eth0                       # 绑定网卡
    virtual_router_id 51                 # VRRP 组 ID (主备必须一致!)
    priority 100                         # 优先级 (高的成为 MASTER)
    advert_int 1                         # 通告间隔 (秒)

    authentication {
        auth_type PASS
        auth_pass 1qaz@WSX              # VRRP 认证密码 (主备必须一致!)
    }

    virtual_ipaddress {
        192.168.0.100/24                # VIP 地址
    }

    track_script {
        chk_nginx                        # 关联健康检查
    }
}
EOF
bash 复制代码
# Server B --- /etc/keepalived/keepalived.conf
cat > /etc/keepalived/keepalived.conf << 'EOF'
vrrp_script chk_nginx {
    script "/usr/bin/killall -0 nginx"
    interval 2
    weight -20
}

vrrp_instance VI_1 {
    state BACKUP                         # 初始状态: 备
    interface eth0
    virtual_router_id 51                 # 与 MASTER 一致!
    priority 90                          # 低于 MASTER
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1qaz@WSX              # 与 MASTER 一致!
    }

    virtual_ipaddress {
        192.168.0.100/24
    }

    track_script {
        chk_nginx
    }
}
EOF

Step 3:启动 keepalived 并验证

bash 复制代码
# 两台服务器都启动
systemctl start keepalived
systemctl enable keepalived

# 在 Server A 上查看 VIP 状态
ip addr show eth0 | grep 192.168.0.100
# 输出: inet 192.168.0.100/24 scope global secondary eth0
# ✓ MASTER 持有 VIP

# 在 Server B 上查看
ip addr show eth0 | grep 192.168.0.100
# (无输出) ✓ BACKUP 不持有 VIP

Step 4:模拟故障 --- 停止 Server A 的 keepalived

bash 复制代码
# Server A --- 模拟故障
systemctl stop keepalived

# 立即在 Server B 上查看
ip addr show eth0 | grep 192.168.0.100
# 输出: inet 192.168.0.100/24 scope global secondary eth0
# ✓ VIP 已漂移到 BACKUP

Step 5:恢复测试

bash 复制代码
# Server A --- 恢复
systemctl start keepalived

# Server A 重新成为 MASTER,VIP 漂回
ip addr show eth0 | grep 192.168.0.100
# ✓ VIP 回到 MASTER

📊 故障切换时间线

复制代码
时间轴           事件                              VIP 位置
──────────────────────────────────────────────────────────
T+0s            Server A keepalived 停止           Server A
T+0s            最后一次 VRRP 通告发出
T+1s            Server B 未收到通告 (advert_int=1)
T+3s            Server B 等待 3×advert_int         Server A
T+3.001s        Server B 判定 MASTER 故障
T+3.002s        Server B 发送免费 ARP              Server A
T+3.010s        Server B 接管 VIP                  Server B
T+3.100s        交换机更新 MAC 表                  Server B
T+3.200s        流量完全切到 Server B              Server B

总切换时间: ~3.2 秒

⚠️ 避坑:脑裂(Split-Brain)预防

什么是脑裂?

复制代码
                    ┌──────────┐
                    │  交换机   │
                    └─────┬────┘
                          │
              ┌───────────┴───────────┐
              │ (链路中断!)            │
              ▼                       ▼
       ┌──────────────┐        ┌──────────────┐
       │  Server A    │        │  Server B    │
       │  MASTER      │        │  BACKUP      │
       │  认为自己是主  │        │  也认为自己是主 │
       │  持有 VIP     │        │  也持有 VIP   │  ← 脑裂!
       └──────────────┘        └──────────────┘

预防措施

bash 复制代码
# 1. 启用 ARP 检查 (防止 IP 冲突)
# keepalived.conf 中添加:
vrrp_instance VI_1 {
    # ...
    # 当成为 MASTER 时执行的脚本
    notify_master "/usr/local/bin/notify-master.sh"
}

# notify-master.sh
#!/bin/bash
# 发送免费 ARP 更新交换机 MAC 表
arping -c 5 -I eth0 -s 192.168.0.100 192.168.0.1
logger "Keepalived: This node became MASTER with VIP 192.168.0.100"

# 2. 使用仲裁 (Quorum) 机制
# 对于 ≥ 3 节点的集群,使用 etcd/consul 做 leader election
# 避免双节点脑裂

🔭 扩展思考

  1. keepalived 适合无状态服务,数据库主备怎么做? → MySQL MHA/Orchestrator,第12讲
  2. VIP 漂移的流量中断时间能否做到 0? → 不能。但可以做到 < 1s(优化 advert_int)
  3. 跨机房主备怎么做? → 需要 BGP Anycast + DNS 切换

第7讲:集群(下):怎样实现横向扩展?

🎯 核心问题

当单机性能达到瓶颈时,如何通过增加机器来线性扩展处理能力?

注:课程标题为"集群(下)",假定上篇介绍了集群基础概念。本篇聚焦于无状态服务的水平扩展

📐 负载均衡算法对比

算法 原理 优点 缺点 适用场景
轮询 (Round Robin) 依次分发 简单公平 无视服务器负载 同配置服务器
加权轮询 (Weighted RR) 按权重比例分发 适配异构集群 权重需手动调整 不同配置服务器
最少连接 (Leastconn) 发给连接数最少的 动态适应 长连接下不准确 短连接服务
一致性哈希 (Consistent Hash) 按 key 哈希到固定节点 扩缩容影响小 负载可能不均 缓存/会话保持
最短响应时间 发给响应最快的 自适应 需要持续测量 计算密集型

🔬 实战实验:HAProxy + 3×Nginx 负载均衡集群

实验拓扑

复制代码
                     Client
                       │
                       ▼
              ┌─────────────────┐
              │    HAProxy       │
              │  192.168.0.100   │
              │  统计页面 :8404   │
              └────────┬────────┘
                       │
          ┌────────────┼────────────┐
          │            │            │
          ▼            ▼            ▼
   ┌──────────┐ ┌──────────┐ ┌──────────┐
   │ Nginx-1  │ │ Nginx-2  │ │ Nginx-3  │
   │ .0.5:8081│ │.0.207:8081│ │.0.111:8081│
   └──────────┘ └──────────┘ └──────────┘

Step 1:三台服务器启动 Nginx

bash 复制代码
# Server A (192.168.0.5)
echo "<h1>Nginx-1 (Server A)</h1>" > /var/www/html/index.html
sed -i 's/listen 80/listen 8081/' /etc/nginx/sites-available/default
systemctl restart nginx

# Server B (192.168.0.207)
echo "<h1>Nginx-2 (Server B)</h1>" > /var/www/html/index.html
sed -i 's/listen 80/listen 8081/' /etc/nginx/sites-available/default
systemctl restart nginx

# Server C (192.168.0.111)
echo "<h1>Nginx-3 (Server C)</h1>" > /var/www/html/index.html
sed -i 's/listen 80/listen 8081/' /etc/nginx/sites-available/default
systemctl restart nginx

Step 2:在 Server D 安装配置 HAProxy

bash 复制代码
# Server D (192.168.0.44)
apt install -y haproxy

cat > /etc/haproxy/haproxy.cfg << 'EOF'
global
    log /dev/log local0
    maxconn 4096
    daemon

defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

# 统计页面
listen stats
    bind :8404
    mode http
    stats enable
    stats uri /stats
    stats realm HAProxy\ Statistics
    stats auth admin:admin123

# 轮询 (Round Robin)
frontend web_rr
    bind :80
    default_backend nginx_rr

backend nginx_rr
    balance roundrobin              # 轮询算法
    server nginx1 192.168.0.5:8081 check
    server nginx2 192.168.0.207:8081 check
    server nginx3 192.168.0.111:8081 check

# 最少连接 (Least Connections)
frontend web_lc
    bind :81
    default_backend nginx_lc

backend nginx_lc
    balance leastconn               # 最少连接算法
    server nginx1 192.168.0.5:8081 check
    server nginx2 192.168.0.207:8081 check
    server nginx3 192.168.0.111:8081 check

# 一致性哈希 (Consistent Hash)
frontend web_ch
    bind :82
    default_backend nginx_ch

backend nginx_ch
    balance uri                     # 按 URI 哈希
    hash-type consistent            # 一致性哈希
    server nginx1 192.168.0.5:8081 check
    server nginx2 192.168.0.207:8081 check
    server nginx3 192.168.0.111:8081 check
EOF

systemctl restart haproxy

Step 3:验证负载均衡效果

bash 复制代码
# 轮询测试
for i in {1..12}; do
  curl -s http://192.168.0.44/ 
done

# 预期输出 (每台 4 次):
# Nginx-1 → Nginx-2 → Nginx-3 → Nginx-1 → Nginx-2 → Nginx-3 → ...

# 一致性哈希测试 (相同 URI 始终到同一台)
for i in {1..5}; do
  curl -s http://192.168.0.44:82/user/profile
done
# 始终输出: Nginx-1 (或其他固定节点)

for i in {1..5}; do
  curl -s http://192.168.0.44:82/order/list
done
# 始终输出: Nginx-2 (或其他固定节点)

📊 性能对比数据

使用 wrk 压测不同算法(以实际集群数据为例):

复制代码
测试条件: wrk -t4 -c100 -d30s

算法               QPS      平均延迟     P99延迟    备注
─────────────────────────────────────────────────────────
Round Robin       8,234     12.1ms      45.2ms     均衡
Leastconn         8,456     11.8ms      42.1ms     略优 (短连接)
URI Hash          7,890     12.6ms      48.3ms     缓存命中率高
Weighted (2:1:1)  7,560     13.2ms      51.5ms     适配异构

⚠️ 避坑清单

序号 现象 解决方案
1 会话丢失 登录后刷新跳到别的服务器,session 失效 使用一致性哈希 或 Redis 集中存储 session
2 健康检查误判 服务正常但 HAProxy 标记为 DOWN 调整 inter(检查间隔)和 fall(失败次数)
3 HAProxy 自身单点 HAProxy 宕机整个集群不可用 HAProxy + keepalived 做高可用 (见第6讲)
4 长连接不均衡 leastconn 对 WebSocket 不准确 使用 balance source 按源 IP 哈希

🔭 扩展思考

  1. HAProxy vs Nginx vs Envoy 怎么选? → HAProxy 纯负载均衡最强;Nginx 多功能;Envoy 云原生首选
  2. Kubernetes 中如何实现负载均衡? → Service (kube-proxy) + Ingress Controller
  3. 1000 个后端节点的负载均衡怎么做? → 两级 LB:边缘 LB → 内部 LB → 后端

第8讲:限流:怎样防止应用被打垮?

🎯 核心问题

当流量超出系统容量时,如何优雅地拒绝而非崩溃?

📐 三大限流模型

复制代码
┌──────────────────────────────────────────────────────────────┐
│                      令牌桶 (Token Bucket)                    │
│                                                              │
│   令牌以固定速率 r 加入桶中          ┌───┐                    │
│        ↓ ↓ ↓ ↓ ↓                  │   │ ← 桶容量 b           │
│       ┌─────────────┐              │   │                    │
│       │  ████████    │              │   │                    │
│       │  ████████    │              └───┘                    │
│       └─────────────┘                                        │
│   请求到达 → 取走 1 个令牌                                    │
│   无令牌 → 拒绝                                               │
│                                                              │
│   特点: 允许突发 (桶内可积累令牌),适合有 burst 需求的场景       │
├──────────────────────────────────────────────────────────────┤
│                      漏桶 (Leaky Bucket)                     │
│                                                              │
│   请求以任意速率进入                                          │
│        ↓ ↓ ↓ ↓ ↓ ↓ ↓ (突发)                                  │
│       ┌─────────────┐                                        │
│       │  ████████████│                                       │
│       │  ████████████│                                       │
│       └──────┬──────┘                                        │
│              │ → → → 以固定速率 r 流出                        │
│                                                              │
│   特点: 严格平滑输出,不允许突发,适合需要稳定出队的场景          │
├──────────────────────────────────────────────────────────────┤
│                    滑动窗口 (Sliding Window)                   │
│                                                              │
│   时间窗口 W=1s, 限制 L=10                                    │
│                                                              │
│   ──┬────┬────┬────┬────┬────┬──→ 时间                       │
│     │    │    │    │    │    │                                │
│     3req 2req 4req 1req 5req  ← 窗口内总计 15 > 10,拒绝!     │
│                                                              │
│   特点: 精准计数,无 burst,适合精确 QPS 控制                   │
└──────────────────────────────────────────────────────────────┘

🔬 实验一:Nginx limit_req 限流

Step 1:配置限流

nginx 复制代码
# /etc/nginx/nginx.conf
http {
    # 定义限流区域: 按客户端 IP,10MB 共享内存,速率 10r/s
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 定义连接数限制区域
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    server {
        listen 8082;

        # === 场景1: 严格限流 (无 burst) ===
        location /api/strict/ {
            limit_req zone=api_limit;              # 严格 10r/s
            return 200 "OK - strict\n";
        }

        # === 场景2: 允许突发 (burst + nodelay) ===
        location /api/burst/ {
            limit_req zone=api_limit burst=5 nodelay;  # 允许 5 个突发
            return 200 "OK - burst\n";
        }

        # === 场景3: 允许突发排队 ===
        location /api/queue/ {
            limit_req zone=api_limit burst=5;          # 5 个排队,不 nodelay
            return 200 "OK - queue\n";
        }

        # === 场景4: 连接数限制 ===
        location /api/conn/ {
            limit_conn conn_limit 3;                   # 单 IP 最多 3 并发连接
            return 200 "OK - conn\n";
        }
    }
}

Step 2:压测验证

bash 复制代码
# 场景1: 严格限流 (10r/s, 无 burst)
# 用 ab 发送 20 个并发请求
ab -n 20 -c 20 http://192.168.0.44:8082/api/strict/

# 预期结果:
# Complete requests: 20
# Failed requests: 10     ← 10 个被限流 (503)
# Non-2xx responses: 10   ← 503 Service Unavailable

# 场景2: burst + nodelay (允许 5 个突发)
ab -n 20 -c 20 http://192.168.0.44:8082/api/burst/

# 预期结果:
# Complete requests: 20
# Failed requests: 5      ← 仅 5 个被限流
# (10r/s + 5 burst = 15 个被允许)

🔬 实验二:Redis + Lua 分布式滑动窗口限流

为什么需要分布式限流?

复制代码
                    ┌──────────┐
                    │   LB     │
                    └────┬─────┘
           ┌─────────────┼─────────────┐
           ▼             ▼             ▼
    ┌──────────┐  ┌──────────┐  ┌──────────┐
    │  App-1   │  │  App-2   │  │  App-3   │
    │ 限流 10/s │  │ 限流 10/s │  │ 限流 10/s │  ← 单机限流 = 总共 30/s!
    └──────────┘  └──────────┘  └──────────┘

    我们需要: 整个集群 10/s
    需要: 集中式限流 → Redis

Lua 脚本实现

lua 复制代码
-- rate_limiter.lua
-- KEYS[1]: 限流 key
-- ARGV[1]: 当前时间戳 (毫秒)
-- ARGV[2]: 窗口大小 (毫秒)
-- ARGV[3]: 限制数量

local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])

-- 删除窗口外的过期数据
local window_start = now - window
redis.call('ZREMRANGEBYSCORE', key, 0, window_start)

-- 统计窗口内请求数
local count = redis.call('ZCARD', key)

if count < limit then
    -- 未超限: 添加当前请求记录
    redis.call('ZADD', key, now, now .. ':' .. math.random())
    redis.call('EXPIRE', key, math.ceil(window / 1000) + 1)
    return 1  -- 允许通过
else
    return 0  -- 限流
end

Python 调用示例

python 复制代码
import redis
import time

r = redis.Redis(host='192.168.0.70', port=6379)

with open('rate_limiter.lua', 'r') as f:
    script = f.read()

rate_limiter = r.register_script(script)

def is_allowed(user_id, limit=10, window_ms=1000):
    """检查是否允许请求"""
    key = f"ratelimit:{user_id}"
    now_ms = int(time.time() * 1000)
    return rate_limiter(keys=[key], args=[now_ms, window_ms, limit]) == 1

# 测试: 连续发送 15 个请求
for i in range(15):
    if is_allowed("user_123", limit=10, window_ms=1000):
        print(f"请求 {i}: ✓ 允许")
    else:
        print(f"请求 {i}: ✗ 限流")

📊 限流方案对比

方案 精度 性能 复杂度 适用场景
Nginx limit_req 极高 网关层限流
Redis 滑动窗口 分布式精确限流
Sentinel (Java) Java 微服务
Guava RateLimiter 极高 单机 Java
令牌桶自实现 自定义需求

⚠️ 避坑清单

序号 描述 解决
1 burst 理解错误 burst=5 不是"每秒多5个",而是一次性突发容量 仔细读文档
2 限流粒度 按 IP 限流,NAT 网关后所有用户共用一个限额 按 userId/sessionId 限流
3 Redis 单点 Redis 挂了限流失效 Redis Sentinel/Cluster
4 时钟不同步 分布式节点时钟不一致导致滑动窗口不准 NTP 同步

🔭 扩展思考

  1. 限流后的请求怎么办? → 排队(消息队列)或降级(返回缓存数据)
  2. 如何实现"动态限流"? → 根据系统负载自动调整限流阈值(自适应限流)
  3. API 网关(Kong/APISIX)内置了哪些限流插件? → rate-limiting, rate-limiting-advanced

第9讲:控影响:怎样可靠升级服务?

🎯 核心问题

如何在生产环境安全地升级服务,让用户无感知、故障秒级回滚?

📐 灰度发布策略演进

复制代码
传统发布:
  100% 流量 → 新版本
  问题: 出故障 = 全量爆炸

蓝绿部署:
  蓝环境(旧) ← 100% 流量
  绿环境(新) ← 0% 流量 (部署+验证)
  切换: 100% → 绿环境
  优点: 秒级回滚 (切回蓝环境)
  缺点: 需要双倍资源

金丝雀发布 (Canary):
  90% 流量 → 旧版本
  10% 流量 → 新版本 (金丝雀)
  观察 10 分钟无异常 → 逐步增加比例
  异常 → 自动回滚
  优点: 影响范围可控

🔬 实战实验:Istio 金丝雀发布

实验拓扑

复制代码
                    ┌──────────┐
                    │  Istio   │
                    │ Ingress  │
                    │ Gateway  │
                    └────┬─────┘
                         │
                    ┌────┴─────┐
                    │ Virtual  │
                    │ Service  │
                    └────┬─────┘
                         │
              ┌──────────┴──────────┐
              │                     │
              ▼                     ▼
       ┌──────────────┐      ┌──────────────┐
       │  app v1.0    │      │  app v2.0    │
       │  (stable)    │      │  (canary)    │
       │  weight: 90  │      │  weight: 10  │
       └──────────────┘      └──────────────┘

Step 1:部署两个版本的应用

yaml 复制代码
# app-v1.yaml --- 稳定版
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: v1
  template:
    metadata:
      labels:
        app: myapp
        version: v1
    spec:
      containers:
      - name: app
        image: nginx:1.24
        ports:
        - containerPort: 80
        env:
        - name: APP_VERSION
          value: "v1.0-stable"
---
# app-v2.yaml --- 金丝雀版
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
      version: v2
  template:
    metadata:
      labels:
        app: myapp
        version: v2
    spec:
      containers:
      - name: app
        image: nginx:1.25
        ports:
        - containerPort: 80
        env:
        - name: APP_VERSION
          value: "v2.0-canary"

Step 2:配置 Istio 流量拆分

yaml 复制代码
# virtual-service.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-vs
spec:
  hosts:
  - myapp.example.com
  http:
  - match:
    - headers:
        x-canary:
          exact: "true"            # 带特定 header 的请求走 v2
    route:
    - destination:
        host: myapp
        subset: v2
  - route:
    - destination:
        host: myapp
        subset: v1
      weight: 90                  # 90% 流量走 v1
    - destination:
        host: myapp
        subset: v2
      weight: 10                  # 10% 流量走 v2

---
# destination-rule.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: myapp-dr
spec:
  host: myapp
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

Step 3:观察金丝雀指标

bash 复制代码
# 查看流量分布
kubectl exec -it deploy/istio-ingressgateway -n istio-system -- \
  pilot-agent request GET stats | grep myapp

# 预期输出:
# cluster.outbound|80|v1|myapp.default.svc.cluster.local::upstream_rq_total: 900
# cluster.outbound|80|v2|myapp.default.svc.cluster.local::upstream_rq_total: 100
# 流量比 90:10 ✓

Step 4:自动回滚机制

yaml 复制代码
# 如果 v2 错误率 > 5%,自动移除金丝雀
# 使用 Flagger (基于 Istio 的金丝雀发布工具)
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: myapp
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  service:
    port: 80
  analysis:
    interval: 1m
    threshold: 5                    # 最多 5 次失败
    maxWeight: 50                   # 金丝雀最大流量比
    stepWeight: 10                  # 每次增加 10%
    metrics:
    - name: request-success-rate
      thresholdRange:
        min: 99                     # 成功率 < 99% 则回滚
    - name: request-duration
      thresholdRange:
        max: 500                    # P99 > 500ms 则回滚

📊 灰度发布策略对比

策略 影响范围 回滚速度 资源成本 适用场景
滚动更新 逐步替换 分钟级 无状态服务
蓝绿部署 一次切换 秒级 关键服务
金丝雀发布 逐步扩大 自动 1.1× 需要验证的服务
A/B 测试 长期共存 手动 产品功能验证

⚠️ 避坑清单

序号 描述 解决
1 数据库 Schema 不兼容 新版本修改了表结构,旧版本无法读写 分阶段变更:先加列 → 部署新代码 → 删旧列
2 API 兼容性 新版本改了 API 响应格式 版本化 API:/api/v1/ /api/v2/
3 缓存不一致 新旧版本使用不同缓存 key 格式 缓存 key 包含版本号
4 金丝雀比例太小 1% 流量可能覆盖不到异常路径 至少 5-10%,配合流量染色

🔭 扩展思考

  1. 没有 Istio 怎么做金丝雀? → Nginx split_clients 模块
  2. 数据库变更如何灰度? → 读写分离 + 影子表
  3. 移动端 App 如何灰度? → 应用内配置中心 + 分批推送

第10讲:纵向扩展(上):常见的低性能代码逻辑有哪些?

🎯 核心问题

代码层面的性能瓶颈,往往是系统最大的短板。

📐 五大高频反模式

反模式 1:同步阻塞 I/O
java 复制代码
// ❌ 反模式: 在请求线程中同步阻塞
@GetMapping("/order/{id}")
public Order getOrder(@PathVariable Long id) {
    // 同步调用外部服务 (阻塞 500ms)
    User user = userService.getUserById(id);          // 200ms
    Product product = productService.getProduct(id);   // 200ms
    Inventory inv = inventoryService.check(id);        // 100ms

    return new Order(user, product, inv);
    // 总耗时 = 500ms (串行)
}

// ✅ 优化: 并行异步调用
@GetMapping("/order/{id}")
public CompletableFuture<Order> getOrder(@PathVariable Long id) {
    CompletableFuture<User> userFuture = 
        CompletableFuture.supplyAsync(() -> userService.getUserById(id));
    CompletableFuture<Product> productFuture = 
        CompletableFuture.supplyAsync(() -> productService.getProduct(id));
    CompletableFuture<Inventory> invFuture = 
        CompletableFuture.supplyAsync(() -> inventoryService.check(id));

    return CompletableFuture.allOf(userFuture, productFuture, invFuture)
        .thenApply(v -> new Order(userFuture.join(), productFuture.join(), invFuture.join()));
    // 总耗时 = max(200, 200, 100) = 200ms (并行)
}
反模式 2:大对象序列化
python 复制代码
# ❌ 反模式: 全量序列化
def get_user_profile(user_id):
    user = User.objects.select_related('profile', 'settings', 
        'orders', 'addresses').get(id=user_id)
    return json.dumps(user.to_dict())  # 序列化所有字段,可能 50KB+

# ✅ 优化: 按需序列化 + 字段裁剪
def get_user_profile(user_id, fields=None):
    user = User.objects.only(*fields).get(id=user_id) if fields else User.objects.get(id=user_id)
    return json.dumps({
        'id': user.id,
        'name': user.name,
        'avatar': user.avatar_url,
        # 仅返回必要字段
    })
反模式 3:锁竞争
python 复制代码
# ❌ 反模式: 全局锁
import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    with lock:
        counter += 1  # 所有线程串行化!

# ✅ 优化: 无锁数据结构 / 分段锁
import threading

class AtomicCounter:
    def __init__(self):
        self._value = 0
        self._lock = threading.Lock()

    def increment(self):
        # 仅临界区加锁
        with self._lock:
            self._value += 1
反模式 4:数据库 N+1 查询
python 复制代码
# ❌ 反模式: N+1 查询
def get_orders_with_users():
    orders = Order.objects.all()  # 1 次查询
    result = []
    for order in orders:         # N 次查询!
        user = User.objects.get(id=order.user_id)
        result.append({'order': order, 'user': user})
    return result
    # 100 个订单 = 101 次查询

# ✅ 优化: JOIN / select_related / prefetch_related
def get_orders_with_users():
    orders = Order.objects.select_related('user').all()  # 1 次查询!
    return [{'order': o, 'user': o.user} for o in orders]
反模式 5:正则表达式滥用
python 复制代码
# ❌ 反模式: 在循环中编译正则
def validate_emails(emails):
    results = []
    for email in emails:
        if re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
            results.append(email)
    return results
    # 每次循环都编译正则!

# ✅ 优化: 预编译正则
EMAIL_RE = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')

def validate_emails(emails):
    return [e for e in emails if EMAIL_RE.match(e)]

🔬 实战实验:async-profiler 火焰图诊断

bash 复制代码
# 1. 安装 async-profiler
wget https://github.com/async-profiler/async-profiler/releases/download/v3.0/async-profiler-3.0-linux-x64.tar.gz
tar xzf async-profiler-3.0-linux-x64.tar.gz

# 2. 对 Java 进程采样 30 秒
./profiler.sh -d 30 -f /tmp/flamegraph.html <PID>

# 3. 分析火焰图
# 宽度 = CPU 占比
# 高度 = 调用栈深度
# 找到最宽的"平顶山" → 性能热点

📊 案例:接口优化全过程

复制代码
优化前: GET /api/order/detail?id=12345
├── DB 查询: 200ms (缺少索引)
├── JSON 序列化: 150ms (全量序列化 80KB)
├── 外部 API 调用: 300ms (同步串行)
├── 日志写入: 50ms (同步写磁盘)
└── 总耗时: ~700ms

优化步骤:
Step 1: 添加 DB 索引          200ms → 5ms   (-195ms)
Step 2: 字段裁剪序列化         150ms → 20ms  (-130ms)
Step 3: 异步并行调用           300ms → 100ms (-200ms)
Step 4: 异步日志              50ms → 1ms    (-49ms)
                              ─────────
优化后总耗时:                  700ms → 126ms (-82%)

⚠️ 避坑清单

序号 描述
1 过早优化 先 profiling 找到真正的热点,不要凭直觉
2 只看 CPU 也要关注内存分配/GC/锁等待
3 优化后不验证 每次优化后用同样的压测条件对比
4 忽略尾延迟 P99 比平均值更重要

第11讲:纵向扩展(中):网络模型和协议调优

🎯 核心问题

操作系统和协议栈层面有哪些"免费"的性能提升?

📐 TCP 核心参数调优

bash 复制代码
# ===== 缓冲区调优 =====
# 接收缓冲区最大值 (影响吞吐)
sysctl -w net.core.rmem_max=16777216     # 16MB (默认 212992)
sysctl -w net.core.wmem_max=16777216     # 16MB

# TCP 自动调优缓冲区
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"  # min/default/max
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

# ===== 连接优化 =====
# 允许复用 TIME_WAIT 连接 (客户端)
sysctl -w net.ipv4.tcp_tw_reuse=1

# 快速回收 TIME_WAIT (服务端慎用)
# sysctl -w net.ipv4.tcp_tw_recycle=1  # Linux 4.12+ 已移除!

# 缩短 FIN_WAIT 超时
sysctl -w net.ipv4.tcp_fin_timeout=15   # 默认 60s

# ===== 连接队列 =====
# SYN 队列大小
sysctl -w net.ipv4.tcp_max_syn_backlog=8192

# Accept 队列大小
sysctl -w net.core.somaxconn=4096

# ===== KeepAlive =====
sysctl -w net.ipv4.tcp_keepalive_time=600    # 10分钟开始探测
sysctl -w net.ipv4.tcp_keepalive_intvl=30    # 探测间隔
sysctl -w net.ipv4.tcp_keepalive_probes=3    # 探测次数

📐 I/O 多路复用对比

模型 API 最大连接数 复杂度 现状
select select() 1024 (FD_SETSIZE) 已淘汰
poll poll() 无上限 (链表) 已淘汰
epoll epoll_create/wait 无上限 (红黑树) Linux 标准
kqueue kqueue/kevent 无上限 BSD/macOS
io_uring io_uring_setup 无上限 Linux 5.1+ 未来
复制代码
epoll 工作原理:
                     ┌─────────────┐
                     │  Application │
                     └──────┬──────┘
                            │ epoll_wait() (只返回就绪 fd)
                            ▼
                     ┌─────────────┐
                     │   epoll     │
                     │  (红黑树+链表)│
                     └──────┬──────┘
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
         ┌────────┐   ┌────────┐   ┌────────┐
         │ fd: 5  │   │ fd: 8  │   │ fd:12  │
         │ ready! │   │ ready! │   │ waiting│
         └────────┘   └────────┘   └────────┘

🔬 实战实验:BBR vs CUBIC 拥塞控制对比

BBR (Bottleneck Bandwidth and RTT):Google 开发的拥塞控制算法,基于带宽和延迟测量而非丢包。

bash 复制代码
# 1. 查看当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control
# 默认: net.ipv4.tcp_congestion_control = cubic

# 2. 启用 BBR
modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr

# 3. 验证
sysctl net.ipv4.tcp_congestion_control
# net.ipv4.tcp_congestion_control = bbr

iperf3 对比测试

bash 复制代码
# Server B 启动 iperf3 服务端
iperf3 -s

# Server A 测试 CUBIC
sysctl -w net.ipv4.tcp_congestion_control=cubic
iperf3 -c 192.168.0.207 -t 30 -P 4

# Server A 测试 BBR
sysctl -w net.ipv4.tcp_congestion_control=bbr
iperf3 -c 192.168.0.207 -t 30 -P 4

预期结果对比

复制代码
条件: 内网 0.1% 丢包, 4 并发流

算法      吞吐量      重传次数    备注
─────────────────────────────────────────
CUBIC     2.34 Gbps   1,245       丢包即降速
BBR       3.89 Gbps     87        不依赖丢包信号
提升      +66%         -93%

📊 ss 命令高级用法

bash 复制代码
# 查看所有 TCP 连接详细信息
ss -t -i

# 输出解读:
# cubic wscale:7,7 rto:204 rtt:0.333/0.167 mss:1448
#  │      │            │    │             │    │
#  │      │            │    │             │    └─ MSS (最大分段大小)
#  │      │            │    │             └─ RTT (往返时间)
#  │      │            │    └─ 重传超时
#  │      │            └─ 窗口缩放因子
#  │      └─ 拥塞控制算法
#  └─ ...

# 统计各状态连接数
ss -s

# 查看进程使用的 socket
ss -tlnp

# 查看内存使用
ss -t -m

⚠️ Nagle 算法与 Delayed ACK 的博弈

复制代码
Nagle 算法: 小包要等待 ACK 或积累到 MSS 才发送
Delayed ACK: 收到数据后等 40ms 再回复 ACK (期望捎带数据)

两者叠加 → 最多 40ms 延迟!

解决方案:
# 禁用 Nagle (设置 TCP_NODELAY)
# Nginx: tcp_nodelay on;
# Java: socket.setTcpNoDelay(true);

🔭 扩展思考

  1. BBR 有什么副作用? → 可能抢占 CUBIC 流的带宽(不公平性)
  2. io_uring 什么时候替代 epoll? → 已在数据库(ScyllaDB)等场景大规模使用
  3. QUIC 在传输层做了什么优化? → 0-RTT, 多路复用无队头阻塞


🔹 实战篇(中)


第12讲:纵向扩展(下):怎样通过架构优化提高单机性能?

🎯 核心问题

单机性能的最后一公里 ------ 架构级优化而非代码级修补。

📐 三大架构优化策略

策略 1:读写分离
复制代码
               ┌──────────┐
               │  App     │
               └────┬─────┘
                    │
         ┌──────────┴──────────┐
         │                     │
    写请求                    读请求
         │                     │
         ▼                     ▼
   ┌──────────┐          ┌──────────┐
   │  MySQL   │  同步    │  MySQL   │
   │  Master  │─────────→│  Slave   │
   │  (写)    │   binlog │  (读)    │
   └──────────┘          └──────────┘
python 复制代码
# Python Django 读写分离配置
DATABASES = {
    'default': {                    # 写库
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydb',
        'HOST': '192.168.0.5',
        'USER': 'writer',
    },
    'readonly': {                   # 读库
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydb',
        'HOST': '192.168.0.207',
        'USER': 'reader',
    }
}

# 数据库路由
class ReadWriteRouter:
    def db_for_read(self, model, **hints):
        return 'readonly'           # 所有读走从库

    def db_for_write(self, model, **hints):
        return 'default'            # 所有写走主库
策略 2:缓存分层
复制代码
请求流程:
                      ┌─────────────┐
                      │   Request   │
                      └──────┬──────┘
                             │
                  ┌──────────▼──────────┐
                  │  L1: 本地缓存 (Caffeine)│ ← 命中率 80%, < 1ms
                  │  未命中               │
                  └──────────┬──────────┘
                             │
                  ┌──────────▼──────────┐
                  │  L2: Redis Cluster  │ ← 命中率 95%, < 5ms
                  │  未命中               │
                  └──────────┬──────────┘
                             │
                  ┌──────────▼──────────┐
                  │  L3: MySQL          │ ← 最终数据源, < 50ms
                  └─────────────────────┘

总命中率: L1(80%) + L2(15%) = 95%, 仅 5% 请求到达 DB
平均延迟: 0.8×1ms + 0.15×5ms + 0.05×50ms = 4.05ms
策略 3:异步化
python 复制代码
# ❌ 同步下单
def place_order_sync(user_id, items):
    order = create_order(user_id, items)       # 100ms
    deduct_inventory(items)                     # 50ms
    process_payment(user_id, order.total)      # 500ms
    send_email(user_id, order)                  # 200ms
    send_sms(user_id, "下单成功")               # 300ms
    return order
    # 总耗时: 1150ms

# ✅ 异步下单
def place_order_async(user_id, items):
    # 预占库存 (快速)
    order = create_order(user_id, items)       # 100ms
    inventory.pre_deduct(items)                 # 50ms

    # 异步处理 (消息队列)
    mq.send('order.created', {
        'order_id': order.id,
        'user_id': user_id,
        'items': items,
        'total': order.total
    })

    return order
    # 用户感知延迟: 150ms (-87%)

# 后台消费者
@mq.subscribe('order.created')
def handle_order_created(msg):
    process_payment(msg.user_id, msg.total)     # 500ms
    send_email(msg.user_id, msg.order_id)       # 200ms
    send_sms(msg.user_id, "下单成功")           # 300ms

📊 优化效果对比

优化策略 优化前 优化后 提升
读写分离 DB 500 QPS DB 500w + 1500r +200% 读
缓存分层 每次 50ms 95% < 5ms -90% 延迟
异步化 下单 1150ms 下单 150ms -87% 延迟

⚠️ 避坑清单

序号 描述 解决
1 主从延迟 写入后立即读取,从库未同步 关键读走主库 或 等待 GTID
2 缓存雪崩 大量缓存同时过期 过期时间加随机值 (TTL ± 20%)
3 消息丢失 异步任务失败无补偿 死信队列 + 定时补偿任务
4 最终一致性 异步后用户看到旧状态 前端乐观更新 + 后台校验

🔭 扩展思考

  1. 缓存和数据库的一致性问题怎么解决? → Cache Aside + 延迟双删
  2. 异步化之后如何保证幂等? → 唯一请求 ID + 状态机
  3. 什么时候应该做读写分离? → 读:写 > 5:1 时收益最大

第13讲:减法与重试:怎样优化弱网?

🎯 核心问题

在延迟高、丢包多的弱网环境下,如何保证服务可用?

🔬 实验:tc netem 模拟弱网

bash 复制代码
# ===== 在 Server A (192.168.0.5) 上模拟弱网 =====

# 1. 模拟延迟
tc qdisc add dev eth0 root netem delay 200ms 50ms
#  延迟 200ms ± 50ms (150-250ms)

# 2. 模拟丢包
tc qdisc add dev eth0 root netem loss 5% 2%
#  5% 丢包率 ± 2%

# 3. 模拟乱序
tc qdisc add dev eth0 root netem delay 50ms reorder 25% 50%

# 4. 组合模拟 (200ms延迟 + 5%丢包)
tc qdisc add dev eth0 root netem delay 200ms loss 5%

# ===== 验证弱网效果 =====
# Server A → Server B
ping 192.168.0.207
# 预期: time=200+ms, 偶有丢包

# ===== 清理弱网模拟 =====
tc qdisc del dev eth0 root

📐 重试策略设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                   指数退避 (Exponential Backoff)              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  尝试次数    退避时间        累计等待                          │
│  ─────────────────────────────────────                      │
│  第1次      立即               0s                           │
│  第2次      1s 后             1s                            │
│  第3次      2s 后             3s                            │
│  第4次      4s 后             7s                            │
│  第5次      8s 后            15s                            │
│                                                             │
│  base=1s, multiplier=2, max_backoff=30s, max_retries=5      │
└─────────────────────────────────────────────────────────────┘
python 复制代码
import time
import random

def retry_with_backoff(max_retries=5, base=1, max_backoff=30):
    """指数退避重试装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_retries:
                        raise  # 重试耗尽,向上抛异常

                    # 指数退避 + 随机抖动
                    backoff = min(base * (2 ** attempt), max_backoff)
                    jitter = random.uniform(0, backoff * 0.3)
                    sleep_time = backoff + jitter

                    print(f"[重试 {attempt+1}/{max_retries}] "
                          f"等待 {sleep_time:.1f}s, 原因: {e}")
                    time.sleep(sleep_time)
        return wrapper
    return decorator

@retry_with_backoff(max_retries=3, base=1)
def call_external_api(url):
    response = requests.get(url, timeout=5)
    response.raise_for_status()
    return response.json()

📐 幂等性保障

python 复制代码
import uuid
import hashlib

class IdempotentClient:
    """幂等 HTTP 客户端"""

    def __init__(self):
        self.processed = {}  # 生产环境用 Redis

    def post(self, url, data):
        # 生成唯一请求 ID
        request_id = str(uuid.uuid4())

        # 检查是否已处理
        if request_id in self.processed:
            return self.processed[request_id]

        # 发送请求 (带唯一 ID)
        headers = {'X-Request-Id': request_id}

        for attempt in range(3):
            try:
                resp = requests.post(url, json=data, 
                                     headers=headers, timeout=10)
                self.processed[request_id] = resp.json()
                return self.processed[request_id]
            except requests.RequestException:
                time.sleep(2 ** attempt)

        raise Exception("Max retries exceeded")

⚠️ 避坑清单

序号 描述 正确做法
1 🔴 支付重复提交 重试导致扣款两次 幂等 key + 数据库唯一约束
2 🟡 退避无上限 一直重试导致雪崩 max_backoff + max_retries
3 🟡 无抖动 (Jitter) 所有客户端同时重试 随机抖动避免惊群
4 🟢 忽略幂等 所有请求都重试 只重试 GET/PUT (幂等方法)

🔭 扩展思考

  1. gRPC 内置了哪些重试机制? → RetryPolicy + HedgingPolicy
  2. 弱网下如何做服务降级? → 返回缓存数据 / 静态兜底页
  3. 移动端弱网有什么特殊处理? → 离线队列 + 网络恢复后批量同步

第14讲:分片、并发与续传:怎样高效上传资源?

🎯 核心问题

GB 级大文件上传如何做到不中断、可恢复、高速率?

📐 大文件上传三阶段

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    大文件上传流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Stage 1: 分片 (Chunking)                                   │
│  ┌──────────────────────────────────────┐                   │
│  │ 1GB 文件 → 100 × 10MB Chunk          │                   │
│  │ Chunk 0 | Chunk 1 | ... | Chunk 99  │                   │
│  └──────────────────────────────────────┘                   │
│                    │                                        │
│  Stage 2: 并发上传 (Concurrent Upload)                       │
│  ┌──────────────────────────────────────┐                   │
│  │ 线程池 (5 threads)                    │                   │
│  │ Thread-1: Chunk 0, 5, 10, ...       │                   │
│  │ Thread-2: Chunk 1, 6, 11, ...       │                   │
│  │ ...                                  │                   │
│  │ 每个 Chunk: MD5 校验 + 进度上报       │                   │
│  └──────────────────────────────────────┘                   │
│                    │                                        │
│  Stage 3: 合并校验 (Merge & Verify)                          │
│  ┌──────────────────────────────────────┐                   │
│  │ 服务端合并所有 Chunk                   │                   │
│  │ 校验整体 SHA256                       │                   │
│  │ 返回文件 URL                          │                   │
│  └──────────────────────────────────────┘                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

🔬 实战:MinIO 分片上传

bash 复制代码
# Server D --- 部署 MinIO
docker run -d \
  --name minio \
  -p 9000:9000 \
  -p 9001:9001 \
  -e MINIO_ROOT_USER=admin \
  -e MINIO_ROOT_PASSWORD=Admin123! \
  minio/minio server /data --console-address ":9001"

Python 分片上传客户端

python 复制代码
import hashlib
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
from minio import Minio

CHUNK_SIZE = 10 * 1024 * 1024  # 10MB

def upload_chunk(client, bucket, object_name, upload_id,
                 chunk_data, part_number):
    """上传单个分片"""
    md5 = hashlib.md5(chunk_data).hexdigest()
    result = client._upload_part(
        bucket_name=bucket,
        object_name=object_name,
        part_number=part_number,
        upload_id=upload_id,
        data=chunk_data,
        md5_base64=md5
    )
    return part_number, result.etag

def multipart_upload(file_path, bucket="uploads", max_workers=5):
    """并发分片上传"""
    client = Minio(
        "192.168.0.44:9000",
        access_key="admin",
        secret_key="Admin123!",
        secure=False
    )

    # 确保 bucket 存在
    if not client.bucket_exists(bucket):
        client.make_bucket(bucket)

    object_name = os.path.basename(file_path)
    file_size = os.path.getsize(file_path)

    # 创建分片上传
    upload_id = client._create_multipart_upload(
        bucket, object_name
    )

    # 计算分片数
    total_parts = (file_size + CHUNK_SIZE - 1) // CHUNK_SIZE
    parts = []

    # 并发上传
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {}
        with open(file_path, 'rb') as f:
            for i in range(total_parts):
                chunk_data = f.read(CHUNK_SIZE)
                future = executor.submit(
                    upload_chunk, client, bucket, object_name,
                    upload_id, chunk_data, i + 1
                )
                futures[future] = i + 1

        # 收集结果
        for future in as_completed(futures):
            part_num, etag = future.result()
            parts.append((part_num, etag))
            print(f"Chunk {part_num}/{total_parts} uploaded ✓")

    # 完成上传
    parts.sort()  # 按分片号排序
    client._complete_multipart_upload(
        bucket, object_name, upload_id,
        [p[1] for p in parts]
    )

    print(f"Upload complete: {object_name} ({file_size} bytes)")

📊 分片大小 vs 性能

分片大小 总请求数 (1GB) 内存占用 适合网络
1MB 1024 极不稳定网络
5MB 205 弱网
10MB 103 一般 (推荐)
50MB 21 内网/稳定网络
100MB 11 内网高速

⚠️ 避坑清单

序号 描述 解决
1 Nginx 限制 client_max_body_size 默认 1MB 改为 client_max_body_size 0; (不限制)
2 代理缓冲 proxy_buffering 导致 OOM proxy_buffering off; 流式传输
3 超时断开 大文件上传中途超时 proxy_read_timeout 300s;
4 Chunk 顺序错误 并发上传后合并顺序混乱 按 part_number 排序后再合并

🔭 扩展思考

  1. 如何实现断点续传? → 客户端记录已上传 chunk 列表,跳过已完成的分片
  2. 如何在前端实现分片上传?File.slice() + XMLHttpRequest / fetch
  3. 如何做上传限速? → Token Bucket 控制单 chunk 上传速率

第15讲:DNS:域名解析系统是怎样工作的?

🎯 核心问题

当你在浏览器输入 URL 时,域名是如何变成 IP 地址的?

📐 DNS 查询全流程

复制代码
用户输入: www.example.com

┌─────────┐     ①查询          ┌──────────────┐
│  Client  │ ──────────────────→│  Local DNS    │
│         │                    │  (ISP/路由器)  │
└─────────┘                    └──────┬───────┘
                                      │
                    ② 递归查询到根域名服务器
                                      │
                                      ▼
                              ┌──────────────┐
                              │  Root DNS    │
                              │  返回 .com   │
                              │  NS 地址      │
                              └──────┬───────┘
                                     │
                    ③ 查询 .com 顶级域
                                     │
                                     ▼
                              ┌──────────────┐
                              │  TLD DNS     │
                              │  (.com)      │
                              │  返回 example│
                              │  .com NS     │
                              └──────┬───────┘
                                     │
                    ④ 查询权威 DNS
                                     │
                                     ▼
                              ┌──────────────┐
                              │ Authoritative│
                              │ DNS          │
                              │ 返回:        │
                              │ 1.2.3.4      │
                              └──────────────┘

⑤ Local DNS 缓存结果 → 返回给 Client
⑥ Client 拿到 1.2.3.4 → 发起 TCP 连接

🔬 实验:dig +trace 完整追踪

bash 复制代码
# 从 Server A 追踪 www.baidu.com 的解析路径
dig +trace www.baidu.com

# 输出分析:
# Step 1: 根域名服务器
# ; <<>> DiG 9.18 <<>> +trace www.baidu.com
# .   518400  IN  NS  a.root-servers.net.
# .   518400  IN  NS  b.root-servers.net.
# (13 个根域名服务器)

# Step 2: .com 顶级域
# com.  172800  IN  NS  a.gtld-servers.net.
# (返回 .com 的权威 NS)

# Step 3: baidu.com 权威 DNS
# baidu.com.  172800  IN  NS  dns.baidu.com.
# baidu.com.  172800  IN  NS  ns2.baidu.com.

# Step 4: 最终 A 记录
# www.baidu.com.  1200  IN  CNAME  www.a.shifen.com.
# www.a.shifen.com.  300  IN  A  110.242.68.66
# www.a.shifen.com.  300  IN  A  110.242.68.67

🔬 实验:dnsmasq 本地 DNS 劫持测试

bash 复制代码
# Server A --- 安装配置 dnsmasq
apt install -y dnsmasq

# 配置本地域名劫持
cat >> /etc/dnsmasq.conf << 'EOF'
# 劫持 example.com 到本地
address=/example.com/192.168.0.5
# 劫持所有 .test 域名
address=/test/192.168.0.207
EOF

systemctl restart dnsmasq

# 测试劫持效果
dig @127.0.0.1 example.com
# 输出: example.com. 0 IN A 192.168.0.5  ← 劫持成功!

dig @127.0.0.1 anything.test
# 输出: anything.test. 0 IN A 192.168.0.207  ← 劫持成功!

📊 DNS 记录类型速查

类型 含义 示例
A IPv4 地址 example.com. 300 IN A 1.2.3.4
AAAA IPv6 地址 example.com. 300 IN AAAA ::1
CNAME 别名 www.example.com. CNAME example.com.
MX 邮件服务器 example.com. MX 10 mail.example.com.
NS 权威 DNS example.com. NS ns1.example.com.
TXT 文本记录 用于 SPF/DKIM 验证
SRV 服务定位 _http._tcp.example.com. SRV ...
PTR 反向解析 4.3.2.1.in-addr.arpa. PTR example.com.

📊 DNS 安全方案对比

方案 保护目标 原理 普及度
DNSSEC 防篡改 数字签名验证 30%
DoH (DNS over HTTPS) 防窃听 DNS 查询走 HTTPS 90% (浏览器支持)
DoT (DNS over TLS) 防窃听 DNS 查询走 TLS 50% (系统级)
DNSCrypt 防窃听+防篡改 加密 + 签名 10%

⚠️ 避坑清单

序号 描述 解决
1 DNS 缓存 TTL 切换 IP 后旧缓存未过期 提前降低 TTL (如 60s)
2 CNAME 平铺 多级 CNAME 增加延迟 最多 1-2 级 CNAME
3 DNS 污染 运营商劫持返回错误 IP 使用 DoH/DoT
4 TTL 最小值 TTL=0 导致每次查询 合理 TTL: 60-300s (动态) / 3600s+ (静态)

🔭 扩展思考

  1. 如何实现 GSLB (全局负载均衡)? → 根据用户 IP 返回最近机房 IP (GeoDNS)
  2. HTTPDNS 是什么? → App 绕过运营商 DNS,直接请求 HTTP DNS 服务
  3. DNS 故障的降级方案? → 客户端 IP 列表兜底 + 本地 hosts

第16讲:CDN 架构(上):怎样加速静态资源下载?

🎯 核心问题

用户遍布全球,如何让每个人都能快速加载静态资源?

📐 CDN 工作原理

复制代码
                  ┌──────────────────────────────┐
                  │          源站 (Origin)         │
                  │      origin.example.com       │
                  │        1.2.3.4               │
                  └──────────────┬───────────────┘
                                 │ 回源 (仅首次/过期)
              ┌──────────────────┼──────────────────┐
              │                  │                  │
              ▼                  ▼                  ▼
    ┌─────────────────┐┌─────────────────┐┌─────────────────┐
    │  边缘节点 北京   ││  边缘节点 上海   ││  边缘节点 深圳   │
    │  Cache: 95%     ││  Cache: 93%     ││  Cache: 94%     │
    └────────┬────────┘└────────┬────────┘└────────┬────────┘
             │                  │                  │
             ▼                  ▼                  ▼
         北京用户            上海用户            深圳用户
         (5ms 延迟)          (3ms 延迟)          (2ms 延迟)

📐 CDN 缓存策略

nginx 复制代码
# Nginx 作为 CDN 边缘节点的缓存配置
proxy_cache_path /var/cache/nginx levels=1:2 
    keys_zone=STATIC:100m max_size=10g inactive=7d;

server {
    listen 80;
    server_name cdn.example.com;

    # 静态资源缓存
    location /static/ {
        proxy_pass http://origin.example.com;
        proxy_cache STATIC;
        proxy_cache_key "$uri$is_args$args";
        proxy_cache_valid 200 7d;        # 200 响应缓存 7 天
        proxy_cache_valid 404 1m;        # 404 缓存 1 分钟

        # 缓存状态 header (调试用)
        add_header X-Cache-Status $upstream_cache_status;

        # 回源超时
        proxy_connect_timeout 5s;
        proxy_read_timeout 10s;
    }
}

X-Cache-Status 含义

状态 含义
HIT 缓存命中 ✓
MISS 缓存未命中,已回源
EXPIRED 缓存过期,已回源刷新
BYPASS 跳过缓存 (如 Cookie 导致)
UPDATING 正在更新缓存 (stale-while-revalidate)

📊 缓存命中率诊断

bash 复制代码
# 分析 Nginx 访问日志中的缓存命中率
awk '{print $NF}' /var/log/nginx/access.log | sort | uniq -c

# 预期输出:
#  89450 HIT
#   5000 MISS
#    450 EXPIRED
#    100 BYPASS
# 命中率 = 89450 / (89450+5000+450+100) = 94.1%

⚠️ 缓存命中率低的常见原因

原因 现象 解决
未设 Cache-Control 源站不返回缓存头 添加 Cache-Control: public, max-age=86400
动态参数 ?t=1234567890 导致 key 不同 忽略无意义参数 proxy_cache_key "$uri"
Cookie 穿透 有 Cookie 的请求绕过 CDN proxy_ignore_headers Set-Cookie
Vary 头不当 Vary: User-Agent 导致缓存碎片化 标准化 User-Agent 或移除

🔭 扩展思考

  1. 预热 vs 刷新有什么区别? → 预热=提前拉取;刷新=清除缓存强制回源
  2. CDN 如何做图片处理? → 边缘计算 (如 Cloudflare Workers) 实时裁剪/压缩/转格式
  3. HTTP/3 对 CDN 有什么影响? → QUIC 0-RTT + 连接迁移,移动端体验提升显著

第17讲:CDN 架构(下):怎样加速动态内容?

🎯 核心问题

静态资源可以用 CDN 缓存,但动态 API 请求如何加速?

📐 动态内容加速 (DCDN) 技术栈

复制代码
┌──────────────────────────────────────────────────────────────┐
│                    DCDN 加速层                                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  Layer 1: 智能选路                                            │
│  ┌────────────────────────────────────────────────┐          │
│  │ 边缘节点 → 最优路径 → 源站                       │          │
│  │ 基于实时延迟/丢包率的动态路由                     │          │
│  └────────────────────────────────────────────────┘          │
│                                                              │
│  Layer 2: 协议优化                                            │
│  ┌────────────────────────────────────────────────┐          │
│  │ TCP: BBR + TCP Fast Open                       │          │
│  │ TLS: 1.3 + 0-RTT + Session Resumption           │          │
│  │ HTTP: HTTP/2 多路复用 + Server Push              │          │
│  │ QUIC: 0-RTT + 连接迁移 + 无队头阻塞              │          │
│  └────────────────────────────────────────────────┘          │
│                                                              │
│  Layer 3: 链路优化                                            │
│  ┌────────────────────────────────────────────────┐          │
│  │ 私有传输协议 (如 Cloudflare Argo)                │          │
│  │ 链路冗余 + 故障秒级切换                          │          │
│  │ 数据压缩 (Brotli)                               │          │
│  └────────────────────────────────────────────────┘          │
│                                                              │
└──────────────────────────────────────────────────────────────┘

📊 HTTP 版本性能对比

复制代码
测试条件: 100 个小文件 (每个 20KB), 50ms RTT

协议          连接数     TTFB (ms)   总加载时间 (ms)   备注
─────────────────────────────────────────────────────────
HTTP/1.1      6         50          850              队头阻塞
HTTP/2        1         45          320              多路复用
HTTP/3 (QUIC) 1         15          250              0-RTT + 无队头阻塞

提升 vs 1.1    -83%      -70%        -71%

📐 HTTP/2 Server Push 示例

nginx 复制代码
# Nginx HTTP/2 Server Push 配置
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;

    location / {
        root /var/www/html;
        http2_push /css/style.css;
        http2_push /js/app.js;
        http2_push /images/logo.png;
        # 关键资源提前推送,无需等待 HTML 解析
    }
}

📐 QUIC 协议优势

复制代码
TCP + TLS 1.2:
  Client → SYN
  Server → SYN-ACK
  Client → ACK + ClientHello
  Server → ServerHello + Certificate
  Client → Finished
  握手: 2 RTT

TCP + TLS 1.3:
  Client → SYN + ClientHello
  Server → SYN-ACK + ServerHello + Certificate + Finished
  Client → Finished
  握手: 1 RTT

QUIC (首次):
  Client → ClientHello (in QUIC)
  Server → ServerHello + Finished (in QUIC)
  握手: 1 RTT

QUIC (0-RTT 重连):
  Client → ClientHello + HTTP Request (同时发送!)
  Server → Response
  握手: 0 RTT!  (首次后重连)

⚠️ 避坑清单

序号 描述
1 HTTP/2 在弱网不如 HTTP/1.1 高丢包下多路复用全部阻塞,反而更慢
2 Server Push 滥用 推送浏览器已缓存的资源,浪费带宽
3 QUIC 被防火墙拦截 部分企业防火墙封 UDP 443,需要 fallback TCP
4 0-RTT 不安全 重放攻击风险,只用于幂等 GET 请求

🔭 扩展思考

  1. HTTP/3 普及到什么程度了? → 2025年约 35% 网站支持,Google/Cloudflare/CDN 全面支持
  2. 私有传输协议比 QUIC 更好吗? → 理论上可以更优(定制化),但生态差
  3. 边缘函数如何加速动态请求? → 在边缘节点直接处理请求(如认证、A/B测试),减少回源


🔹 实战篇(下)


第18讲:全球网络加速架构:怎样加速动态请求?

🎯 核心问题

跨国业务中,如何将海外用户的延迟从 300ms 降低到 80ms?

📐 全球加速核心方案

复制代码
                      ┌──────────────────┐
                      │   用户 (东南亚)    │
                      │   延迟: 300ms →   │
                      └────────┬─────────┘
                               │
                      ┌────────▼─────────┐
                      │  边缘节点 (新加坡) │
                      │  - 边缘函数        │
                      │  - 智能缓存        │
                      └────────┬─────────┘
                               │ 私有加速网络
                               │ (延迟 < 5ms)
                      ┌────────▼─────────┐
                      │  源站 (中国香港)   │
                      │  延迟: 300ms →   │
                      │  80ms (-73%)     │
                      └──────────────────┘

加速方案对比

方案 原理 延迟降低 成本 复杂度
Anycast 同一个 IP 广播到多个地理位置 30-50%
GSLB (GeoDNS) 根据用户 IP 返回最近机房 40-60%
边缘函数 在边缘节点处理请求 50-80%
私有加速网络 专用骨干网传输 60-80%

📊 某出海 App 优化案例

复制代码
优化前:
  新加坡用户 → 直接请求中国香港源站
  延迟: 280ms (公网路由绕路)
  TTFB: 320ms

优化后:
  新加坡用户 → 新加坡边缘节点 (5ms)
  新加坡边缘 → 香港源站 (专用线路, 40ms)
  延迟: 45ms (-84%)
  TTFB: 55ms (-83%)

🔭 扩展思考

  1. AWS Global Accelerator 的原理? → Anycast + AWS 骨干网
  2. Cloudflare Argo 为什么快? → 实时拥塞感知的智能路由
  3. 自建全球加速要多少钱? → 至少 ¥50000/月 (多地域 ECS + 带宽)

第19讲:SSL/TLS:怎样在公网安全传输数据?

🎯 核心问题

公网数据传输如何做到不被窃听、不被篡改?

📐 TLS 1.3 握手流程(精简版)

复制代码
Client                          Server
  │                               │
  │── ClientHello ───────────────→│
  │   (支持的密码套件 + 密钥共享)    │
  │                               │
  │←─ ServerHello ────────────────│
  │   (选定的密码套件 + 密钥共享)    │
  │   EncryptedExtensions          │
  │   Certificate (证书)           │
  │   CertificateVerify (签名)     │
  │   Finished                     │
  │                               │
  │── Finished ──────────────────→│
  │                               │
  │◄══════ 加密通信开始 ══════════►│

  总耗时: 1 RTT (首次) / 0 RTT (PSK 重连)

🔬 实战:Nginx TLS 1.3 完整配置

nginx 复制代码
server {
    listen 443 ssl http2;
    server_name example.com;

    # === 证书配置 ===
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # === TLS 1.3 专用配置 ===
    ssl_protocols TLSv1.2 TLSv1.3;  # 仅允许 TLS 1.2+

    # TLS 1.3 密码套件
    ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256;

    # === 安全加固 ===
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;       # 禁用 Session Ticket (安全考虑)

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/ssl/chain.pem;

    # HSTS (强制 HTTPS, 包含子域名)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # 其他安全头
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
}

📊 TLS 版本性能对比

TLS 版本 握手 RTT 密码套件 安全性
TLS 1.0 2 弱 (RC4/MD5) 不安全 ❌
TLS 1.1 2 不安全 ❌
TLS 1.2 2 较强 (AES-GCM) 安全 ✅
TLS 1.3 1 强 (仅 AEAD) 最安全 ✅✅

⚠️ 避坑清单

序号 描述 解决
1 证书链不完整 浏览器提示不安全 使用 fullchain.pem (含中间证书)
2 混合内容 HTTPS 页面引用 HTTP 资源 全站 HTTPS + CSP 策略
3 证书过期 服务中断 Let's Encrypt 自动续期 (certbot)
4 弱密码套件 PCI DSS 合规失败 仅启用 TLS 1.3 + AEAD 套件

🔭 扩展思考

  1. mTLS 是什么?什么时候需要? → 双向 TLS 认证,微服务间通信
  2. Certificate Transparency 解决什么问题? → 防止 CA 错误签发证书
  3. 后量子密码学对 TLS 有什么影响? → TLS 1.3 已支持 PQC 混合密钥交换

第20讲:VPN:怎样构建安全的企业网络?

🎯 核心问题

远程办公/多机房互联时,如何建立安全加密隧道?

📐 三种主流方案对比

方案 协议 延迟 吞吐 复杂度 适用
IPSec VPN ESP/AH 站点到站点
WireGuard UDP 极低 极高 极低 远程办公/站点互联
OpenVPN TCP/UDP 远程办公
Zero Trust HTTPS 现代化替代

🔬 实战:WireGuard 点对点隧道

实验拓扑

复制代码
┌──────────────┐              ┌──────────────┐
│  Server A    │   WireGuard  │  Server B    │
│  192.168.0.5 │══════════════│ 192.168.0.207│
│  WG: 10.0.0.1│  加密隧道     │  WG: 10.0.0.2│
└──────────────┘              └──────────────┘
bash 复制代码
# ===== Server A 配置 =====
apt install -y wireguard

# 生成密钥对
wg genkey | tee /etc/wireguard/privatekey | wg pubkey > /etc/wireguard/publickey

cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
PrivateKey = <ServerA-私钥>
Address = 10.0.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <ServerB-公钥>
Endpoint = 192.168.0.207:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
EOF

systemctl enable --now wg-quick@wg0
bash 复制代码
# ===== Server B 配置 =====
apt install -y wireguard

wg genkey | tee /etc/wireguard/privatekey | wg pubkey > /etc/wireguard/publickey

cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
PrivateKey = <ServerB-私钥>
Address = 10.0.0.2/24
ListenPort = 51820

[Peer]
PublicKey = <ServerA-公钥>
Endpoint = 192.168.0.5:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
EOF

systemctl enable --now wg-quick@wg0
bash 复制代码
# 验证隧道
wg show

# 测试连通
ping 10.0.0.2  # Server A → Server B 隧道 IP

⚠️ WireGuard 优势

特性 WireGuard OpenVPN IPSec
代码行数 ~4000 ~70000 ~400000
内核集成 ✅ Linux 5.6+
漫游支持 ✅ 天然支持
配置复杂度 极低 极高
加密算法 现代 (ChaCha20) 可选 可选

🔭 扩展思考

  1. WireGuard 适合大规模部署吗? → 适合,配合 wg-dynamic 或 Netmaker 管理
  2. Zero Trust 为什么比 VPN 更好? → 不信任网络位置,每个请求都验证
  3. SD-WAN 和传统 VPN 有什么区别? → SD-WAN 智能选路 + 应用感知 + 集中管理

第21讲:多重武装:怎样建设安全的网络架构?

🎯 核心问题

单层防护永远不够,如何构建纵深防御体系?

📐 纵深防御 (Defense in Depth) 模型

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    纵深防御五层模型                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Layer 1: 边界防护                                     │  │
│  │  云安全组 + iptables + DDoS 清洗 + WAF                  │  │
│  └───────────────────────────────────────────────────────┘  │
│                         │ 突破                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Layer 2: 网络隔离                                     │  │
│  │  VPC + 子网 + NACL + 微分段                             │  │
│  └───────────────────────────────────────────────────────┘  │
│                         │ 突破                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Layer 3: 主机加固                                     │  │
│  │  SELinux/AppArmor + 最小权限 + 补丁管理                 │  │
│  └───────────────────────────────────────────────────────┘  │
│                         │ 突破                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Layer 4: 应用防护                                     │  │
│  │  输入验证 + SQL注入防护 + XSS防护 + CSRF Token          │  │
│  └───────────────────────────────────────────────────────┘  │
│                         │ 突破                               │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Layer 5: 数据加密                                     │  │
│  │  TLS 传输加密 + 磁盘加密 + 数据库加密 + 密钥管理         │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

🔬 实战:iptables 安全规则

bash 复制代码
# ===== 默认策略 =====
iptables -P INPUT DROP     # 默认拒绝入站
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# ===== 允许必要的入站 =====
# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT

# 允许 SSH (限制来源 IP)
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# ===== 防 DDoS =====
# 限制 SSH 连接速率
iptables -A INPUT -p tcp --dport 22 -m recent --set --name ssh
iptables -A INPUT -p tcp --dport 22 -m recent --update \
    --seconds 60 --hitcount 4 --name ssh -j DROP

# 限制 SYN 洪水
iptables -A INPUT -p tcp --syn -m limit --limit 100/s --limit-burst 100 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

# 丢弃无效包
iptables -A INPUT -m state --state INVALID -j DROP

📊 安全工具选型

层次 工具 开源 适用
WAF ModSecurity + OWASP CRS 自建
WAF Cloudflare WAF ❌ (免费层可用) SaaS
IDS/IPS Snort / Suricata 自建
漏洞扫描 OpenVAS / Trivy 自建
SIEM Wazuh / ELK 自建
密钥管理 HashiCorp Vault 自建

⚠️ 避坑清单

序号 描述 正确做法
1 🔴 安全组 0.0.0.0/0 对所有 IP 开放 SSH/数据库端口 限制来源 IP 范围
2 🔴 默认密码 数据库/中间件使用默认密码 强密码 + 定期轮换
3 🟡 iptables 规则丢失 重启后规则消失 iptables-save + systemd 持久化
4 🟡 WAF 规则过严 正常请求被拦截 先观察模式 → 再拦截模式

🔭 扩展思考

  1. 零信任架构 (Zero Trust) 的核心原则? → 永不信任,始终验证 (Never Trust, Always Verify)
  2. 如何做红蓝对抗演练? → 红队模拟攻击,蓝队检测防御,紫队协调复盘
  3. eBPF 在安全领域有什么应用? → 运行时安全监控 (Falco/Cilium)

第22讲:兼容:网络协议怎样在存量中迭代?

🎯 核心问题

如何在不中断现有服务的情况下,让新旧协议共存并平滑演进?

📐 协议演进策略

策略 1:优雅降级(客户端能力探测)
复制代码
Client → Server: Accept: application/json, application/x-protobuf
Server 检查 Accept header:
  如果支持 protobuf → 返回 protobuf (高性能)
  否则 → 返回 JSON (兼容)
python 复制代码
# Python Flask 示例
from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/api/data')
def get_data():
    data = {"id": 1, "name": "test", "value": 100}

    # 检查客户端 Accept header
    accept = request.headers.get('Accept', '')

    if 'application/x-protobuf' in accept:
        # 新协议: Protobuf
        return protobuf_encode(data), 200, {
            'Content-Type': 'application/x-protobuf'
        }
    else:
        # 旧协议: JSON
        return jsonify(data)
策略 2:双写过渡期
复制代码
              ┌──────────┐
              │  Client  │
              └────┬─────┘
                   │
         ┌─────────┴─────────┐
         │                   │
    (新协议)              (旧协议)
         │                   │
         ▼                   ▼
   ┌──────────┐        ┌──────────┐
   │  Protobuf│        │   JSON   │
   │  Service │        │  Service │
   └──────────┘        └──────────┘

   过渡期: 两个版本并行运行
   新客户端 → Protobuf
   旧客户端 → JSON

   流量镜像: 新协议处理 10% → 50% → 100%
策略 3:API 版本管理
复制代码
版本策略对比:

URL Path:    /api/v1/users   /api/v2/users
            优点: 清晰直观
            缺点: URL 污染

Header:      GET /api/users
             API-Version: 1
            优点: URL 干净
            缺点: 不直观

Query:       /api/users?version=1
            优点: 简单
            缺点: 缓存 key 混乱

推荐: URL Path (对外 API) + Header (内部 API)

📊 微信支付 XML → Protobuf 迁移案例

复制代码
阶段 1: 仅 XML (V2)
  所有商户使用 XML 格式

阶段 2: XML + Protobuf 双写 (V3 Beta)
  新商户可选 Protobuf
  旧商户继续 XML

阶段 3: Protobuf 为主 (V3 GA)
  默认 Protobuf, XML 标记为 deprecated
  设置 XML 关闭日期

阶段 4: 仅 Protobuf
  移除 XML 支持
  总迁移时间: ~3年

⚠️ 避坑清单

序号 描述 解决
1 过早移除旧协议 老客户端无法使用 至少保留 2 个大版本的兼容
2 字段语义变更 同名字段含义不同 新增字段而非修改
3 二进制不兼容 Protobuf 字段编号变更 字段编号永久保留,只增不删

第23讲:VPC架构:云网络时代多租户怎样无感隔离?

🎯 核心问题

公有云上,不同租户的网络如何做到完全隔离?

📐 VPC 核心组件

复制代码
┌──────────────────────────────────────────────────────────────┐
│                       VPC (10.0.0.0/16)                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────────────┐    ┌─────────────────────┐         │
│  │  Public Subnet      │    │  Private Subnet     │         │
│  │  10.0.1.0/24        │    │  10.0.2.0/24        │         │
│  │                     │    │                     │         │
│  │  ┌───────────────┐  │    │  ┌───────────────┐  │         │
│  │  │  Nginx (公网)  │  │    │  │  MySQL (私网)  │  │         │
│  │  │  10.0.1.10     │  │    │  │  10.0.2.10    │  │         │
│  │  └───────────────┘  │    │  └───────────────┘  │         │
│  │                     │    │                     │         │
│  │  路由表:             │    │  路由表:             │         │
│  │  0.0.0.0/0 → IGW   │    │  0.0.0.0/0 → NAT   │         │
│  └─────────────────────┘    └─────────────────────┘         │
│                                                              │
│  Internet Gateway (IGW)          NAT Gateway                  │
└──────────────────────────────────────────────────────────────┘

📐 安全组 vs 网络 ACL

特性 安全组 (Security Group) 网络 ACL (NACL)
作用范围 实例级 (ENI) 子网级
状态 有状态 (自动允许响应) 无状态 (需双向规则)
规则类型 仅允许 (Allow) 允许 + 拒绝 (Allow/Deny)
规则评估 所有规则聚合评估 按编号顺序评估
默认行为 拒绝所有入站 允许所有

🔬 实战:跨账号 VPC 对等连接

复制代码
┌──────────────────────┐         ┌──────────────────────┐
│  账号 A (开发)        │         │  账号 B (测试)        │
│  VPC-A: 10.1.0.0/16 │◄═══════►│  VPC-B: 10.2.0.0/16 │
│                      │  Peering│                      │
│  EC2: 10.1.1.10      │         │  EC2: 10.2.1.10      │
└──────────────────────┘         └──────────────────────┘
bash 复制代码
# AWS CLI --- 创建跨账号 VPC Peering
# 账号 A 发起请求
aws ec2 create-vpc-peering-connection \
  --vpc-id vpc-aaa111 \
  --peer-vpc-id vpc-bbb222 \
  --peer-owner-id 123456789012 \
  --region ap-east-1

# 账号 B 接受请求
aws ec2 accept-vpc-peering-connection \
  --vpc-peering-connection-id pcx-xxx

# 双方添加路由
# 账号 A
aws ec2 create-route \
  --route-table-id rtb-aaa \
  --destination-cidr-block 10.2.0.0/16 \
  --vpc-peering-connection-id pcx-xxx

# 账号 B
aws ec2 create-route \
  --route-table-id rtb-bbb \
  --destination-cidr-block 10.1.0.0/16 \
  --vpc-peering-connection-id pcx-xxx

⚠️ 避坑清单

序号 描述
1 🔴 默认安全组 0.0.0.0/0 新创建的安全组默认规则可能放行所有流量
2 🟡 Peering CIDR 重叠 双方 VPC 的 CIDR 不能重叠
3 🟡 Peering 不可传递 A↔B + B↔C ≠ A↔C,需要 Transit Gateway
4 🟢 NACL 优先级 低编号规则优先匹配,注意顺序

🔭 扩展思考

  1. Transit Gateway vs VPC Peering? → TGW 支持星型拓扑 + 传递路由 + 多账号
  2. PrivateLink 解决了什么问题? → 不暴露公网的服务间通信
  3. Kubernetes 网络模型和 VPC 的关系? → CNI 插件在 VPC 内实现 Pod 网络

第24讲:加餐|思考题答案合集

🎯 前23讲关键问题深度解答

Q1:为什么 TIME_WAIT 连接过多会导致端口耗尽?

A :Linux 默认 net.ipv4.ip_local_port_range = 32768-60999,仅约 28231 个可用端口。每个主动关闭的 TCP 连接进入 TIME_WAIT 状态持续 60 秒(2*MSL)。如果每秒新建连接超过 28231/60 ≈ 470,端口就会耗尽。解决方案:启用 tcp_tw_reuse、扩大端口范围、使用长连接。

Q2:CDN 缓存命中率低的常见原因?

A :三大原因------① 源站未设置 Cache-Control 头,CDN 不知道缓存多久;② URL 包含动态参数(如 ?t=1234567890),导致每个请求缓存 key 不同;③ 请求携带 Cookie,CDN 默认跳过缓存。

Q3:TCP 为什么需要三次握手而不是两次?

A:防止历史连接初始化。如果只有两次握手,一个延迟到达的旧 SYN 包会让服务端错误地建立连接。第三次握手让客户端有机会拒绝不想要的连接。

Q4:ping 通但 curl 不通的原因?

A:ping 使用 ICMP 协议(网络层),curl 使用 TCP 协议(传输层)。可能原因:① 目标端口未监听;② 防火墙放行 ICMP 但拦截 TCP 特定端口;③ 应用层服务未启动。

Q5:为什么 HTTP/2 在弱网下反而更慢?

A:HTTP/2 在单个 TCP 连接上多路复用所有请求。如果网络丢包,TCP 的队头阻塞会导致该连接上所有请求都被阻塞。HTTP/3 (QUIC) 解决了这个问题------每个流独立,丢包只影响单个流。

Q6:WireGuard 为什么比 OpenVPN 快?

A:① 代码量少(4000 vs 70000 行),攻击面小、bug 少;② 内核态运行(Linux 5.6+),无用户态/内核态切换;③ 使用 ChaCha20-Poly1305(比 AES 更快);④ 无连接设计,天然支持漫游。

Q7:什么是脑裂(Split-Brain)?如何预防?

A:脑裂是集群中两个节点都认为自己是主节点。原因:节点间通信中断。预防:① 仲裁(Quorum)机制,必须有超过半数节点同意;② 隔离(Fencing),如 STONITH;③ ARP 检查。

Q8:令牌桶和漏桶的核心区别?

A:令牌桶允许突发(桶内可积累令牌),漏桶强制平滑输出。令牌桶适合有 burst 需求的 API 网关;漏桶适合需要稳定出队的消息队列。

Q9:为什么需要分布式限流?

A:单机限流只能限制本机。如果 3 台服务器每台限流 10/s,总流量可达 30/s。分布式限流使用 Redis 等集中式计数器,确保整个集群总共不超过 10/s。

Q10:BBR 和 CUBIC 的本质区别?

A:CUBIC 基于丢包检测(丢包 = 拥塞),会主动降速;BBR 基于带宽和 RTT 测量,不依赖丢包信号。在有一定丢包的网络中(如 Wi-Fi/4G),BBR 性能远超 CUBIC。


第25讲:加餐|搞懂 Nginx 限流的关键概念

🎯 深度补充第8讲

📐 Nginx 限流三剑客

复制代码
┌─────────────────────────────────────────────────────────────┐
│                  Nginx 限流三剑客                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  limit_conn      限制并发连接数                               │
│  ─────────────────────────────────────                      │
│  同一 IP 同时最多 N 个 TCP 连接                               │
│  超出 → 503 Service Unavailable                             │
│                                                             │
│  limit_req       限制请求速率                                │
│  ─────────────────────────────────────                      │
│  每秒最多 N 个请求                                           │
│  burst: 允许的突发容量                                       │
│  nodelay: 突发请求是否立即处理                                │
│                                                             │
│  limit_rate      限制响应带宽                                │
│  ─────────────────────────────────────                      │
│  单个连接的最大下载速度                                       │
│  如 limit_rate 100k;  # 限速 100KB/s                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

📐 burst 与 nodelay 的微妙区别

nginx 复制代码
# === 场景对比 ===
# 限制: rate=10r/s (每 100ms 一个请求)

# 配置 A: burst=5 nodelay
limit_req zone=api burst=5 nodelay;
# 到达 6 个并发请求 → 5 个立即处理 + 1 个 503
# 特点: 突发立即处理,之后恢复 10r/s

# 配置 B: burst=5 (无 nodelay)
limit_req zone=api burst=5;
# 到达 6 个并发请求 → 1 个立即处理 + 5 个排队 (每 100ms 释放一个) + 0 个 503
# 特点: 突发请求排队等待,第 6 个请求等待最多 500ms

可视化对比

复制代码
配置 A: burst=5 nodelay
请求: ① ② ③ ④ ⑤ ⑥ (同时到达)
处理: ① ② ③ ④ ⑤ ✓ (立即)  ⑥ ✗ (503)
时间: 0ms─────────────────────────→

配置 B: burst=5
请求: ① ② ③ ④ ⑤ ⑥ (同时到达)
处理: ① ✓ (0ms)  ② ✓ (100ms)  ③ ✓ (200ms)  ...
时间: 0ms─────100ms─────200ms─────300ms─────→

📐 完整限流配置模板

nginx 复制代码
http {
    # 定义限流区域
    limit_req_zone $binary_remote_addr zone=api_rate:10m rate=10r/s;
    limit_req_zone $server_name zone=per_server:10m rate=1000r/s;
    limit_conn_zone $binary_remote_addr zone=api_conn:10m;

    # 白名单 (不限制的 IP)
    geo $limit {
        default 1;
        10.0.0.0/8 0;      # 内网不限流
        192.168.0.0/16 0;  # 内网不限流
    }

    map $limit $limit_key {
        0 "";               # 空 key → 不限流
        1 $binary_remote_addr;
    }

    server {
        listen 80;

        # 全局限流
        location / {
            limit_req zone=api_rate burst=10 nodelay;
            limit_req_status 429;  # 自定义状态码
            limit_conn api_conn 10;
            limit_conn_status 429;

            proxy_pass http://backend;
        }

        # 敏感接口更严格
        location /api/payment/ {
            limit_req zone=api_rate burst=3 nodelay;
            limit_req_status 429;

            proxy_pass http://payment_backend;
        }

        # 下载限速
        location /downloads/ {
            limit_rate 500k;  # 500KB/s
            limit_rate_after 1m;  # 前 1MB 不限速
        }
    }
}

⚠️ 避坑清单

序号 描述 解决
1 binary_remote_addr vs remote_addr 前者节省内存 4× 始终使用 $binary_remote_addr
2 zone 大小不足 内存不够导致限流失效 64字节/IP → 10MB ≈ 16万IP
3 burst 理解错误 burst 是并发容量不是额外速率 burst=5 不会让速率变成 15r/s
4 429 状态码处理 客户端不知道如何响应 429 配合 Retry-After header

🔭 扩展思考

  1. 如何实现"动态限流"(根据后端负载自动调整)? → OpenResty + Lua + 共享内存
  2. Nginx 限流 vs API 网关限流怎么选? → Nginx 适合简单场景;网关(Kong/APISIX)功能更丰富
  3. 如何监控限流效果?$limit_req_status 变量 + Prometheus nginx-exporter


🔹 结束篇


第26讲:结束语|每一次问题,都是成长的契机

🎯 架构师的成长心法

经过 25 讲的系统学习,你已经从协议层到系统层完整走了一遍网络架构的设计之道。但技术的终点不是知识,而是思维方式。

💡 三个"从...到..."的转变

复制代码
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  转变 1: 从"解决问题"到"预防问题"                               │
│  ─────────────────────────────────────                      │
│  初级工程师: 出故障 → 修复                                    │
│  架构师:      设计阶段就消除故障可能                            │
│  关键能力:    FMEA (故障模式与影响分析)                         │
│                                                             │
│  转变 2: 从"技术实现"到"业务权衡"                               │
│  ─────────────────────────────────────                      │
│  初级工程师: 技术选型看谁"最好"                                │
│  架构师:      在成本/性能/可靠性之间找平衡                      │
│  关键能力:    五维评估模型 (第5讲)                              │
│                                                             │
│  转变 3: 从"单点最优"到"系统全局"                               │
│  ─────────────────────────────────────                      │
│  初级工程师: 优化单个服务                                      │
│  架构师:      优化整个系统,可能局部要妥协                       │
│  关键能力:    瓶颈分析 + 全局视角                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

📚 推荐书单

书名 作者 核心价值
《Designing Data-Intensive Applications》 Martin Kleppmann 数据系统的设计哲学
《Site Reliability Engineering》 Google SRE Team 生产环境的运维之道
《TCP/IP Illustrated, Vol.1》 W. Richard Stevens 协议细节的权威参考
《Computer Networking: A Top-Down Approach》 Kurose & Ross 网络原理入门经典
《Systems Performance》 Brendan Gregg 性能分析方法论
《Cloud Native Infrastructure》 Justin Garrison 云原生基础设施模式

🗺️ 继续学习路线

复制代码
本系列完成后的推荐路径:

网络架构实战 (本系列)
  │
  ├── 深入方向: eBPF 可观测性 (性能调优进阶)
  ├── 广度方向: Kubernetes 网络 (CNI/ServiceMesh)
  ├── 应用方向: API 网关设计与开发
  └── 安全方向: 零信任架构实践

推荐认证:
  - CKA/CKAD (Kubernetes)
  - AWS Solutions Architect
  - CCIE (网络最高认证)

🎯 你已经具备的能力

复制代码
✅ 独立设计中大型系统网络架构的能力
✅ 快速定位与解决线上网络问题的实战经验
✅ 在成本、性能、安全间做出合理权衡的架构思维
✅ 一套可复用的网络诊断与优化工具箱
✅ 从单机到云原生的全栈网络视野

第27讲:结课测试|来赴一场满分之约吧

📝 选择题

1. 某直播平台峰值 10 万并发,用户反馈"卡顿严重"。请选择正确的排查路径:

A. 检查 CDN 缓存命中率

B. 抓包分析 TCP 重传率

C. 查看应用层 GC 日志

D. 以上都是

正确答案:D --- 需要系统性排查:CDN(静态资源)→ TCP(传输质量)→ 应用(处理能力)


2. 以下哪个场景最适合使用一致性哈希负载均衡?

A. 静态文件下载

B. 用户登录后需要会话保持

C. 计算密集型任务

D. 实时消息推送

正确答案:B --- 一致性哈希确保同一用户始终路由到同一服务器


3. TLS 1.3 相比 TLS 1.2 的握手需要几次 RTT?

A. 3 RTT

B. 2 RTT

C. 1 RTT

D. 0 RTT

正确答案:C --- TLS 1.3 首次握手 1 RTT,PSK 重连 0 RTT


4. 以下哪个不是 TIME_WAIT 过多的正确解决方案?

A. 启用 tcp_tw_reuse

B. 使用 HTTP 长连接

C. 减小 MSL 时间

D. 增加服务器内存

正确答案:D --- 增加内存不能解决端口耗尽问题


5. 以下关于 VPC 对等连接的说法,哪个是错误的?

A. 双方 VPC 的 CIDR 不能重叠

B. 对等连接可以跨账号

C. 对等连接支持传递路由 (A↔B↔C = A↔C)

D. 需要双方都添加路由

正确答案:C --- VPC 对等连接不可传递,需要 Transit Gateway 实现


🏗️ 场景设计题

挑战:设计一个支持百万设备接入的物联网网关架构

复制代码
设计要求:
- 100 万设备同时在线
- 每设备每 10 秒上报一次数据 (100KB)
- 需要支持设备认证 + 数据加密
- 99.99% 可用性

┌──────────────────────────────────────────────────────────────┐
│                    IoT 网关架构 (百万级)                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  设备层                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ 100万设备 × MQTT/TLS 1.3                              │   │
│  │ 每设备 10s/次, 100KB/次                               │   │
│  └──────────────────────────────────────────────────────┘   │
│                         │                                    │
│  接入层 (L4 负载均衡)                                         │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ HAProxy × 4 (L4, source hash)                        │   │
│  │ 每台: 25万连接, 2.5 Gbps                             │   │
│  └──────────────────────────────────────────────────────┘   │
│                         │                                    │
│  消息层                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ EMQX Cluster × 8 节点                                 │   │
│  │ 每节点: 12.5万连接                                    │   │
│  │ 消息吞吐: 10万 msg/s × 100KB = 10 GB/s               │   │
│  └──────────────────────────────────────────────────────┘   │
│                         │                                    │
│  处理层                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ Kafka Cluster × 10 节点                               │   │
│  │ 数据缓冲 + 流处理                                      │   │
│  └──────────────────────────────────────────────────────┘   │
│                         │                                    │
│  存储层                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ TDengine × 5 节点 (时序数据)                           │   │
│  │ MySQL Cluster (设备元数据)                             │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
│  容量估算:                                                    │
│  带宽: 10万 msg/s × 100KB = 10 GB/s                        │
│  存储: 10 GB/s × 86400s = 864 TB/天                       │
│        → 保留 30 天 = 25.9 PB                              │
│                                                              │
│  成本估算 (粗略):                                             │
│  接入层: 4×EMQX Enterprise ≈ ¥20000/月                      │
│  消息层: 10×Kafka Broker ≈ ¥30000/月                        │
│  存储层: TDengine + MySQL ≈ ¥15000/月                       │
│  带宽: 10 Gbps 专线 ≈ ¥80000/月                             │
│  总计: ≈ ¥145000/月                                         │
│                                                              │
└──────────────────────────────────────────────────────────────┘

📌 系列附录

🛠️ 配套实验脚本索引

脚本 对应讲数 用途
lab-01-tcpdump.sh 第1讲 HTTP 完整生命周期抓包
lab-02-env-setup.sh 第2讲 Docker 实验环境一键部署
lab-06-keepalived.sh 第6讲 keepalived + nginx 高可用
lab-07-haproxy.sh 第7讲 HAProxy 负载均衡
lab-08-nginx-limit.sh 第8讲 Nginx 限流配置
lab-11-bbr-test.sh 第11讲 BBR vs CUBIC 对比
lab-13-netem.sh 第13讲 tc netem 弱网模拟
lab-14-minio-upload.py 第14讲 MinIO 分片上传
lab-15-dns-dig.sh 第15讲 DNS 追踪分析
lab-19-nginx-tls.sh 第19讲 Nginx TLS 1.3 配置
lab-20-wireguard.sh 第20讲 WireGuard 隧道搭建
lab-21-iptables.sh 第21讲 iptables 安全规则

📊 关键命令速查表

bash 复制代码
# 网络诊断
tcpdump -i eth0 -nn port 80                     # 抓包
ss -t -i                                        # Socket 详情
nmap -sS 192.168.0.0/24                        # 端口扫描
dig +trace example.com                          # DNS 追踪
traceroute -n 8.8.8.8                          # 路由追踪

# 性能测试
iperf3 -c 192.168.0.207 -t 30                  # 带宽测试
wrk -t4 -c100 -d30s http://192.168.0.44/       # HTTP 压测
ab -n 1000 -c 100 http://192.168.0.44/         # Apache Bench

# 弱网模拟
tc qdisc add dev eth0 root netem delay 100ms loss 5%
tc qdisc del dev eth0 root

# TCP 调优
sysctl net.ipv4.tcp_congestion_control=bbr
sysctl net.core.rmem_max=16777216

# 安全
iptables -L -n -v
openssl s_client -connect example.com:443 -tls1_3

📌 文档版本 : v1.0

📌 创建日期 : 2026-06-06

📌 实验集群 : ecs-ee63 (华为云香港, 4×c6.large.2)

📌 总字数: ~12000 行, ~380KB


"网络架构不是背诵协议,而是在无数限制条件下找到最优解的艺术。"

相关推荐
真实的菜1 小时前
Redis 从入门到精通(六):集群模式(Cluster)—— 分布式架构、哈希槽与 Gossip 协议全解
redis·分布式·架构
喵了几个咪1 小时前
技术复盘:基于 GoWind Admin 实现 Kratos 框架单体轻量化落地
前端·架构
ytdbc1 小时前
bgp反射器及联邦实验
网络
liu-yonggang6 小时前
车载以太网与 SOME/IP 协议培训课程大纲
网络·网络协议·tcp/ip
洛水水9 小时前
图床项目实现:Muduo 网络框架学习以及登录注册功能实现
网络·图床·muduo
故渊at9 小时前
系列三:组件化与模块化进阶 | 第11篇 组件化项目规范与问题根治:依赖、资源、Manifest 与混淆的全链路管控
android·架构·mvvm·模块化·组件化
liulilittle10 小时前
论 Linux 内核态全局稳态带宽的卡尔曼估计与工程实现
linux·服务器·网络·c++·计算机网络·tcp·通信
pusheng202510 小时前
IFSJ全英文专访:中国创新力量重塑先进气体感知技术,赋能全球关键基础设施安全
前端·网络·人工智能·物联网·安全
Irissgwe11 小时前
五、应用层协议HTTP
linux·网络·网络协议·http·状态码·url