Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← Web 开发 / Web Development

中间件 / Middleware

1. Web 中间件全景 / The Web Middleware Landscape

2. 中间件——流量洪峰下的系统保护 / Middleware for Protecting Systems Under Traffic Spikes

cache layer

1. 缓存架构全景 / Cache Architecture Overview

2. Redis 深入——为什么你的缓存总是出问题 / Redis Internals and Cache Failure Modes

3. Redis 数据结构场景应用——什么时候用什么 / Choosing Redis Data Structures for Real Applications

4. 缓存策略——库存变了,缓存怎么处理 / Cache Strategies and Inventory Consistency

5. Redis 缓存三剑客——穿透/击穿/雪崩 + 一致性策略 / Redis Cache Penetration, Breakdown, Avalanche, and Consistency

6. Redis 分布式锁——从 SETNX 到 Redisson / Redis Distributed Locks from SETNX to Redisson

7. Redis Cluster 与 Sentinel 高可用架构 / Redis Cluster and Sentinel High-Availability Architecture

8. Redis 高级特性——Stream / PubSub / Module / LLM 应用

9. Redis 架构深度分析——为什么 Redis 能这么快 / Redis Architecture and the Sources of Its Performance

10. Redis 全景——为什么你的系统需要一个缓存层 / The Redis Landscape and Why Systems Need a Cache Layer

message queue

1. 消息队列全景——为什么你的系统需要一个中间人 / Message Queue Overview and Why Your System Needs a Middleman

2. Kafka 核心——为什么你的消息总是"丢"了 / Kafka Fundamentals and Message Delivery Semantics

3. 消息队列高级——死信队列、延迟消息、消息积压 / Advanced Messaging with Dead Letters, Delays, and Backlogs

4. Kafka Streams 与 Connect —— 让数据自己流动起来 / Kafka Streams and Connect for Streaming Data Pipelines

5. RabbitMQ 深度解析 —— 灵活路由与消息可靠性 / RabbitMQ Deep Dive into Flexible Routing and Reliability

6. 消息队列对比——为什么最终选了 Kafka / Comparing Message Queues and Choosing Kafka

search engine

1. 搜索引擎知识体系 / Search Engine Knowledge System

2. Elasticsearch——为什么 Like 查询总是那么慢 / Elasticsearch for Full-Text Search at Scale

3. Elasticsearch 查询 DSL 深入——为什么你的搜索总是不准 / Elasticsearch Query DSL Deep Dive

4. Elasticsearch 集群规划与运维——为什么你的集群总是"黄" / Elasticsearch Cluster Planning and Operations

5. Meilisearch 与轻量搜索替代方案——当 ES 太重时 / Meilisearch and Lightweight Search Alternatives

infrastructure

1. 基础设施组件全景 / Infrastructure Components Landscape

2. Nginx 与反向代理 / Nginx and Reverse Proxy

3. 服务发现 / Service Discovery

4. 配置中心 / Configuration Center

本页目录

Nginx 与反向代理 / Nginx and Reverse Proxy ​

📅 创建时间:2026-07-28 🏷️ 标签:#Nginx #ReverseProxy #LoadBalancing #SSL #HTTP2 #RateLimiting 📚 前置知识:[[00-overview]](基础设施组件全景)


📋 本章目标 ​

  • 理解 Nginx 的 Master/Worker 进程模型与事件驱动架构
  • 掌握反向代理的核心配置(proxy_pass、负载均衡算法、健康检查)
  • 能够正确配置 SSL/TLS 终止、HTTP/2、OCSP Stapling
  • 理解静态资源服务的最佳实践(缓存策略、压缩、条件请求)
  • 掌握 Nginx 限流(limit_req/limit_conn)与基础安全配置
  • 理解 Nginx 变量系统与常用脚本模式
  • 能够对比 Nginx、Caddy、Traefik 并做出合理选型

第1部分:Nginx 架构 ​

1.1 Master/Worker 进程模型 ​

