跳转至

第 5 章:Nginx 原理与配置

Nginx 是全球使用最广泛的 Web 服务器和反向代理。理解 Nginx 是生产环境部署的必备技能。


5.1 Nginx 是什么?

Nginx(发音 "engine-x")是由 Igor Sysoev 于 2004 年创建的 高性能 HTTP 服务器和反向代理服务器

全球使用率

1
2
3
4
5
6
7
8
9
┌─────────────────────────────────────────────┐
│              全球 Web 服务器市场份额           │
│                                              │
│  Nginx     ████████████████████████████  34% │
│  Apache    ████████████████            20%   │
│  Cloudflare ██████████████              14%  │
│  Caddy     ████                          4%  │
│  其他      ████████████████████        28%   │
└─────────────────────────────────────────────┘

Nginx 能做什么?

功能 说明
反向代理 接收客户端请求,转发给后端服务器
负载均衡 将请求分发到多个后端实例
静态文件服务 高效提供 HTML/CSS/JS/图片
SSL/TLS 终止 处理 HTTPS 加密/解密
缓存 缓存后端响应,减轻后端压力
限流 控制请求频率,防止滥用
WebSocket 代理 WebSocket 连接
gRPC 代理 代理 gRPC 服务

5.2 为什么需要 Nginx?

问题:直接暴露应用服务器

1
2
3
4
5
6
7
8
9
客户端 ──────────────────→ Express/FastAPI
                              │ 问题:
                              │ ❌ 无法处理 HTTPS
                              │ ❌ 无法负载均衡
                              │ ❌ 静态文件效率低
                              │ ❌ 无法限流
                              │ ❌ 单点故障
                              │ ❌ 无法缓存

方案:Nginx 作为前置层

客户端 ──→ Nginx ──→ Express 实例 1
                      ├─→ Express 实例 2
                      ├─→ Express 实例 3
                      └─→ FastAPI 实例

✅ HTTPS 在 Nginx 配置
✅ 负载均衡自动分发
✅ 静态文件 Nginx 直接返回
✅ 限流/防火墙在 Nginx 层
✅ 多实例高可用
✅ 响应缓存

5.3 Nginx 架构与事件模型

进程模型

┌──────────────────────────────────────────────┐
│                Nginx  Master 进程              │
│          (管理 Worker 进程,加载配置)          │
│                                              │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │ Worker 1 │ │ Worker 2 │ │ Worker N │     │
│  │ (事件驱动)│ │ (事件驱动)│ │ (事件驱动)│     │
│  └──────────┘ └──────────┘ └──────────┘     │
│       │            │            │            │
│       └────────────┴────────────┘            │
│              共享端口(accept_mutex)          │
└──────────────────────────────────────────────┘
  • Master 进程:读取配置、管理 Worker 进程、平滑重启
  • Worker 进程:实际处理请求,数量通常等于 CPU 核心数

事件驱动 vs 多线程

1
2
3
4
5
Apache(多线程/多进程):
  10000 个并发连接 → 10000 个线程 → 💥 内存耗尽

Nginx(事件驱动):
  10000 个并发连接 → 4 个 Worker 进程 → ✅ 每个 Worker 用 epoll 处理 2500 个连接

epoll/kqueue 原理

Linux 使用 epoll,macOS/BSD 使用 kqueue

传统方式(select/poll):
  for each connection:
      check if has data    ← 每次都要遍历所有连接
  时间复杂度:O(n)

epoll 方式:
  操作系统主动通知哪些连接有数据    ← 只处理有数据的连接
  时间复杂度:O(1)

5.4 配置文件结构

配置文件位置

1
2
3
4
5
6
7
8
# 主配置文件
/etc/nginx/nginx.conf

