Lesson 0013:网络实战——负载均衡、CDN 和真实排错

← Lesson 0012 讲了协议原理。这一课把理论落到 Nginx 配置和真实场景。

1. Nginx 反向代理进阶

Lesson 0007 讲了基础反代。现在上生产级配置:

# /etc/nginx/sites-available/myapp —— 生产级配置
upstream app_backend {
    least_conn;                        # 最少连接数算法(默认是轮询)
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;  # 3次失败后摘除30秒
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
    server 10.0.0.5:3000 backup;       # 备用服务器,只在其他都挂了才用
    keepalive 32;                       # 保持 32 个到后端的空闲连接
}

server {
    listen 80;
    server_name example.com;

    # 限流:每个 IP 每秒最多 10 个请求
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
    limit_req zone=mylimit burst=20 nodelay;

    # 限并发:每个 IP 最多 5 个并发连接
    limit_conn_zone $binary_remote_addr zone=connlimit:10m;
    limit_conn connlimit 5;

    # 静态文件直接返回(不转发到后端)
    location /static/ {
        alias /var/www/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # API 请求转发到后端
    location /api/ {
        proxy_pass http://app_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 超时配置
        proxy_connect_timeout 5s;       # 连后端超时
        proxy_read_timeout 30s;         # 读后端响应超时
        proxy_send_timeout 10s;         # 发请求给后端超时
    }

    # 健康检查端点(不记日志)
    location /health {
        access_log off;
        return 200 "OK";
    }
}

2. 负载均衡算法

算法Nginx 指令适用场景
轮询(默认)后端服务器性能相同
加权轮询server ... weight=3;服务器性能不同
最少连接least_conn;请求处理时间不均匀
IP Haship_hash;需要会话保持(同一 IP 总到同一台)

3. 负载均衡的层次

DNS 层    Route53 / Cloudflare → 把域名解析到不同 IP(最简单,但切换慢)
L4 (TCP)  Nginx stream / HAProxy → 只看 IP+端口,不看内容。性能最高
L7 (HTTP) Nginx http / Traefik → 看 URL、Header、Cookie 做路由。最灵活

4. CDN 原理

CDN = 把静态文件缓存在离用户最近的边缘节点。

用户在北京 → 北京边缘节点(有缓存)→ 直接返回 ✈️ 快
用户在北京 → 北京边缘节点(无缓存)→ 回源到你的服务器 → 缓存后返回

关键配置:

5. 真实排错场景

场景 A:「用户说网站很慢」

# 1. 从用户侧开始
curl -w "DNS:%{time_namelookup}s TCP:%{time_connect}s TLS:%{time_appconnect}s FirstByte:%{time_starttransfer}s Total:%{time_total}s\n" -o /dev/null -s https://example.com

# 2. 看服务器负载
ssh server "uptime; free -h; iostat -x 1 3"

# 3. 看 Nginx 访问日志——找慢请求
awk '$NF > 3 {print $0}' /var/log/nginx/access.log  # 响应时间 > 3 秒的

# 4. 看数据库慢查询(如果有的话)
# MySQL: SHOW FULL PROCESSLIST; 或 slow query log

场景 B:「间歇性 502」

# 1. 确认后端是否活着
ss -tlnp | grep 3000
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/health

# 2. 看 Nginx 错误日志
tail -100 /var/log/nginx/error.log | grep "upstream"

# 3. 检查是不是连接数爆了
ss -s    # 看总连接数
# 如果大量 TIME_WAIT → 调内核参数或启用 keepalive

# 4. 检查文件描述符限制
cat /proc/$(pgrep nginx | head -1)/limits | grep "open files"

场景 C:「端口不通」

# 从外到内排查
ping -c 3 server-ip           # 1. 机器活着吗?
nc -zv server-ip 80           # 2. 端口开着吗?
# 如果是云服务器:
# 3. 检查安全组/防火墙是否放行 80
# 4. 检查服务是否绑在 0.0.0.0 而不是 127.0.0.1
sudo ss -tlnp | grep :80     # 0.0.0.0:80 = 对外监听,127.0.0.1:80 = 只本地

动手练习

用 Docker 搭两个后端 + Nginx 负载均衡:

mkdir /tmp/lb-demo && cd /tmp/lb-demo

# docker-compose.yml: Nginx + 2 个 Node.js 后端
cat > docker-compose.yml << 'EOF'
services:
  nginx:
    image: nginx:alpine
    ports: ["8080:80"]
    volumes: ["./nginx.conf:/etc/nginx/conf.d/default.conf"]
  backend1:
    image: node:22-alpine
    command: node -e "require('http').createServer((q,r)=>{r.end('Server 1\\n')}).listen(3000)"
  backend2:
    image: node:22-alpine
    command: node -e "require('http').createServer((q,r)=>{r.end('Server 2\\n')}).listen(3000)"
EOF

cat > nginx.conf << 'EOF'
upstream backends { server backend1:3000; server backend2:3000; }
server {
    listen 80;
    location / { proxy_pass http://backends; }
}
EOF

docker compose up -d
# 多次 curl,看到轮询返回 Server 1 和 Server 2
for i in 1 2 3 4; do curl -s http://localhost:8080; done

docker compose down

小测验

Q1:L4 和 L7 负载均衡的区别?
Q2:CDN 缓存雪崩是什么?
Q3:端口测试中 ss -tlnp 显示 127.0.0.1:3000 意味着什么?

下一步

Lesson 0014:Kubernetes 核心概念 →——Pod、Deployment、Service、Namespace。容器编排的真正入口。

← Lesson 0012 · Lesson 0014 → · 术语表