侧边栏壁纸
  • 累计撰写 88 篇文章
  • 累计创建 31 个标签
  • 累计收到 21 条评论

目 录CONTENT

文章目录

Nginx 深度实战:从反向代理到高性能网关,生产级配置与调优全攻略

Administrator
2026-04-11 / 0 评论 / 0 点赞 / 0 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

本文约 6000 字,涵盖 Nginx 核心原理、反向代理、负载均衡、HTTPS/HTTP2、限流防刷、缓存加速、Lua 动态扩展、性能调优、Docker 部署及生产踩坑指南,适合有一定 Linux 基础的后端/运维同学。


一、为什么 Nginx 在微服务时代依然不可替代

在 K8s + Spring Cloud Gateway 大行其道的今天,Nginx 依然是很多公司的第一道流量入口。原因很简单:

维度NginxSpring Cloud Gateway
性能(10K并发)✅ C语言,极低内存⚠️ JVM 预热,内存占用高
静态资源✅ 原生高效❌ 不擅长
SSL 卸载✅ OpenSSL 原生⚠️ 需额外配置
Lua 扩展✅ OpenResty❌ 不支持
动态路由⚠️ 需 Lua/API✅ 代码原生支持
学习曲线中(需熟悉 WebFlux)

结论:Nginx 在接入层(7层入口)做 SSL 卸载、静态资源、限流防刷;Spring Cloud Gateway 在业务层做动态路由、鉴权聚合。两者不是竞争关系,而是黄金搭档。


二、Nginx 核心架构原理(面试必问)

2.1 Master-Worker 进程模型

┌─────────────────────────────────────────┐
│              Master Process             │
│  - 读取配置、管理 Worker 生命周期        │
│  - 不处理实际请求                        │
└──────────┬──────────────────────────────┘
           │ fork
    ┌──────┴──────┐
    ▼             ▼
Worker-1       Worker-2   ... (Worker 数 = CPU 核数)
  │
  ├── 连接1 (非阻塞 I/O)
  ├── 连接2
  └── 连接N  (单 Worker 可处理数万并发)
  • Master:解析配置、绑定端口、管理 Worker(热重载/优雅停机)
  • Worker:基于 epoll 的事件驱动模型,单线程处理海量并发
  • 热重载原理nginx -s reload → Master 发 USR1 信号 → 新 Worker 用新配置启动 → 旧 Worker 处理完存量请求后退出(零停机)

2.2 epoll 事件驱动 vs 传统 BIO

传统 Apache(BIO):1 请求 = 1 线程,10K 并发 = 10K 线程,内存爆炸
Nginx(epoll):N 请求 = 1 Worker 线程,用 epoll 监听 I/O 就绪事件,内存极低

这就是 Nginx 能用 10MB 内存处理 1 万并发的根本原因。


三、生产级 nginx.conf 完整配置详解

3.1 主配置骨架

# /etc/nginx/nginx.conf

# ============================================================
# 全局配置
# ============================================================
user  nginx;                          # 工作进程用户
worker_processes  auto;               # 自动等于 CPU 核数
worker_rlimit_nofile  65535;          # 单 Worker 最大文件描述符(需同步调整系统 ulimit)
error_log  /var/log/nginx/error.log  warn;
pid        /var/run/nginx.pid;

# ============================================================
# 事件模块
# ============================================================
events {
    use  epoll;                       # Linux 下使用 epoll(默认已选最优)
    worker_connections  10240;        # 单 Worker 最大并发连接数
    multi_accept  on;                 # 一次 accept 多个连接(高并发场景打开)
    accept_mutex  off;                # 高并发场景关闭,减少锁竞争
}

