跳至正文
来两杯美式
返回

Nginx:高性能原理与常用配置(负载均衡 / 跨域 / 防盗链)

By 来两杯美式
发布于更新于

最近整理 Nginx 学习笔记,顺手记录一下。Nginx 这东西——装上就能跑,但跑明白不容易。本篇聚焦三件事:为什么快、怎么配、负载均衡怎么玩

一、Nginx 为什么性能这么高

1.1 解决惊群效应

惊群效应(Thundering Herd):早期的 Web 服务器,多个 worker 进程同时监听同一个 socket。一个连接进来,所有 worker 都被唤醒去 accept,但只有一个能成功,其余的被白白唤醒——并发越高,浪费越大。

Nginx 的解法:不让多个进程在同一时间监听接受连接的 socket,而是让每个进程轮流监听。具体做法:

这样连接过来时,只有一个 worker 在监听——惊群问题从根上消除。

1.2 异步非阻塞的事件模型

传统服务器的事件处理:

Nginx 的事件处理使用异步非阻塞模型

epoll 的关键优势:相比 select/poll 的「每次都遍历所有 fd」,epoll 用红黑树 + 就绪链表——只有真正就绪的 fd 才会被处理,时间复杂度 O(就绪 fd 数) 而不是 O(总 fd 数)。单 worker 扛几万并发连接就是这么来的。

1.3 master-worker 架构

master 进程(管理)
   ├── worker 1 ──► 处理连接(epoll)
   ├── worker 2 ──► 处理连接(epoll)
   ├── worker N ──► 处理连接(epoll)
   └── cache manager / loader(可选)

为什么 worker 数 = CPU 核心数?——避免进程间切换的开销。每个 worker 绑一个 CPU 核(配合 worker_cpu_affinity),减少上下文切换。

二、基础配置详解

2.1 主配置骨架

# worker 数量,一般来说 CPU 有几个就设置几个,也可以设置成 N-1
worker_processes 1;

events {
    # 默认使用 epoll(Linux 下不用显式写,nginx 会自动选)
    use epoll;

    # 单个 worker 允许的最大连接数
    worker_connections 1024;
}