┌─────────────────────────────────────────────────────────────┐
│                    Nginx 进程模型                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Master Process(PID=1,以 root 运行)              │   │
│  │  • 读取和验证配置文件                                │   │
│  │  • 创建和管理 Worker 进程                            │   │
│  │  • 处理信号(reload / reopen / stop)               │   │
│  │  • 不处理任何客户端请求                              │   │
│  └──────┬───────────────┬───────────────┬──────────────┘   │
│         │               │               │                   │
│         ▼               ▼               ▼                   │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐       │
│  │  Worker 1    │ │  Worker 2    │ │  Worker N    │       │
│  │  (非 root)   │ │  (非 root)   │ │  (非 root)   │       │
│  │              │ │              │ │              │       │
│  │  epoll/kqueue│ │  epoll/kqueue│ │  epoll/kqueue│       │
│  │  事件循环     │ │  事件循环     │ │  事件循环     │       │
│  │              │ │              │ │              │       │
│  │  处理请求     │ │  处理请求     │ │  处理请求     │       │
│  └──────────────┘ └──────────────┘ └──────────────┘       │
│                                                             │
│  关键设计决策:                                              │
│  • worker_processes auto;  ← 自动设为 CPU 核心数           │
│  • worker_connections 1024; ← 每个 Worker 最大连接数        │
│  • 最大并发 = worker_processes × worker_connections         │
│  • Worker 之间不共享内存,通过共享内存区域(shared mem)    │
│    实现限流、缓存等需要跨 Worker 协作的功能                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

1.2 事件驱动 vs 线程模型 ​

┌─────────────────────────────────────────────────────────────┐
│                    事件驱动 vs 线程模型                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Apache(线程/进程模型):                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  每个请求 → 创建一个线程/进程                         │   │
│  │  1000 并发 → 1000 个线程 → 大量上下文切换            │   │
│  │  长连接(SSE/WebSocket)→ 线程被长时间占用           │   │
│  │  内存:每个线程 ~2MB 栈空间                           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Nginx(事件驱动模型):                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  每个 Worker 是一个单线程事件循环                      │   │
│  │  1000 并发 → 1 个线程 + 1000 个事件                  │   │
│  │  通过 epoll(Linux)/ kqueue(macOS)监听事件         │   │
│  │  epoll 核心:只返回"有事件发生"的 fd                 │   │
│  │  │                                                    │   │
│  │  │  select/poll(老方案):遍历所有 fd,O(n)         │   │
│  │  │  epoll:只返回活跃 fd,O(1) per event            │   │
│  │  内存:无需为每个连接创建线程,内存占用极小           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  这也是为什么 Nginx 能做到 C10K(1 万并发),甚至         │
│  C100K(10 万并发)而 Apache 在几百并发就崩溃的原因。      │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

1.3 非阻塞 I/O 的工作方式 ​

┌─────────────────────────────────────────────────────────────┐
│                    非阻塞 I/O 流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  传统阻塞 I/O(BIO):                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  read(fd, buf)  → 内核准备数据 → 等待... 等待...    │   │
│  │                  → 数据就绪 → 复制到用户空间 → 返回  │   │
│  │  线程在"等待"期间什么都做不了(阻塞)                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Nginx 非阻塞 I/O + epoll:                                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. 把 fd 设为非阻塞模式(O_NONBLOCK)              │   │
│  │  2. 把 fd 注册到 epoll,告诉内核"就绪了叫我"       │   │
│  │  3. read(fd) → 数据未就绪 → 返回 EAGAIN(不等待)  │   │
│  │  4. Worker 继续处理其他事件                          │   │
│  │  5. 内核通知:"fd 就绪了" → Worker 再回来 read     │   │
│  │                                                     │   │
│  │  关键:一个线程处理成千上万个连接,不做无谓等待。    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Nginx 的配置体现这个思维:                                  │
│  sendfile on;        ← 零拷贝:数据从磁盘到 socket          │
│  tcp_nopush on;      ← 攒够一个包再发,减少网络包数         │
│  tcp_nodelay on;     ← 小包立即发送(对 keep-alive 重要)  │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

第2部分:反向代理配置 ​

2.1 核心指令:proxy_pass ​

