Appearance
Nginx 详解:高性能反向代理与负载均衡
Nginx 是业界最主流的高性能 HTTP 服务器、反向代理和负载均衡器。在微服务架构中,Nginx 通常作为统一入口网关,负责流量分发、SSL 卸载、静态资源加速和请求限流。
一、为什么需要 Nginx?
1.1 Nginx 解决了什么问题?
在微服务架构中,前端需要调用多个后端服务,直接暴露每个服务会产生一系列问题:
没有 Nginx 时:
浏览器 → order-service:8080/api/orders
浏览器 → inventory-service:8081/api/inventory
浏览器 → user-service:8082/api/users
问题:跨域、多端口暴露、SSL 证书多份、无统一限流
有了 Nginx 后:
浏览器 → Nginx:443/api/orders → order-service:8080
浏览器 → Nginx:443/api/inventory → inventory-service:8081
浏览器 → Nginx:443/api/users → user-service:8082
好处:统一入口、统一 SSL、跨域解决、统一限流、静态资源缓存1.2 Nginx 的核心能力
| 能力 | 说明 | 典型场景 |
|---|---|---|
| 反向代理 | 客户端请求 → Nginx → 后端服务,隐藏后端真实 IP | 统一入口,屏蔽后端结构 |
| 负载均衡 | 将请求分发到多个后端实例 | 水平扩展,高可用 |
| 静态资源服务 | 直接返回 HTML/CSS/JS/图片,不经过后端 | 前后端分离,降低后端压力 |
| SSL/TLS 终止 | 在 Nginx 层处理 HTTPS,后端用 HTTP | 简化证书管理 |
| 缓存 | 缓存后端响应,减少重复请求 | 加速读取,降低后端压力 |
| 限流 | 控制请求频率,防止恶意攻击 | 防刷、防 DDoS |
| 动静分离 | 静态资源由 Nginx 直接返回,动态请求转发后端 | 性能优化 |
| WebSocket 代理 | 支持 WebSocket 协议的长连接代理 | 实时推送 |
二、核心架构
2.1 Master-Worker 进程模型
┌──────────┐
│ Master │ ← 读取配置、管理 Worker
└────┬─────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Worker 1 │ │ Worker 2 │ │ Worker 3 │ ← 每个 Worker 处理请求
└──────────┘ └──────────┘ └──────────┘
│ │ │
└──────────────┴──────────────┘
│
accept_mutex 锁
│
┌──────────────────────┐
│ epoll / kqueue / IOCP │ ← 事件驱动,一个 Worker 处理数万连接
└──────────────────────┘- Master 进程:读取和验证配置,创建/绑定 socket,管理 Worker 生命周期
- Worker 进程:处理实际请求,每个 Worker 是单线程、事件驱动的,通过
epoll(Linux)/kqueue(macOS)/IOCP(Windows)同时处理数万并发连接
2.2 为什么 Nginx 这么快?
- 事件驱动:一个 Worker 线程处理所有请求,不阻塞等待,通过 I/O 多路复用(epoll)高效管理连接
- 非阻塞 I/O:读不到数据立即返回,不会让线程傻等,CPU 利用率极高
- 多进程 + 单线程:每个 Worker 单线程,无锁竞争,上下文切换开销极低
- 内存池:预分配内存池,减少频繁
malloc/free
2.3 Nginx vs Apache
| 维度 | Nginx | Apache |
|---|---|---|
| 并发模型 | 事件驱动(epoll) | 进程/线程 per 连接 |
| 并发连接数 | 数万(内存占用低) | 数千(内存占用高) |
| 静态资源 | 极快,自带缓存 | 较快 |
| 动态内容 | 反向代理到后端 | 通过模块处理(mod_php) |
| 配置 | 简洁,声明式 | 丰富,.htaccess 灵活 |
| 适用场景 | 反向代理、负载均衡、高并发 | 共享主机、动态内容 |
三、反向代理
3.1 什么是反向代理?
正向代理(代理客户端):
客户端 → [代理服务器] → 互联网
作用:翻墙、隐藏客户端 IP
反向代理(代理服务端):
客户端 → [Nginx 反向代理] → 后端服务集群
作用:隐藏服务端结构、负载均衡、SSL 卸载3.2 基本配置
nginx
# /etc/nginx/conf.d/api.conf
server {
listen 80;
server_name api.example.com;
# 反向代理到后端服务
location /api/orders {
proxy_pass http://localhost:8080;
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;
}
location /api/inventory {
proxy_pass http://localhost:8081;
}
}proxy_set_header 关键说明:
| Header | 含义 | 后端拿到的值 |
|---|---|---|
| X-Real-IP | 客户端的真实 IP | $remote_addr |
| X-Forwarded-For | 经过的代理链 | 客户端IP, 代理1, 代理2 |
| X-Forwarded-Proto | 原始请求协议 | http 或 https |
| Host | 原始请求的 Host | api.example.com |
3.3 proxy_pass 规则
nginx
# 规则1:带 URI 路径 → 替换匹配部分
location /api/ {
proxy_pass http://backend/; # /api/orders → http://backend/orders(/api 被替换成 /)
}
# 规则2:不带 URI 路径 → 原样拼接
location /api/ {
proxy_pass http://backend; # /api/orders → http://backend/api/orders(原样)
}
# 规则3:精确匹配
location = /health {
proxy_pass http://backend;
}四、负载均衡
4.1 upstream 模块
Nginx 的 upstream 模块定义一组后端服务器,配合 proxy_pass 实现负载均衡:
nginx
upstream order-backend {
server 192.168.1.101:8080 weight=5;
server 192.168.1.102:8080 weight=3;
server 192.168.1.103:8080 weight=2 backup; # 备用节点
}
server {
listen 80;
location /api/orders {
proxy_pass http://order-backend;
proxy_connect_timeout 3s; # 连接超时
proxy_read_timeout 10s; # 读取超时
proxy_send_timeout 10s; # 发送超时
}
}4.2 6 种负载均衡策略
4.2.1 轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器。如果某台服务器宕机,自动剔除。
nginx
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}4.2.2 加权轮询(weight)
权重越高分配到的请求越多。适合后端服务器性能不一致的场景。
nginx
upstream backend {
server 192.168.1.101:8080 weight=5; # 高性能机器
server 192.168.1.102:8080 weight=3;
server 192.168.1.103:8080 weight=2; # 低配机器
}4.2.3 IP Hash(ip_hash)
根据客户端 IP 的 Hash 值分配,同一客户端的请求始终落到同一台服务器。解决 Session 共享问题,但后端服务器宕机时会重新分配。
nginx
upstream backend {
ip_hash;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}注意: ip_hash 与 weight 互斥,不能同时使用。如果需要加权 + 会话保持,建议用 Redis 集中管理 Session。
4.2.4 最少连接数(least_conn)
优先分配给当前活跃连接数最少的服务器。适合请求处理时间差异较大的场景。
nginx
upstream backend {
least_conn;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}4.2.5 URL Hash(hash $request_uri)
按请求 URL 的 Hash 分配,同一个 URL 始终落到同一台服务器。适合后端有本地缓存的场景,提高缓存命中率。
nginx
upstream backend {
hash $request_uri;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}4.2.6 一致性 Hash(hash $remote_addr consistent)
基于一致性 Hash 环分配,当服务器增减时,只有少部分请求被重新分配。适合缓存场景,减少缓存失效。
nginx
upstream backend {
hash $remote_addr consistent;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}一致性 Hash 原理:
普通 Hash:增减服务器 → 所有请求重新分配 → 缓存全部失效
一致性 Hash:增减服务器 → 只有相邻节点的请求被重新分配 → 大部分缓存保留4.3 后端状态标记
nginx
upstream backend {
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s; # 30s 内失败 3 次则标记为 down
server 192.168.1.102:8080 down; # 手动下线
server 192.168.1.103:8080 backup; # 备用节点,所有正常节点挂掉后才启用
}| 参数 | 说明 |
|---|---|
max_fails=N | 最大失败次数 |
fail_timeout=N | 失败超时时间,超时后重新尝试 |
down | 手动标记为不可用 |
backup | 备用节点,只在其他节点都不可用时才启用 |
五、SSL/TLS 配置
nginx
server {
listen 443 ssl http2;
server_name api.example.com;
# 证书配置
ssl_certificate /etc/nginx/ssl/fullchain.pem; # 公钥证书
ssl_certificate_key /etc/nginx/ssl/privkey.pem; # 私钥
ssl_session_cache shared:SSL:10m; # 会话缓存 10MB
ssl_session_timeout 10m; # 会话超时
# 安全协议与加密套件
ssl_protocols TLSv1.2 TLSv1.3; # 只允许 TLS 1.2+
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on; # 优先使用服务端加密套件
# 后端用 HTTP,SSL 在 Nginx 层终结
location /api/ {
proxy_pass http://backend;
}
}
# HTTP 自动跳转 HTTPS
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}六、Gzip 压缩
nginx
http {
gzip on;
gzip_min_length 1024; # 小于 1KB 不压缩,不划算
gzip_comp_level 5; # 压缩级别 1-9,5 是性价比最优
gzip_types text/plain
text/css
text/javascript
application/json
application/javascript
application/xml
image/svg+xml;
gzip_vary on; # 添加 Vary: Accept-Encoding 响应头
gzip_disable "msie6"; # 禁用 IE6 压缩
}gzip_comp_level 选择:
| 级别 | CPU 消耗 | 压缩率 | 推荐 |
|---|---|---|---|
| 1-3 | 低 | 低 | 不推荐 |
| 4-6 | 中 | 中 | 推荐 5 |
| 7-9 | 高 | 高 | 浪费 CPU |
七、缓存配置
7.1 静态资源缓存
nginx
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 30d; # 浏览器缓存 30 天
add_header Cache-Control "public, immutable";
access_log off; # 不记录日志
}7.2 代理缓存
nginx
http {
# 定义缓存路径:目录、层级、缓存大小、非活跃清理时间
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m
max_size=1g inactive=60m use_temp_path=off;
server {
location /api/ {
proxy_cache my_cache;
proxy_cache_key "$host$request_uri$request_body"; # 缓存键
proxy_cache_valid 200 1m; # 200 响应缓存 1 分钟
proxy_cache_valid 404 10s; # 404 缓存 10 秒
proxy_cache_bypass $http_pragma; # 跳过缓存的条件
proxy_cache_revalidate on; # 过期时重新验证
add_header X-Cache-Status $upstream_cache_status; # 调试用
proxy_pass http://backend;
}
}
}$upstream_cache_status 值含义:
| 值 | 含义 |
|---|---|
| MISS | 未命中缓存,从后端获取 |
| HIT | 命中缓存 |
| EXPIRED | 缓存过期,重新验证 |
| STALE | 后端异常,返回过期缓存 |
| BYPASS | 跳过缓存 |
八、限流
8.1 请求频率限制(控制 QPS)
nginx
http {
# 定义限流区域:10MB 存储约 16 万个 IP 的状态
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=req_limit burst=20 nodelay;
# burst=20:允许 20 个突发请求排队
# nodelay:排队中的请求立即处理,不延迟
proxy_pass http://backend;
}
}
}参数解释:
| 参数 | 含义 |
|---|---|
rate=10r/s | 每秒允许 10 个请求(平均 100ms 一个) |
burst=20 | 突发队列长度,超过 rate 的请求排队等待 |
nodelay | 突发请求立即处理,不按 rate 均匀延迟 |
delay=10 | 突发队列中前 10 个立即处理,其余延迟(替代 nodelay 的精细控制) |
8.2 并发连接数限制
nginx
http {
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
limit_conn conn_limit 5; # 每个 IP 最大 5 个并发连接
limit_conn_status 429; # 超限返回 429 Too Many Requests
proxy_pass http://backend;
}
}
}8.3 下载速度限制
nginx
location /downloads/ {
limit_rate 500k; # 限制每个连接的速度为 500KB/s
limit_rate_after 10m; # 下载 10MB 后才开始限速
}九、动静分离
nginx
server {
listen 80;
server_name www.example.com;
# 静态资源:Nginx 直接返回
location / {
root /var/www/html; # 前端静态文件目录
index index.html;
try_files $uri $uri/ /index.html; # SPA 模式,找不到文件返回 index.html
}
# 动态请求:反向代理到后端
location /api/ {
proxy_pass http://backend;
}
}十、WebSocket 代理
nginx
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1; # WebSocket 需要 HTTP/1.1
proxy_set_header Upgrade $http_upgrade; # 升级协议
proxy_set_header Connection "upgrade"; # 保持连接
proxy_read_timeout 3600s; # 长连接超时
proxy_send_timeout 3600s;
}十一、Nginx 在微服务架构中的位置
┌─────────────────────────┐
│ Nginx(服务端负载均衡) │ ← 统一入口、SSL、限流、静态资源
└──────────┬──────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Gateway │ │ Gateway │ │ Gateway │ ← 微服务网关
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└───────────────┼───────────────┘
│
▼
┌──────────────────────────┐
│ Ribbon / LoadBalancer │ ← 客户端负载均衡
│ (服务间调用) │
└──────────────────────────┘Nginx 和 Ribbon/LoadBalancer 的分工:
| Nginx | Ribbon / LoadBalancer | |
|---|---|---|
| 类型 | 服务端负载均衡(中心化) | 客户端负载均衡(去中心化) |
| 位置 | 系统最外层入口 | 服务间内部调用 |
| 流量类型 | 南北向(外部→内部) | 东西向(服务→服务) |
| 策略 | 6 种(轮询、加权、IP Hash、最小连接、URL Hash、一致性 Hash) | Ribbon 7 种 / LoadBalancer 2-3 种 |
| SSL | 在 Nginx 层终结 | 内网 HTTP,不需要 |
十二、常用命令
bash
# 启动
nginx
# 停止(优雅,等待处理完当前请求)
nginx -s quit
# 立即停止
nginx -s stop
# 重载配置(不中断服务)
nginx -s reload
# 重新打开日志文件
nginx -s reopen
# 测试配置文件语法
nginx -t
# 测试指定配置文件
nginx -t -c /etc/nginx/nginx.conf
# 查看版本
nginx -v十三、面试要点
Q:Nginx 如何处理高并发?
Master-Worker 多进程模型 + 事件驱动(epoll)+ 非阻塞 I/O。每个 Worker 单线程处理,通过 epoll 同时监听数万连接,有事件才处理,不阻塞等待。配合 sendfile 系统调用实现零拷贝静态文件传输。
Q:Nginx 有哪几种负载均衡策略?
轮询(默认)、加权轮询(weight)、IP Hash(ip_hash)、最少连接数(least_conn)、URL Hash(hash $request_uri)、一致性 Hash(hash $remote_addr consistent)。
Q:正向代理和反向代理的区别?
正向代理代理客户端,客户端知道目标服务器但通过代理访问(如翻墙);反向代理代理服务端,客户端只知道 Nginx 地址,不知道后端真实服务器。
Q:Nginx 的 location 匹配优先级?
= 精确匹配 > ^~ 前缀匹配(不检查正则) > ~ 和 ~* 正则匹配(按书写顺序) > 普通前缀匹配(最长匹配优先)。
Q:如何实现 Nginx 高可用?
通过 Keepalived 实现 VIP(虚拟 IP)漂移。两台 Nginx 共享一个虚拟 IP,主节点故障时备节点自动接管。同时配合 upstream 的健康检查,自动剔除故障后端节点。