# ============================================================
# HTTP 核心模块
# ============================================================
http {
    include       /etc/nginx/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" "$http_x_forwarded_for" '
                      'rt=$request_time uct=$upstream_connect_time '
                      'uht=$upstream_header_time urt=$upstream_response_time';

    log_format  json  escape=json
                      '{"time":"$time_iso8601",'
                      '"client":"$remote_addr",'
                      '"method":"$request_method",'
                      '"uri":"$request_uri",'
                      '"status":$status,'
                      '"bytes":$body_bytes_sent,'
                      '"rt":$request_time,'
                      '"urt":"$upstream_response_time"}';

    access_log  /var/log/nginx/access.log  json;   # JSON 格式方便 ELK 解析

    # ---------- 传输优化 ----------
    sendfile        on;               # 零拷贝发送文件
    tcp_nopush      on;               # 与 sendfile 配合,减少网络包数量
    tcp_nodelay     on;               # 小包立即发送(长连接场景)
    keepalive_timeout  75s;           # 客户端长连接超时
    keepalive_requests 1000;          # 单连接最大请求数

    # ---------- 压缩 ----------
    gzip  on;
    gzip_min_length  1024;            # 小于 1KB 不压缩
    gzip_comp_level  4;               # 压缩级别 1-9,4 是性能/压缩率平衡点
    gzip_types  text/plain text/css application/json application/javascript
                text/xml application/xml application/xml+rss text/javascript
                image/svg+xml;
    gzip_vary  on;                    # 添加 Vary: Accept-Encoding 响应头
    gzip_proxied  any;                # 对代理请求也压缩

    # ---------- 缓冲区调优 ----------
    client_max_body_size  100m;       # 上传文件大小限制
    client_body_buffer_size  128k;
    proxy_buffer_size  16k;
    proxy_buffers  8 64k;
    proxy_busy_buffers_size  128k;

    # ---------- 超时配置 ----------
    proxy_connect_timeout  5s;        # 连接上游超时
    proxy_send_timeout     60s;       # 发送请求到上游超时
    proxy_read_timeout     60s;       # 读取上游响应超时

    # ---------- 安全头 ----------
    server_tokens  off;               # 不暴露 Nginx 版本号
    add_header  X-Frame-Options  SAMEORIGIN;
    add_header  X-Content-Type-Options  nosniff;
    add_header  X-XSS-Protection  "1; mode=block";
    add_header  Referrer-Policy  "strict-origin-when-cross-origin";

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

四、反向代理与负载均衡

4.1 upstream 负载均衡配置

# /etc/nginx/conf.d/upstream.conf

# ============================================================
# upstream:定义后端服务器组
# ============================================================

# 轮询(默认,适合无状态服务)
upstream backend_rr {
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
    keepalive 32;                     # 与上游保持长连接池
}

# 加权轮询(按服务器性能分配流量)
upstream backend_weight {
    server 10.0.0.1:8080  weight=5;  # 高配机器
    server 10.0.0.2:8080  weight=3;
    server 10.0.0.3:8080  weight=1  backup;  # 备用节点,正常不参与
}

# ip_hash(同一客户端 IP 打到同一后端,适合有状态会话)
upstream backend_iphash {
    ip_hash;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080  down;      # 临时下线(不影响 hash 环)
}

# least_conn(最少连接数,适合请求耗时差异大的场景)
upstream backend_leastconn {
    least_conn;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

# hash 一致性哈希(适合缓存穿透场景)
upstream backend_hash {
    hash $request_uri  consistent;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

4.2 健康检查(商业版 vs 开源方案)

# 开源版:被动健康检查
upstream backend {
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    # max_fails=3:3次失败则标记不可用
    # fail_timeout=30s:30秒后重新尝试
    server 10.0.0.3:8080  max_fails=3  fail_timeout=30s;
}

# 推荐方案:nginx_upstream_check_module(第三方模块)
upstream backend {
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;

    check interval=3000 rise=2 fall=3 timeout=1000 type=http;
    check_http_send "HEAD /actuator/health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}

# 暴露健康检查状态页
server {
    location /upstream_check {
        check_status;
        access_log  off;
        allow  10.0.0.0/8;    # 仅内网访问
        deny   all;
    }
}

五、HTTPS + HTTP/2 完整配置

5.1 SSL 证书配置最佳实践

server {
    listen  443  ssl http2;
    listen  [::]:443  ssl http2;
    server_name  92yangyi.top www.92yangyi.top;

    # ---------- 证书路径 ----------
    ssl_certificate      /etc/nginx/ssl/92yangyi.top.pem;
    ssl_certificate_key  /etc/nginx/ssl/92yangyi.top.key;

    # ---------- 协议与加密套件 ----------
    ssl_protocols  TLSv1.2 TLSv1.3;            # 禁用 TLS 1.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:
                 ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers  off;             # TLS 1.3 不需要此选项

    # ---------- Session 复用(减少握手开销)----------
    ssl_session_cache    shared:SSL:20m;        # 20MB 共享缓存
    ssl_session_timeout  1d;
    ssl_session_tickets  off;                   # 禁用 ticket(前向安全)

    # ---------- OCSP Stapling(加速证书验证)----------
    ssl_stapling         on;
    ssl_stapling_verify  on;
    ssl_trusted_certificate  /etc/nginx/ssl/chain.pem;
    resolver  8.8.8.8 8.8.4.4  valid=300s;
    resolver_timeout  5s;

    # ---------- HSTS(强制 HTTPS,需谨慎开启)----------
    add_header  Strict-Transport-Security  "max-age=63072000; includeSubDomains; preload"  always;

    # ---------- HTTP/2 Push(主动推送关键资源)----------
    location = /index.html {
        http2_push  /static/css/main.css;
        http2_push  /static/js/main.js;
    }

    # ... 其他 location 配置
}

# HTTP → HTTPS 301 跳转
server {
    listen  80;
    listen  [::]:80;
    server_name  92yangyi.top www.92yangyi.top;
    return  301  https://$host$request_uri;
}

5.2 Let's Encrypt 自动续签(Certbot + Docker)

# 一键申请证书
docker run --rm \
  -v /etc/letsencrypt:/etc/letsencrypt \
  -v /var/www/certbot:/var/www/certbot \
  -p 80:80 \
  certbot/certbot certonly \
  --standalone \
  -d 92yangyi.top \
  --email admin@92yangyi.top \
  --agree-tos \
  --no-eff-email

# crontab 每月1日凌晨2点自动续签
0 2 1 * * docker run --rm -v /etc/letsencrypt:/etc/letsencrypt certbot/certbot renew --quiet && nginx -s reload

六、限流与防刷(生产必备)

6.1 请求频率限制(limit_req)

http {
    # 定义限流区域:按客户端 IP 限流,10MB 内存约存 16 万条 IP 记录
    limit_req_zone  $binary_remote_addr  zone=api_limit:10m  rate=20r/s;

    # 按 API Key 限流(更精细,适合 SaaS 场景)
    limit_req_zone  $http_x_api_key  zone=apikey_limit:10m  rate=100r/s;

    # 登录接口专用限流(严格防爆破)
    limit_req_zone  $binary_remote_addr  zone=login_limit:10m  rate=5r/m;

    server {
        # API 接口:20r/s + 允许突发 50 个请求入队(nodelay 超出立即返回 503)
        location /api/ {
            limit_req  zone=api_limit  burst=50  nodelay;
            limit_req_status  429;               # 返回 429 而非默认 503

            # 自定义限流响应
            error_page  429  /429.json;

            proxy_pass  http://backend;
        }

        # 登录接口:极严格限流
        location /api/auth/login {
            limit_req  zone=login_limit  burst=5  nodelay;
            limit_req_status  429;
            proxy_pass  http://backend;
        }

        location = /429.json {
            internal;
            default_type  application/json;
            return  429  '{"code":429,"message":"请求过于频繁,请稍后再试"}';
        }
    }
}

6.2 并发连接限制(limit_conn)

http {
    # 按 IP 限制并发连接数
    limit_conn_zone  $binary_remote_addr  zone=conn_limit:10m;

    server {
        # 单 IP 最多 20 个并发连接
        limit_conn  conn_limit  20;
        limit_conn_status  503;

        # 下载接口限速(防止带宽被单用户耗尽)
        location /download/ {
            limit_conn  conn_limit  5;
            limit_rate  500k;            # 单连接限速 500KB/s
            limit_rate_after  10m;       # 前 10MB 不限速(用户体验优先)
            proxy_pass  http://file_server;
        }
    }
}

6.3 黑白名单与 Geo 封锁

http {
    # IP 黑名单(GeoIP2 模块,需安装 ngx_http_geoip2_module)
    geoip2  /usr/share/GeoIP/GeoLite2-Country.mmdb {
        $geoip2_country_code  country iso_code;
    }

    # 封锁特定国家/地区(按需配置)
    map $geoip2_country_code $allowed_country {
        default   1;
        # CN       1;  # 中国大陆
        # TW       1;  # 台湾
        RU        0;  # 示例:封锁来自 RU 的请求(仅演示)
    }

    server {
        if ($allowed_country = 0) {
            return  403;
        }
    }
}

# 静态黑名单文件(blocklist.conf)
# deny 192.168.1.100;
# deny 10.0.0.0/8;
# include /etc/nginx/blocklist.conf;

七、静态资源缓存与 CDN 配合

7.1 浏览器缓存策略

server {
    # HTML:不缓存(确保用户获取最新页面)
    location ~* \.html$ {
        expires  -1;
        add_header  Cache-Control  "no-cache, no-store, must-revalidate";
    }

    # 带 hash 的静态资源(如 main.abc123.js):长期缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|webp|svg|ico|woff2|woff|ttf)$ {
        expires  365d;
        add_header  Cache-Control  "public, immutable";
        add_header  Vary  "Accept-Encoding";

        # 开启 ETag
        etag  on;
    }

    # API 响应:禁止缓存
    location /api/ {
        add_header  Cache-Control  "no-store";
        proxy_pass  http://backend;
    }
}

7.2 Nginx 代理层缓存(proxy_cache)

http {
    # 定义缓存区域(磁盘路径 + 内存索引大小 + 磁盘最大容量)
    proxy_cache_path  /var/cache/nginx
                      levels=1:2
                      keys_zone=api_cache:50m
                      max_size=2g
                      inactive=60m
                      use_temp_path=off;

    server {
        # 对 GET 请求开启缓存
        location /api/public/ {
            proxy_cache  api_cache;
            proxy_cache_key  "$scheme$request_method$host$request_uri";
            proxy_cache_valid  200  10m;          # 200 响应缓存 10 分钟
            proxy_cache_valid  404  1m;
            proxy_cache_valid  any  0;            # 其他状态码不缓存

            # 缓存 stale 内容(上游宕机时继续服务)
            proxy_cache_use_stale  error timeout updating
                                   http_500 http_502 http_503 http_504;

            # 防止缓存击穿:同一 key 只有一个请求穿透到上游
            proxy_cache_lock  on;
            proxy_cache_lock_timeout  5s;

            # 响应头中暴露缓存状态(调试用)
            add_header  X-Cache-Status  $upstream_cache_status;

            proxy_pass  http://backend;
        }

        # 手动清除缓存接口(配合 ngx_cache_purge 模块)
        location ~ /purge(/.*) {
            allow  127.0.0.1;
            allow  10.0.0.0/8;
            deny   all;
            proxy_cache_purge  api_cache  "$scheme$request_method$host$1";
        }
    }
}

八、OpenResty + Lua:动态扩展能力

当 Nginx 内置指令无法满足复杂业务逻辑时,OpenResty = Nginx + LuaJIT,可以在 Nginx 内嵌入高性能 Lua 脚本。

8.1 安装 OpenResty(Docker 方式)

FROM openresty/openresty:1.25.3.1-alpine

# 安装 Lua 包管理器 opm
RUN opm get ledgetech/lua-resty-http \
    && opm get bungle/lua-resty-redis

COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY lua/ /usr/local/openresty/nginx/lua/

8.2 Lua 实现 Redis 动态黑名单

# nginx.conf(OpenResty)
http {
    lua_shared_dict  ip_blacklist  10m;    # 共享内存缓存黑名单
    lua_package_path  "/usr/local/openresty/nginx/lua/?.lua;;";

    init_worker_by_lua_block {
        -- Worker 启动时从 Redis 加载黑名单到共享内存
        local redis = require "resty.redis"
        local red = redis:new()
        red:set_timeouts(1000, 1000, 1000)
        local ok, err = red:connect("127.0.0.1", 6379)
        if ok then
            local ips, _ = red:smembers("nginx:blacklist")
            local blacklist = ngx.shared.ip_blacklist
            if ips then
                for _, ip in ipairs(ips) do
                    blacklist:set(ip, true, 3600)
                end
            end
        end
    }

    server {
        access_by_lua_block {
            local blacklist = ngx.shared.ip_blacklist
            local client_ip = ngx.var.remote_addr
            if blacklist:get(client_ip) then
                ngx.status = 403
                ngx.header["Content-Type"] = "application/json"
                ngx.say('{"code":403,"message":"您的 IP 已被封禁"}')
                return ngx.exit(403)
            end
        }

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

        # 动态添加黑名单接口
        location /admin/blacklist/add {
            allow 127.0.0.1;
            deny  all;

            content_by_lua_block {
                local args = ngx.req.get_uri_args()
                local ip = args.ip
                if not ip then
                    ngx.say('{"code":400,"message":"缺少 ip 参数"}')
                    return
                end
                -- 写入共享内存
                ngx.shared.ip_blacklist:set(ip, true, 86400)
                -- 写入 Redis(持久化)
                local redis = require "resty.redis"
                local red = redis:new()
                red:connect("127.0.0.1", 6379)
                red:sadd("nginx:blacklist", ip)
                ngx.say('{"code":200,"message":"已加入黑名单"}')
            }
        }
    }
}

8.3 Lua 实现 JWT 鉴权(无需转发到业务服务)

-- /usr/local/openresty/nginx/lua/jwt_auth.lua
local cjson = require "cjson"

local function base64url_decode(str)
    str = str:gsub("-", "+"):gsub("_", "/")
    local pad = 4 - #str % 4
    if pad < 4 then str = str .. string.rep("=", pad) end
    return ngx.decode_base64(str)
end

local function verify_jwt(token, secret)
    local parts = {}
    for part in token:gmatch("[^%.]+") do
        table.insert(parts, part)
    end
    if #parts ~= 3 then return nil, "invalid token format" end

    -- 验证签名
    local signing_input = parts[1] .. "." .. parts[2]
    local sig = ngx.hmac_sha1(secret, signing_input)
    local expected = ngx.encode_base64(sig):gsub("+", "-"):gsub("/", "_"):gsub("=", "")
    if expected ~= parts[3] then
        return nil, "invalid signature"
    end

    -- 解析 payload
    local payload_str = base64url_decode(parts[2])
    local payload = cjson.decode(payload_str)

    -- 验证过期时间
    if payload.exp and payload.exp < ngx.time() then
        return nil, "token expired"
    end

    return payload
end

-- 使用方
local auth_header = ngx.var.http_authorization
if not auth_header or not auth_header:match("^Bearer ") then
    ngx.status = 401
    ngx.say('{"code":401,"message":"缺少认证 Token"}')
    return ngx.exit(401)
end

local token = auth_header:sub(8)
local payload, err = verify_jwt(token, "your-jwt-secret")
if not payload then
    ngx.status = 401
    ngx.say(cjson.encode({code=401, message=err}))
    return ngx.exit(401)
end

-- 将用户信息透传给上游
ngx.req.set_header("X-User-Id", payload.sub)
ngx.req.set_header("X-User-Role", payload.role)

九、Docker Compose 生产部署

9.1 完整部署结构

nginx-stack/
├── docker-compose.yml
├── nginx/
│   ├── nginx.conf
│   ├── conf.d/
│   │   ├── upstream.conf
│   │   └── app.conf
│   └── ssl/
│       ├── cert.pem
│       └── cert.key
├── logs/
└── cache/

9.2 docker-compose.yml

version: "3.9"

services:
  nginx:
    image: nginx:1.25.4-alpine
    container_name: nginx-gateway
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - ./logs:/var/log/nginx
      - ./cache:/var/cache/nginx
    networks:
      - backend_net
    healthcheck:
      test: ["CMD", "nginx", "-t"]
      interval: 30s
      timeout: 10s
      retries: 3
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 512M
        reservations:
          cpus: "0.5"
          memory: 128M

  # Nginx 日志采集(配合 ELK)
  filebeat:
    image: elastic/filebeat:8.13.0
    container_name: filebeat-nginx
    user: root
    volumes:
      - ./logs:/var/log/nginx:ro
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
    networks:
      - backend_net
    depends_on:
      - nginx

networks:
  backend_net:
    external: true
    name: microservice_network

9.3 常用运维命令

# 验证配置语法
docker exec nginx-gateway nginx -t

# 热重载配置(零停机)
docker exec nginx-gateway nginx -s reload

# 查看实时请求日志
docker logs -f nginx-gateway

# 查看 Nginx 运行状态(需开启 stub_status)
curl http://127.0.0.1/nginx_status

# 分析访问日志:Top 10 高频 IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

# 分析响应时间分布(P99 响应时间)
awk '{print $NF}' /var/log/nginx/access.log | sort -n | awk 'BEGIN{c=0}{a[c++]=$1}END{print "P50:", a[int(c*0.5)], "P95:", a[int(c*0.95)], "P99:", a[int(c*0.99)]}'

十、性能调优:从系统到应用

10.1 Linux 内核参数(必须配置)

# /etc/sysctl.conf

# 文件描述符
fs.file-max = 1000000

# TCP 连接队列
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# TIME_WAIT 优化
net.ipv4.tcp_tw_reuse = 1            # 复用 TIME_WAIT 连接
net.ipv4.tcp_fin_timeout = 15        # 缩短 FIN_WAIT2 超时

# TCP 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# 应用立即生效
sysctl -p

10.2 Nginx 进程调优

# 绑定 Worker 到特定 CPU(减少上下文切换)
worker_cpu_affinity  auto;

# 或手动绑定(4核示例)
# worker_cpu_affinity  0001 0010 0100 1000;

# 优先级(-20 到 19,越小优先级越高)
worker_priority  -5;

# Nginx 状态监控(暴露给 Prometheus)
server {
    listen  8080;
    allow   127.0.0.1;
    deny    all;

    location /nginx_status {
        stub_status;
    }

    location /metrics {
        # nginx-prometheus-exporter 会抓取 stub_status 并转换为 Prometheus 格式
        proxy_pass http://nginx_exporter:9113/metrics;
    }
}

十一、生产踩坑与解决方案

❌ 踩坑一:upstream sent invalid header

现象:代理 Spring Boot 时偶发 502
原因:后端服务返回了格式不规范的 HTTP 响应头
解决

proxy_pass_header  Server;
proxy_pass_header  Date;
proxy_ignore_headers  X-Accel-Expires Expires Cache-Control;

❌ 踩坑二:WebSocket 代理断连

现象:WebSocket 连接一段时间后自动断开
解决

location /ws/ {
    proxy_pass  http://backend;
    proxy_http_version  1.1;
    proxy_set_header  Upgrade  $http_upgrade;
    proxy_set_header  Connection  "Upgrade";
    proxy_set_header  Host  $host;
    proxy_read_timeout  3600s;    # WebSocket 长连接,延长超时
    proxy_send_timeout  3600s;
}

❌ 踩坑三:大文件上传 413 错误

现象:上传超过 1MB 的文件时返回 413 Request Entity Too Large
解决

client_max_body_size  500m;          # 全局或 location 内配置
client_body_timeout  300s;           # 上传超时(慢速网络)
proxy_request_buffering  off;        # 大文件不缓存到 Nginx,直接流式转发

❌ 踩坑四:CORS 重复响应头

现象:前端报 The 'Access-Control-Allow-Origin' header contains multiple values
原因:Nginx 和后端服务都添加了 CORS 头
解决

location /api/ {
    # 先删除上游返回的 CORS 头,再由 Nginx 统一添加
    proxy_hide_header  Access-Control-Allow-Origin;
    proxy_hide_header  Access-Control-Allow-Methods;

    add_header  Access-Control-Allow-Origin  $http_origin  always;
    add_header  Access-Control-Allow-Methods  "GET, POST, PUT, DELETE, OPTIONS"  always;
    add_header  Access-Control-Allow-Headers  "Authorization, Content-Type"  always;
    add_header  Access-Control-Allow-Credentials  "true"  always;

    if ($request_method = OPTIONS) {
        return  204;
    }

    proxy_pass  http://backend;
}

❌ 踩坑五:no live upstreams while connecting to upstream

现象:所有后端都宕机时 Nginx 返回 502
解决:配置自定义错误页 + 备用上游

upstream backend {
    server 10.0.0.1:8080  max_fails=3  fail_timeout=30s;
    server 10.0.0.2:8080  max_fails=3  fail_timeout=30s;
    server 127.0.0.1:9999  backup;    # 备用:本地静态维护页服务
}

error_page  502 503 504  /maintenance.html;
location = /maintenance.html {
    root  /var/www/html;
    internal;
}

十二、完整架构图:Nginx 在微服务体系中的位置

Internet
    │
    ▼
┌──────────────────────────────────────┐
│         CDN(Cloudflare / 阿里云 CDN)  │
│   静态资源缓存、DDoS 防护、边缘加速    │
└──────────────────┬───────────────────┘
                   │ HTTPS
                   ▼
┌──────────────────────────────────────┐
│          Nginx(接入层网关)           │
│  ✅ SSL 卸载(TLS 1.3 + HTTP/2)       │
│  ✅ 限流防刷(limit_req / limit_conn) │
│  ✅ 黑名单(Lua + Redis 动态更新)     │
│  ✅ 静态资源服务 & 代理缓存            │
│  ✅ 负载均衡(upstream 健康检查)      │
│  ✅ CORS 统一处理                      │
│  ✅ 日志采集(JSON → Filebeat → ELK)  │
└──────────────────┬───────────────────┘
                   │ HTTP(内网)
                   ▼
┌──────────────────────────────────────┐
│     Spring Cloud Gateway(业务层)    │
│  ✅ JWT 鉴权 & 权限验证               │
│  ✅ 动态路由(Nacos)                 │
│  ✅ 接口聚合 & 协议转换               │
│  ✅ 服务限流(Sentinel)              │
└──────────┬───────────────┬───────────┘
           │               │
           ▼               ▼
    微服务集群          微服务集群
  (Spring Boot)        (Spring Boot)
   ┌──────────┐        ┌──────────┐
   │ 订单服务 │        │ 用户服务 │  ...
   └──────────┘        └──────────┘

十三、总结

本文从 Nginx 的 Master-Worker 架构和 epoll 原理出发,系统梳理了生产环境中 Nginx 的核心使用场景:

能力配置要点
反向代理 & 负载均衡upstream + 健康检查 + 长连接池
HTTPS / HTTP2TLS 1.3 + OCSP Stapling + Session 复用
限流防刷limit_req_zone + burst + nodelay
代理缓存proxy_cache + cache_lock + stale
动态扩展OpenResty + Lua(JWT鉴权、动态黑名单)
性能调优内核参数 + CPU 绑定 + gzip + sendfile
生产运维Docker Compose + 热重载 + 日志分析

Nginx 的价值在于它的极致性能可编程性。在微服务架构中,它是不可替代的第一道防线,与 Spring Cloud Gateway 协同分工,共同构建高可用、高安全的流量入口体系。


参考资料

0

评论区