http {
    # 引入外部文件(mime 类型映射)
    include       mime.types;
    default_type  application/octet-stream;

    # 开启零拷贝(与 Kafka 的 sendfile 同源——见 Kafka 系列中篇)
    sendfile on;

    # 长连接超时时间(秒)
    keepalive_timeout 65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/local/foodie-shop;
            index  index.html index.htm;
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

worker_processes 现代写法:直接写 auto,nginx 会自动按 CPU 核心数设置。

worker_processes auto;
worker_rlimit_nofile 65535;   # 提升 worker 的最大 fd 数,配合高并发

2.2 Gzip 压缩

# 开启 gzip 压缩
gzip on;

# 小于 1 字节的文件不再压缩(太小压了反而更大)
gzip_min_length 1;

# 压缩级别(1~9),值越大压缩比越大,越耗费 CPU
gzip_comp_level 3;

# 需要压缩的响应类型(这条原文档没写完,必须补全)
gzip_types text/plain text/css application/javascript application/json
           application/xml text/xml image/svg+xml;

gzip_types 必须显式声明——默认只压缩 text/html。生产环境至少要加上 css / js / json / svg。

2.3 location 中 root 与 alias 的区别

这是个经典坑——两者看起来差不多,行为完全不同:

server {
    listen 90;
    server_name localhost;

    # 访问 localhost:90/test1/a.html
    # root:把完整 URI 拼到 root 路径后 → /usr/test1/a.html
    location /test1 {
        root /usr/;
    }

    # 访问 localhost:90/test2/a.html
    # alias:用 alias 路径**替换** location 匹配前缀 → /usr/local/foodie-shop/a.html
    location /test2 {
        alias /usr/local/foodie-shop;
        index index.html;
    }
}
关键字行为是否能用于正则 location
root拼接root + 完整 URI
alias替换alias + (URI - location 前缀)❌(只能用于 prefix location)

口诀root 是「追加」,alias 是「替换」。alias 后面的路径不要带结尾 /(带不带行为不同,是另一个经典坑)。

三、反向代理与负载均衡

3.1 什么是反向代理

先理解正向代理:客户端知道真实服务器在哪,主动通过代理访问(如 VPN、爬虫 IP 池)。代理的是客户端

反向代理:客户端不知道真实服务器在哪,只看到代理服务器,由代理把请求转发给后端真实服务器(如 Nginx → Tomcat 集群)。代理的是服务端

Nginx 最核心的生产场景就是反向代理 + 负载均衡

3.2 upstream 负载均衡配置

# ----------- 配置负载均衡,开始 -----------
upstream tomcats {
    # max_conns:限制每台 server 的连接数,用于保护避免过载,可起到限流作用
    # weight:权重,值越大被分配到的概率越高
    # backup:备用机,只有在其他服务器都宕机以后,自己才会加入集群被访问到
    # 注意 backup 参数不能使用在 hash 和 random load balancing 中
    server 192.168.1.173:8080 max_conns=2 weight=1;
    server 192.168.1.174:8080 max_conns=2 weight=10;
    server 192.168.1.175:8080 backup;

    # 长连接处理的数量(与后端 Tomcat 的 keepalive 配合)
    keepalive 32;
}

server {
    listen      9999;
    server_name www.test.com;

    location / {
        proxy_pass http://tomcats;
    }
}
# ----------- 配置负载均衡,结束 -----------

3.3 负载均衡调度算法

算法关键字适用场景
轮询(默认)不写后端机器性能相近
权重轮询weight=N后端机器性能不均
ip_haship_hash;会话保持——同一 IP 固定打到同一台
最少连接数least_conn;后端处理时间差异大
hash(url/arg)hash $request_uri;缓存命中——同一 URL 固定到同一台

会话保持的代价ip_hash 解决了 session 问题,但节点宕机后该 IP 的 session 全部丢失。生产环境更好的方案是 session 集中存储(Redis)+ 无状态化部署,而不是依赖 ip_hash。

3.4 upstream 参数速查

参数作用
weight=N权重,默认 1
max_conns=N最大并发连接数(限流)
max_fails=N健康检查失败阈值,默认 1
fail_timeout=T失败 N 次后暂停时间,默认 10s
backup备用机,主力都挂了才上
down标记永久不可用(维护中)
keepalive=N到后端的长连接池大小

四、CORS 跨域支持

配置在 server 标签内,与 listen 标签平级。

# 允许跨域请求的域,* 代表所有
add_header 'Access-Control-Allow-Origin' *;

# 允许带上 cookie 请求
add_header 'Access-Control-Allow-Credentials' 'true';

# 允许请求的方法,比如 GET/POST/PUT/DELETE
add_header 'Access-Control-Allow-Methods' *;

# 允许请求的 header
add_header 'Access-Control-Allow-Headers' *;

重要警告Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: true 不能同时使用——浏览器规范禁止。要带 cookie 就必须把 * 替换成具体的 origin(如 https://example.com)。

生产推荐:用 $http_origin 变量做白名单回写,而不是裸写 *

五、防盗链

防盗链(防止其它站点非法引用自己系统的静态资源)。配置在跨域相关位置同级

# 对源站点验证(只允许 imooc.com 的子域引用)
valid_referers *.imooc.com;

# 非法引入会进入下方判断
if ($invalid_referer) {
    return 404;
}

valid_referers 支持的语法:

写法含义
none允许 Referer 为空(直接访问)
blocked允许 Referer 不带 http/https 前缀
*.imooc.com允许 imooc.com 的所有子域
server_names允许与 server_name 匹配的 Referer
~regex正则匹配

现代视角(2026)补一句:防盗链在 2024 年后已经不是最优解——更推荐用签名 URL(带过期时间的 token)或 CDN 鉴权。Referer 头是可以伪造的,只能防君子防不了小人。

六、常用运维命令速查

# 检查配置语法(修改后必须先检查)
nginx -t

# 平滑重载配置(不重启服务,请求零丢失)
nginx -s reload

# 重新打开日志文件(日志切割用)
nginx -s reopen

# 快速停止
nginx -s stop

# 优雅停止(处理完当前请求再退)
nginx -s quit

nginx -s reload 的原理:master 进程收到信号 → 启动新 worker 处理新请求 → 通知老 worker 处理完手上请求后退出。全程不丢请求——这是 Nginx 平滑发布的基石。

七、小结

主题核心要点
高性能惊群消除 + epoll 异步 + master-worker
基础配置worker_processes / worker_connections / sendfile / gzip
路径匹配root 是追加,alias 是替换
负载均衡upstream + 5 种调度算法
跨域CORS 四件套(注意 * + Credentials 互斥)
防盗链valid_referers + $invalid_referer

Nginx 这东西——配置文件就是文档,多敲几遍 nginx -t 比看十篇博客都管用。

现代视角补一句(2026):本篇涵盖的命令、配置到 2026 年仍然适用——Nginx 的核心模型没动过。变的只是:HTTP/3(QUIC)支持动态模块化OpenResty/Lua 生态的成熟。如果是新建项目,可以考虑用 Caddy(自动 HTTPS)做入门,但 Nginx 依然是生产事实标准。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.Linux 命令大全:SSH 免登录、查找、防火墙与运维必会命令
  2. 02.Maven 入门到精通:依赖管理、生命周期与多模块项目
  3. 03.Nginx:高性能原理与常用配置(负载均衡 / 跨域 / 防盗链)
  4. 04.Maxwell 数据初始化:maxwell-bootstrap 全量同步实践
  5. 05.mac 系统的 IntelliJ IDEA 快捷键大全

上一篇
CAP 与 BASE:分布式系统的理论基石
下一篇
MySQL 知识系列(九):CASE 语句、乐观锁与悲观锁实战