┌─────────────────────────────────────────────────────────────┐
│                    反向代理配置骨架                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  http {                                                     │
│                                                             │
│    upstream backend {         ← 定义后端服务器组            │
│      server 10.0.1.1:3000 weight=3;   ← 权重 3            │
│      server 10.0.1.2:3000 weight=1;   ← 权重 1            │
│      server 10.0.1.3:3000 backup;     ← 备用,其他挂了才用│
│      keepalive 32;                   ← 到后端的连接池      │
│    }                                                        │
│                                                             │
│    server {                                                 │
│      listen 443 ssl http2;                                  │
│      server_name api.example.com;                           │
│                                                             │
│      location / {                                           │
│        proxy_pass http://backend;    ← 转发到 upstream     │
│        proxy_http_version 1.1;       ← HTTP/1.1 到后端    │
│        proxy_set_header Connection ""; ← 清理 Connection头 │
│        proxy_set_header Host $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_pass 末尾 / 的陷阱:                                  │
│  location /api/ { proxy_pass http://backend/; }             │
│    → /api/users → /users(/api 被替换)                     │
│  location /api/ { proxy_pass http://backend; }              │
│    → /api/users → /api/users(原样转发)                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

2.2 负载均衡算法 ​

┌─────────────────────────────────────────────────────────────┐
│                    负载均衡算法对比                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  │ 算法              │ 指令              │ 适合场景        │
│  ├──────────────────┼──────────────────┼────────────────┤
│  │ 轮询(默认)      │ (无需指定)      │ 后端性能一致    │
│  │ Round-Robin      │ 或 weight=N      │ 通用场景        │
│  │                  │                  │ 支持权重        │
│  ├──────────────────┼──────────────────┼────────────────┤
│  │ 最少连接          │ least_conn;     │ 请求耗时差异大  │
│  │ Least Connections│                  │ 长连接场景      │
│  ├──────────────────┼──────────────────┼────────────────┤
│  │ IP 哈希           │ ip_hash;        │ 需要会话保持    │
│  │ IP Hash          │                  │ 无状态服务慎用  │
│  ├──────────────────┼──────────────────┼────────────────┤
│  │ 通用哈希          │ hash $request_   │ 按某变量哈希    │
│  │ Generic Hash     │ uri consistent; │ 缓存友好        │
│  ├──────────────────┼──────────────────┼────────────────┤
│  │ 最短响应时间      │ least_time       │ Nginx Plus      │
│  │ Least Time       │ header;         │ (商业版)      │
│                                                             │
│  示例配置:                                                  │
│  upstream backend {                                          │
│    least_conn;                              ← 算法          │
│    server 10.0.1.1:3000 weight=5;          ← 权重          │
│    server 10.0.1.2:3000 weight=3;                           │
│    server 10.0.1.3:3000 max_fails=3         ← 健康检查      │
│                       fail_timeout=30s;     ← 故障冷却      │
│  }                                                          │
│                                                             │
│  ip_hash 的坑:如果用户走代理(NAT),所有用户 IP 都一样,  │
│  会全部打到同一台后端,负载均衡失效。                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

2.3 健康检查与故障转移 ​

┌─────────────────────────────────────────────────────────────┐
│                    被动健康检查                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  被动检查(开源版自带):                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  server 10.0.1.1:3000 max_fails=3 fail_timeout=30s;│   │
│  │  • max_fails=3: 30s 内失败 3 次 → 标记为 down       │   │
│  │  • fail_timeout=30s: 冷却 30s 后重新尝试            │   │
│  │  • 只在有真实请求时才检查(被动)                    │   │
│  │  • 缺点:故障期间所有请求仍然会被转发到挂掉的节点    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  主动检查(Nginx Plus 商业版 / 开源插件):                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  upstream backend {                                   │   │
│  │    server 10.0.1.1:3000;                             │   │
│  │    server 10.0.1.2:3000;                             │   │
│  │                                                     │   │
│  │    health_check interval=5s                          │   │
│  │                  fails=3                            │   │
│  │                  passes=2                           │   │
│  │                  uri=/health;                        │   │
│  │  }                                                   │   │
│  │  • Nginx 主动定期请求 /health 端点                   │   │
│  │  • 及时感知故障,不影响正常请求                       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  生产建议:                                                  │
│  • 健康检查端点应该轻量(不查数据库,只返回 200)             │
│  • 区分存活检查(liveness)和就绪检查(readiness)           │
│  • 后端不要因为健康检查产生副作用(幂等设计)                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

第3部分:SSL/TLS 终止 ​

3.1 概念与配置 ​

┌─────────────────────────────────────────────────────────────┐
│                    SSL/TLS 终止架构                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  无 SSL 终止(Pass-through):                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  客户端 ←── HTTPS ──→ 后端服务(需要证书)           │   │
│  │  • 每个后端都要配置 SSL 证书                         │   │
│  │  • 后端承担加解密开销                                │   │
│  │  • Nginx 在 L4 层透明转发(stream 模块)             │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  SSL 终止(Termination):                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  客户端 ←── HTTPS ──→ [Nginx 解密] ←── HTTP ──→ 后端 │   │
│  │  • 证书只在 Nginx 上配置                              │   │
│  │  • 后端只需要处理 HTTP                                │   │
│  │  • 解密/加密开销集中在 Nginx                          │   │
│  │  • 内网流量不加密(通常可接受)                       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  SSL 重加密(Re-encryption):                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  客户端 ←── HTTPS ──→ [Nginx] ←── HTTPS ──→ 后端   │   │
│  │  • 内网流量也加密(零信任架构)                       │   │
│  │  • 后端也需要配置证书(可以是内网 CA 签发的)        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

3.2 证书配置 ​

┌─────────────────────────────────────────────────────────────┐
│                    SSL 配置最佳实践                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  server {                                                   │
│    listen 443 ssl http2;       ← 同时启用 HTTP/2           │
│    server_name example.com;                                 │
│                                                             │
│    ssl_certificate     /path/to/fullchain.pem;              │
│    ssl_certificate_key /path/to/privkey.pem;                │
│                                                             │
│    ssl_protocols TLSv1.2 TLSv1.3;  ← 禁用 TLSv1.0/1.1     │
│                                                             │
│    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:              │
│               ECDHE-RSA-AES128-GCM-SHA256:                 │
│               ECDHE-ECDSA-AES256-GCM-SHA384:               │
│               ECDHE-RSA-AES256-GCM-SHA384;                 │
│                                                             │
│    ssl_prefer_server_ciphers on;  ← 优先使用服务器端密码套件│
│                                                             │
│    ssl_session_cache shared:SSL:10m; ← 10MB 可存 ~4 万会话│
│    ssl_session_timeout 10m;          ← 会话复用时间         │
│                                                             │
│    ssl_stapling on;                   ← OCSP Stapling      │
│    ssl_stapling_verify on;            ← 验证 OCSP 响应      │
│    resolver 8.8.8.8 valid=300s;       ← DNS 解析器         │
│  }                                                          │
│                                                             │
│  OCSP Stapling 的价值:                                      │
│  传统 OCSP:浏览器需要查询 CA 的 OCSP 服务器验证证书状态    │
│            → 隐私泄露 + 延迟 + CA 服务器可能挂掉            │
│  OCSP Stapling:Nginx 定期从 CA 获取 OCSP 响应并"装订"    │
│                 在 TLS 握手中发送给浏览器                    │
│                → 更快、更隐私、不依赖 CA 实时可用性         │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

3.3 HTTP/2 与 Nginx ​

┌─────────────────────────────────────────────────────────────┐
│                    HTTP/2 关键改进                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  HTTP/1.1 的问题:                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  浏览器 → 6 个并发连接(每个域名)                   │   │
│  │  每个连接 → 串行请求(Head-of-Line Blocking)        │   │
│  │  每个请求 → 独立的 TCP 连接(或 Keep-Alive 复用)    │   │
│  │  N 个资源 → 需要 N 个请求-响应往返                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  HTTP/2 的改进:                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  浏览器 → 1 个 TCP 连接(Multiplexing)             │   │
│  │  所有请求 → 在同一个连接上并行交错传输               │   │
│  │  Server Push → 服务端可主动推送资源                  │   │
│  │  HPACK → 头部压缩,减少带宽                         │   │
│  │  二进制帧 → 更高效的解析                            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Nginx HTTP/2 配置:                                         │
│  listen 443 ssl http2;                                       │
│                                                             │
│  注意事项:                                                  │
│  • HTTP/2 只在 HTTPS 下工作(浏览器不实现 h2c 明文)        │
│  • Nginx 1.25+ 开始支持 HTTP/3(QUIC)                      │
│  • Server Push 在实践中用得很少(难以预测缓存状态)          │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

第4部分:静态资源服务与缓存 ​

4.1 静态资源配置 ​

┌─────────────────────────────────────────────────────────────┐
│                    静态资源服务配置                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  location /static/ {                                        │
│    alias /var/www/static/;     ← 物理路径映射               │
│    expires 30d;                ← Cache-Control: max-age    │
│    add_header Cache-Control "public, immutable";            │
│                                                             │
│    gzip on;                    ← 启用 gzip                  │
│    gzip_comp_level 6;          ← 压缩级别 1-9              │
│    gzip_min_length 1024;       ← 小于 1KB 不压缩           │
│    gzip_types text/plain text/css application/javascript    │
│               application/json image/svg+xml;               │
│    gzip_vary on;               ← 添加 Vary: Accept-Encoding│
│                                                             │
│    brotli on;                  ← 启用 Brotli(需编译模块)  │
│    brotli_comp_level 6;        ← Brotli 比 gzip 小 ~20%    │
│    brotli_types text/plain text/css application/javascript; │
│  }                                                          │
│                                                             │
│  expires 指令的效果:                                        │
│  • expires 30d;        → max-age=2592000                    │
│  • expires -1;         → Cache-Control: no-cache            │
│  • expires epoch;      → Cache-Control: no-cache            │
│  • expires off;        → 不添加 Cache-Control               │
│                                                             │
│  缓存策略建议:                                              │
│  │ 资源类型       │ 缓存策略              │ 原因           │
│  ├───────────────┼──────────────────────┼───────────────┤
│  │ 带哈希的静态资源│ 1 年 + immutable     │ 内容变了文件名│
│  │ (app.a1b2.js) │                      │ 就变          │
│  ├───────────────┼──────────────────────┼───────────────┤
│  │ HTML 入口文件  │ no-cache             │ 需要验证更新  │
│  ├───────────────┼──────────────────────┼───────────────┤
│  │ API 响应       │ no-store(或短 TTL) │ 动态数据      │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

4.2 gzip vs Brotli 对比 ​

┌─────────────────────────────────────────────────────────────┐
│                    gzip vs Brotli                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  │ 维度          │ gzip          │ Brotli                   │
│  ├──────────────┼──────────────┼─────────────────────────┤
│  │ 压缩率        │ 中等(基线)  │ 比 gzip 小 15-25%       │
│  ├──────────────┼──────────────┼─────────────────────────┤
│  │ 压缩速度      │ 快            │ 较慢(level 11 很慢)   │
│  ├──────────────┼──────────────┼─────────────────────────┤
│  │ 解压速度      │ 快            │ 与 gzip 相当            │
│  ├──────────────┼──────────────┼─────────────────────────┤
│  │ 浏览器支持    │ 100%         │ ~97%(所有现代浏览器)   │
│  ├──────────────┼──────────────┼─────────────────────────┤
│  │ Nginx 支持    │ 内置 ngx_http│ 需编译 ngx_brotli 模块  │
│  │              │ _gzip_module │ 或使用 Nginx Plus        │
│                                                             │
│  生产建议:同时启用 gzip 和 Brotli。                          │
│  浏览器发送 Accept-Encoding: br, gzip → Nginx 优先用 Brotli │
│  不支持 Brotli 的旧浏览器 → 降级到 gzip。                    │
│                                                             │
│  静态资源预压缩(最高效方案):                              │
│  gzip_static on;     ← 请求 .js 时自动找 .js.gz            │
│  brotli_static on;   ← 请求 .js 时自动找 .js.br            │
│  构建时压缩一次,Nginx 直接返回,零 CPU 开销。              │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

第5部分:限流与安全 ​

5.1 限流配置 ​

┌─────────────────────────────────────────────────────────────┐
│                    Nginx 限流架构                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  http {                                                     │
│                                                             │
│    # 定义限流区域(共享内存,跨 Worker)                     │
│    limit_req_zone $binary_remote_addr zone=api_limit:10m    │
│                   rate=10r/s;                               │
│    limit_req_zone $server_name zone=server_limit:10m        │
│                   rate=1000r/s;                             │
│                                                             │
│    # 定义连接数限制区域                                       │
│    limit_conn_zone $binary_remote_addr zone=conn_limit:10m; │
│                                                             │
│    server {                                                  │
│      location /api/ {                                       │
│        # 请求速率限制                                        │
│        limit_req zone=api_limit burst=20 nodelay;           │
│        # burst=20: 允许 20 个请求排队                       │
│        # nodelay:  超出 rate 时立即返回 503(不排队)       │
│                                                             │
│        # 连接数限制                                          │
│        limit_conn conn_limit 10;   ← 同一 IP 最多 10 个连接│
│                                                             │
│        # 请求大小限制                                        │
│        client_max_body_size 10m;    ← 上传最大 10MB         │
│        client_body_timeout 60s;     ← 请求体超时            │
│        client_header_timeout 10s;   ← 请求头超时            │
│      }                                                      │
│    }                                                        │
│  }                                                          │
│                                                             │
│  limit_req 的 burst + nodelay 行为:                         │
│  rate=10r/s(每秒 10 个 = 100ms 一个)                       │
│  burst=20(队列最多排 20 个)                                │
│  • 无 nodelay:排队的请求慢慢处理(按 rate 速度释放)        │
│  • 有 nodelay:rate 以内的立即处理,burst 内的也立即处理    │
│              超过 burst → 503                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

5.2 IP 黑白名单与 WAF 基础 ​

┌─────────────────────────────────────────────────────────────┐
│                    IP 访问控制 + WAF                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  # IP 白名单(管理后台只允许公司 IP 访问)                   │
│  location /admin {                                           │
│    allow 10.0.0.0/8;        ← 允许内网                     │
│    allow 203.0.113.5;       ← 公司 VPN IP                  │
│    deny all;                ← 拒绝所有其他                  │
│  }                                                          │
│                                                             │
│  # IP 黑名单(封禁恶意 IP 网段)                             │
│  location / {                                                │
│    deny 192.168.1.0/24;     ← 封禁某网段                    │
│    deny 1.2.3.4;            ← 封禁单 IP                     │
│    allow all;                                                │
│  }                                                          │
│                                                             │
│  # WAF 基础规则(Nginx 层面防御)                            │
│  location / {                                                │
│    # 阻止 SQL 注入                                          │
│    if ($query_string ~* "union.*select.*(") {               │
│      return 403;                                             │
│    }                                                        │
│                                                             │
│    # 阻止路径遍历                                           │
│    if ($uri ~* "\.\./") {                                   │
│      return 403;                                             │
│    }                                                        │
│                                                             │
│    # 限制请求方法                                           │
│    if ($request_method !~ ^(GET|POST|HEAD)$) {              │
│      return 405;                                             │
│    }                                                        │
│                                                             │
│    # 隐藏 Nginx 版本号                                      │
│    server_tokens off;                                       │
│  }                                                          │
│                                                             │
│  生产环境 WAF 建议:                                         │
│  • Nginx 自带 if 规则 → 只适合简单场景                      │
│  • 中型项目 → ModSecurity + Nginx(开源 WAF)               │
│  • 云环境 → 云厂商 WAF(AWS WAF / 阿里云 WAF)              │
│  • 不要试图用 Nginx 替代专业 WAF——规则维护成本太高           │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

第6部分:Nginx 变量与脚本 ​

6.1 常用变量速查 ​

┌─────────────────────────────────────────────────────────────┐
│                    Nginx 核心变量                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  │ 变量               │ 含义              │ 示例值          │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $host             │ 请求的 Host 头    │ api.example.com │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $uri              │ 请求路径(不含参)│ /api/users      │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $request_uri      │ 原始请求 URI      │ /api/users?id=1 │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $args / $query_   │ 查询参数字符串    │ id=1&name=foo   │
│  │ string            │                  │                │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $arg_id           │ 指定参数的值      │ 1               │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $remote_addr      │ 客户端 IP         │ 203.0.113.5     │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $scheme           │ http 或 https    │ https           │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $request_method   │ GET/POST/...     │ POST            │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $server_name      │ 匹配的 server_name│ example.com    │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $http_<header>    │ 任意请求头        │ $http_user_agent│
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $status           │ 响应状态码       │ 200             │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $request_time     │ 请求处理时间(秒)│ 0.123           │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $upstream_addr    │ 上游服务器地址    │ 10.0.1.1:3000   │
│  ├───────────────────┼──────────────────┼────────────────┤
│  │ $upstream_response│ 上游响应时间      │ 0.050           │
│  │ _time             │                  │                │
│                                                             │
│  登录日志配置:                                              │
│  log_format detailed '$remote_addr - [$time_local] '       │
│                      '"$request" $status $body_bytes_sent ' │
│                      '"$http_referer" "$http_user_agent" '  │
│                      '$request_time $upstream_addr '        │
│                      '$upstream_response_time';             │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

6.2 set / map / if 脚本模式 ​

┌─────────────────────────────────────────────────────────────┐
│                    Nginx 脚本三剑客                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  set —— 设置变量:                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  set $cache_key "$host$uri";                        │   │
│  │  set $cache_valid "1";                              │   │
│  │  if ($arg_nocache) { set $cache_valid "0"; }        │   │
│  │  # set 只能在 server/location/if 中使用              │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  map —— 映射转换(最推荐的条件逻辑):                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  map $http_origin $cors_header {                    │   │
│  │    "https://example.com"  "$http_origin";           │   │
│  │    "https://app.example.com" "$http_origin";        │   │
│  │    default                "";                       │   │
│  │  }                                                   │   │
│  │  # map 在 http 块定义,只在使用时才求值(惰性)      │   │
│  │  # 比 if 更高效、更可预测                            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  if —— 条件判断(谨慎使用):                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  if ($http_user_agent ~* "bot") {                   │   │
│  │    return 403;                                      │   │
│  │  }                                                   │   │
│  │  # if 是"邪恶"的(Igor Sysoev 原话)               │   │
│  │  # 原因:if 在 location 中的行为是"重写"而非"分支"  │   │
│  │  # 多个 if 可能导致意外行为                          │   │
│  │  # 优先使用 map + try_files                         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  推荐优先级:map > try_files > return/rewrite > if           │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

第7部分:Nginx vs Caddy vs Traefik ​

7.1 三方对比 ​

┌─────────────────────────────────────────────────────────────┐
│                    Nginx vs Caddy vs Traefik                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  │ 维度          │ Nginx        │ Caddy        │ Traefik    │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 语言          │ C            │ Go           │ Go         │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 配置方式      │ nginx.conf  │ Caddyfile    │ 标签+文件  │
│  │              │ (静态文件)   │ (简洁 DSL)  │ (K8s CRD)  │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 自动 HTTPS    │ ❌ 需手动    │ ✅ 零配置    │ ✅ 自动    │
│  │              │ certbot     │ Let's Encrypt│ Let's Encrypt│
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 动态配置      │ ❌ reload   │ ✅ API       │ ✅ 原生    │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 性能          │ ⭐⭐⭐⭐⭐   │ ⭐⭐⭐⭐     │ ⭐⭐⭐⭐  │
│  │              │ C 语言级别  │ Go 接近 C   │ Go         │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 内存占用      │ 极低 (~5MB) │ 低 (~30MB)  │ 中等       │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ Docker 友好    │ 中等         │ 高           │ 极高       │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ K8s 原生      │ ❌ 需 Ingress│ ❌           │ ✅ CRD/    │
│  │              │ Controller │             │ IngressRoute│
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 插件生态      │ 编译时模块  │ 编译时模块  │ 中间件插件 │
│  ├──────────────┼─────────────┼─────────────┼──────────┤
│  │ 适用场景      │ 高性能/稳定 │ 个人/中小   │ 容器/微服务│
│  │              │ 大型生产    │ 项目        │ K8s 环境   │
│                                                             │
│  选型建议:                                                  │
│  • 高流量/低延迟/极致性能 → Nginx                           │
│  • 个人项目/简单配置/快速上手 → Caddy                        │
│  • K8s 环境/动态配置/服务发现集成 → Traefik                 │
│  • 非 K8s 的微服务/API 管理 → Kong(基于 Nginx)            │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

核心总结 ​

总结1:Nginx 的性能来源于架构 ​

Master/Worker + epoll + 非阻塞 I/O + 零拷贝(sendfile)。不是"C 语言快",而是事件驱动模型让一个 Worker 能处理成千上万个并发连接而不阻塞。

总结2:反向代理的核心配置是 upstream + proxy_pass + proxy_set_header ​

负载均衡算法选型、健康检查配置、请求头透传——这三个做好,反向代理就完成了 80% 的工作。

总结3:SSL 终止是生产环境的标配 ​

不要在应用层处理 HTTPS。把证书放在 Nginx 上,后端用 HTTP,既简化证书管理,又提高应用性能。记得开 OCSP Stapling。

总结4:限流是防止系统崩溃的最后一道防线 ​

limit_req(速率)和 limit_conn(连接数)是你的安全网。配置时要根据业务吞吐量定基线,留出足够的 burst 余量。

总结5:map 优于 if ​

Nginx 不是编程语言。尽量用 map 做条件映射,用 return 做快速响应,减少 if 的使用。if 在 location 中的行为不符合直觉。


章节测试 ​

测试1:Nginx Master 进程的主要职责是什么? ​

测试2:以下负载均衡算法中,哪个最适合请求处理时间差异大的场景? ​

A. round-robin B. ip_hash C. least_conn D. random

测试3:SSL 终止(Termination)和 SSL 透传(Pass-through)的核心区别是什么? ​

测试4:Nginx 中 limit_req 的 burst 参数是什么意思? ​

测试5:为什么说 Nginx 的 map 指令比 if 指令更好? ​

测试6:对于 K8s 环境中的微服务网关,Nginx / Caddy / Traefik 如何选型? ​


参考答案 ​

测试1答案 ​

Nginx Master 进程的职责:

  1. 读取和验证 nginx.conf 配置文件
  2. 创建和管理 Worker 进程(fork 出多个 Worker)
  3. 处理信号:nginx -s reload(平滑重启)、nginx -s stop、nginx -s reopen(重新打开日志文件)
  4. 不处理任何客户端请求——所有请求由 Worker 处理

测试2答案 ​

答案:C(least_conn)。least_conn 将请求转发给当前活跃连接数最少的后端服务器。当请求处理时间差异大时(如有些请求 10ms,有些 5s),轮询会导致某些服务器堆积长请求,而 least_conn 能自然地实现负载均衡。

测试3答案 ​

SSL 终止:Nginx 在代理层解密 HTTPS,后端服务之间用 HTTP 通信。证书只在 Nginx 上配置,后端无需处理 TLS,内网流量明文传输。

SSL 透传:Nginx 在 L4 层(TCP)原样转发加密流量,不解密。每个后端需要配置自己的 TLS 证书。Nginx 无法检查 HTTP 内容(无法做路由、限流等 L7 操作)。

测试4答案 ​

burst 是队列大小。当请求速率超过 rate 限制时,多余的请求不会立即被拒绝,而是排队等待。burst=20 表示最多允许 20 个请求排队。如果同时有 nodelay,队列中的请求也会立即处理(不等待),但当队列满时新请求返回 503。

测试5答案 ​

  1. 声明性:map 是声明式映射,逻辑清晰,不易出错
  2. 惰性求值:map 只在使用变量时才求值,性能更好
  3. 可预测:if 在 location 中的行为是"重写"语义而非"分支"语义,多个 if 可能产生意外结果
  4. 作用域:map 在 http 块定义,全局可用,不受 location 上下文影响

测试6答案 ​

  • 一定要 Nginx:对性能/稳定性有极致要求(C10K 以上),团队对 Nginx 配置已经很熟悉
  • 选 Caddy:简单项目,想要自动 HTTPS + 低维护成本
  • 选 Traefik:K8s 环境,需要与服务发现(K8s Service/Ingress)原生集成,希望通过 CRD 声明式管理路由(IngressRoute)

相关笔记 ​

  • [[00-overview]] — 基础设施组件全景
  • [[02-service-discovery]] — 服务发现(Consul/Nacos/DNS)
  • [[03-configuration-center]] — 配置中心(Nacos/Apollo/Vault)
  • [[../00-overview]] — 中间件全景总览

下一步学习 ​

  • [ ] 阅读 02 - 服务发现 — 理解服务发现的三种模式
  • [ ] 在你的开发环境搭建一个 Nginx 反向代理,配置 SSL 和负载均衡
  • [ ] 用 ab 或 wrk 压测你的 Nginx 配置,观察性能表现
  • [ ] 尝试用 Caddy 替代 Nginx 跑一个简单项目,感受配置差异

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇1. 基础设施组件全景 / Infrastructure Components Landscape
下一篇3. 服务发现 / Service Discovery

持续记录,持续成长

Copyright © Tidenflow