# 站点配置
/etc/nginx/conf.d/*.conf
# 或
/etc/nginx/sites-available/
/etc/nginx/sites-enabled/

配置层次

# nginx.conf 结构
worker_processes auto;    # 全局配置

events {                  # 事件配置
    worker_connections 1024;
}

http {                    # HTTP 配置
    include mime.types;
    default_type application/octet-stream;

    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

    access_log /var/log/nginx/access.log main;

    # 性能优化
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    gzip on;

    # 上游服务器(负载均衡)
    upstream backend {
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
        server 127.0.0.1:3002;
    }

    # 虚拟主机(Server Block)
    server {
        listen 80;
        server_name example.com;

        # 路由(Location Block)
        location / {
            root /var/www/html;
            index index.html;
        }

        location /api/ {
            proxy_pass http://backend;
        }
    }
}

5.5 反向代理配置

基本反向代理

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

    location / {
        proxy_pass http://127.0.0.1:3000;

        # 传递原始请求信息
        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 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

多应用路由

server {
    listen 80;
    server_name example.com;

    # Express 应用
    location /api/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # FastAPI 应用
    location /ai/ {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 静态网站
    location / {
        root /var/www/frontend;
        index index.html;
        try_files $uri $uri/ /index.html;  # SPA 支持
    }
}

WebSocket 代理

1
2
3
4
5
6
7
location /ws/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

5.6 负载均衡

负载均衡策略

# 1. 轮询(Round Robin,默认)
upstream backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

# 2. 加权轮询
upstream backend {
    server 127.0.0.1:3000 weight=3;  # 接收 3/6 的请求
    server 127.0.0.1:3001 weight=2;  # 接收 2/6 的请求
    server 127.0.0.1:3002 weight=1;  # 接收 1/6 的请求
}

# 3. IP Hash(同一 IP 始终到同一后端)
upstream backend {
    ip_hash;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

# 4. 最少连接
upstream backend {
    least_conn;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

健康检查

1
2
3
4
5
upstream backend {
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3002 backup;  # 备用服务器,其他都挂了才用
}

5.7 SSL/TLS 配置

HTTPS 配置

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL 优化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

Let's Encrypt 免费证书

1
2
3
4
5
6
7
8
# 安装 certbot
sudo apt install certbot python3-certbot-nginx

# 自动获取并配置证书
sudo certbot --nginx -d example.com

# 自动续期(certbot 会添加 cron)
sudo certbot renew --dry-run

5.8 静态文件优化

基本静态文件服务

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

    root /var/www/static;

    # HTML/JS/CSS 缓存 1 年
    location ~* \.(html|css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 图片缓存 1 年
    location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 字体缓存 1 年
    location ~* \.(woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 其他文件不缓存
    location / {
        add_header Cache-Control "no-cache";
    }
}

Gzip 压缩

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;  # 压缩级别 1-9,6 是性价比最好的
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/json
    application/javascript
    application/xml
    application/rss+xml
    image/svg+xml;

压缩效果示例:

1
2
3
原始 JS 文件:500KB
Gzip 压缩后:150KB    ← 节省 70% 带宽
压缩耗时:< 1ms       ← CPU 开销极小

5.9 限流配置

基本限流

# 定义限流区域
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
# 10m 内存,每秒 10 个请求 per IP

server {
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        # burst=20:允许突发 20 个请求
        # nodelay:突发请求不延迟,直接处理

        proxy_pass http://backend;
    }
}

多级限流

# 全局限流
limit_req_zone $binary_remote_addr zone=global:10m rate=100r/s;

# API 限流(更严格)
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# 登录限流(最严格)
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

server {
    location / {
        limit_req zone=global burst=50 nodelay;
    }

    location /api/ {
        limit_req zone=api burst=20;
        proxy_pass http://backend;
    }

    location /api/auth/login {
        limit_req zone=login burst=3 nodelay;
        proxy_pass http://backend;
    }
}

5.10 缓存配置

反向代理缓存

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m
                 max_size=1g inactive=60m use_temp_path=off;

server {
    location /api/products {
        proxy_cache api_cache;
        proxy_cache_valid 200 10m;     # 200 响应缓存 10 分钟
        proxy_cache_valid 404 1m;      # 404 响应缓存 1 分钟
        proxy_cache_use_stale error timeout updating;

        # 添加缓存命中头
        add_header X-Cache-Status $upstream_cache_status;

        proxy_pass http://backend;
    }
}

响应头:

1
2
3
X-Cache-Status: HIT    ← 缓存命中
X-Cache-Status: MISS   ← 缓存未命中
X-Cache-Status: EXPIRED ← 缓存过期


5.11 安全配置

安全头

1
2
3
4
5
6
7
8
9
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# 隐藏版本号
server_tokens off;

IP 黑白名单

# 白名单
location /admin/ {
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;
    proxy_pass http://backend;
}

# 黑名单
location / {
    deny 192.168.1.100;
    proxy_pass http://backend;
}

5.12 性能调优

nginx.conf 优化

worker_processes auto;          # 等于 CPU 核心数
worker_rlimit_nofile 65535;     # 文件描述符限制

events {
    worker_connections 4096;    # 每个 Worker 的最大连接数
    multi_accept on;            # 一次性接受多个连接
    use epoll;                  # Linux 使用 epoll
}

http {
    sendfile on;                # 零拷贝传输
    tcp_nopush on;              # 与 sendfile 配合
    tcp_nodelay on;             # 禁用 Nagle 算法
    keepalive_timeout 65;
    keepalive_requests 1000;    # 单个连接最多处理 1000 个请求

    client_max_body_size 50m;   # 最大请求体
    client_body_buffer_size 128k;

    # 缓冲区优化
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
    proxy_busy_buffers_size 256k;

    include /etc/nginx/conf.d/*.conf;
}

理论并发连接数:

worker_processes × worker_connections = 4 × 4096 = 16384


5.13 日志分析

访问日志格式

1
2
3
4
5
log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';

常用分析命令

# 统计每个 IP 的请求数
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 统计状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# 找出最慢的请求(> 5s)
awk '$NF > 5' /var/log/nginx/access.log

# 统计 API 调用次数
grep '/api/' /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

5.14 常用命令

# 测试配置
nginx -t

# 重新加载配置(不中断服务)
nginx -s reload

# 重启
systemctl restart nginx

# 查看状态
systemctl status nginx

# 查看错误日志
tail -f /var/log/nginx/error.log

# 日志轮转
logrotate -f /etc/logrotate.d/nginx

5.15 总结

核心概念 一句话
事件驱动 epoll/kqueue 实现高并发,不依赖多线程
Master-Worker Master 管理配置,Worker 处理请求
反向代理 接收请求并转发,隐藏后端服务器
负载均衡 轮询/加权/IP Hash/最少连接
SSL 终止 HTTPS 在 Nginx 层处理,后端用 HTTP
缓存 减少后端压力,提升响应速度
限流 防止 API 滥用和 DDoS 攻击

Nginx 是生产环境的标配。 无论是个人项目还是大厂,Nginx 都是第一道防线。


上一章:FastAPI 框架 | 下一章:完整架构实战