Nginx 是什么
Nginx 是一个高性能的 Web 服务器,也常被用作反向代理、负载均衡器和 HTTP 缓存工具。它像一个“门卫”,根据配置文件 nginx.conf,决定每个请求的去向。
拦截URL配制
nginx 会根据 location 分辨 url , 让 符合条件的 url 执行对应的逻辑. 像一个 switch
location = /111/ {
default_type text/plain;
return 200 "111 success";
}
拦截规则
| 匹配方式 | 示例 | 特点 | 优先级 |
|---|---|---|---|
| 精确匹配 | location = /exact | 路径必须完全匹配 | 最高 |
| 高优先级前缀 | location ^~ /prefix | 匹配前缀,优先级高于正则 | 第二 |
| 正则匹配 | location ~ /a.*\.html | 区分大小写正则 | 第三 |
| 正则匹配(忽略大小写) | location ~* /a.*\.html | 忽略大小写正则 | 第三 |
| 普通前缀匹配 | location /common | 匹配路径前缀,常用于默认配置 | 最低 |
精确匹配(=) > 高优先级前缀匹配(^~) > 正则匹配(~ ~*) > 普通前缀匹配
URL 分配配制
分配静态资源
- root 和 alias 会设置静态资源路经 , 让 url 访问到对应的资源
- 差异: root 是“补全路径”,alias 是“替换路径”。
- 在使用 正则匹配 location 时, 必须 有捕获组, 否则 会引起错误
location /static/ {
root /data/images/; # 访问 http://localhost:80/static/logo.png → /data/images/static/logo.png
}
location /static/ {
alias /data/images/; # 访问 http://localhost:80/static/logo.png → /data/images/logo.png
}
解析 在访问
http://localhost:80/static/logo.png时, 配制 root 会到 /data/images/static/logo.png 而 alias 会到 /data/images/logo.png 没有 location 所匹配的路经
分配反向代理
- 反向代理 是站在 客户端的角度来看待的. 客户端访问 nginx , nginx 分配到 目标服务中. 对于 目标服务来说, nginx 是它的代理. 对于客户端来说 就是反向的一个代理.
- 反向代理的作用:
- 负载均衡: 将用户请求分发到多个服务器,避免单点过载。
- 安全防护: 隐藏后端服务器 IP,防止 DDoS 攻击。
- 统一入口: 对外提供单一域名和端口,内部可部署多个服务(如微服务网关)。
- 性能优化: 通过缓存、压缩、SSL 卸载提升响应速度。
安全防护 & 统一入口
# 访问 /api 的请求, 都会转接到 http://192.168.1.6:3000
location ^~ /api {
proxy_pass http://192.168.1.6:3000;
}
location ^~ /user_api {
proxy_pass http://192.168.1.6:3001;
}
sequenceDiagram
participant Client as 客户端
participant Nginx as Nginx
participant Backend1 as 后端服务1 (3000)
participant Backend2 as 后端服务2 (3001)
Note over Client: 发起请求
Client->>Nginx: GET /api/user/info
Nginx->>Nginx: 路由匹配检查
alt 路径匹配 /api
Nginx->>Backend1: 代理请求 → http://192.168.1.6:3000/api/user/info
Backend1-->>Nginx: 返回响应数据
else 路径匹配 /user_api
Nginx->>Backend2: 代理请求 → http://192.168.1.6:3001/user_api/...
Backend2-->>Nginx: 返回响应数据
end
Nginx-->>Client: 返回最终响应
负载均衡
- 作用:Nginx 可以将进入的请求流量均匀分发到多个后端服务器(如应用服务节点),从而实现负载均衡,提升系统的吞吐量、响应能力和整体可用性。
- 缺点:传统基于 Nginx 的负载均衡方式通常需要预先配置好所有后端服务器,这些服务器需始终处于运行状态。这种方式有两个主要问题:
- 资源浪费:在低流量时段,闲置的服务器仍在运行,造成资源浪费。
- 扩展困难:在流量高峰期,如果没有提前部署足够的服务器,容易导致系统负载过高甚至崩溃。
- 对比k8s : 在现代云原生架构中,常常使用 Kubernetes(k8s)来动态管理服务的生命周期与扩缩容。Nginx 则更多作为接入层反向代理,与 Kubernetes 的服务发现和负载均衡机制集成使用,起到入口网关(如 Ingress Controller)的作用。
负载均衡策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 默认轮询 | 依次轮流分配请求 | 服务性能均衡 |
| 加权轮询 | 设置权重决定流量比例 | 服务性能差异较大 |
| 最少连接 | 分配给当前连接最少的节点 | 长连接服务,如 WebSocket |
| IP 哈希 | 同一客户端 IP 分配固定节点 | 会话保持(购物车等) |
| 备用服务器 | 主服务器宕机才启用备用节点 | 灾备方案 |
轮询分配
- nginx 的默认策略, 对所有服务器一视同仁, 根据顺序 分配.
- 适合后端服务器性能均匀的无状态服务(如 REST API、静态资源)。
http {
# 定义后端服务器组(upstream)
upstream backend_servers {
# 基础轮询策略(默认)
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name example.com;
location / {
# 将请求代理到后端服务器组
proxy_pass http://backend_servers;
}
}
}
加权轮询
- 使用 weight 设置比重, weight 越大, 流量越大
- 适合后端服务器配置不均(如新旧硬件混用)。
upstream backend {
server 192.168.1.1:80 weight=3; # 处理3倍流量
server 192.168.1.2:80 weight=1;
}
最少连接数
- 优先分配给当前连接数最少的服务器
- 适合长连接服务(如 WebSocket、数据库连接池)
upstream backend {
least_conn;
server 192.168.1.1:80;
server 192.168.1.2:80;
}
IP哈希(IP Hash)
- 同一客户端IP固定访问同一后端(会话保持)
- 适合 需要会话一致性的服务(如用户登录状态、购物车)
upstream backend {
ip_hash;
server 192.168.1.1:80;
server 192.168.1.2:80;
}
备用服务器
- 设置该服务只会在其他服务都挂掉的情况下才使用
- 适合 最后的防线
upstream backend_api {
server 192.168.1.6:3000 weight=2; # 权重2
server 192.168.1.7:3000; # 权重1
server 192.168.1.8:3000 backup; # 备用服务器
}
Nginx 连接池
- Nginx 和 目标服务器 连接时, 会有 TCP 行为. 这会产生不必要的 三次握手. Nginx 会保留已创建好的连接, 来减少 TCP 行为
upstream backend {
server 192.168.1.101:8080;
keepalive 32; # 空闲连接池最大容量 = 32
keepalive_timeout 60s; # 空闲连接超过 60 秒自动关闭
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
运行行为
- Nginx 连接池会在有连接时, 创建连接, 而并非
keepalive设置多少就创建多少keepalive是指最多保留多少连接. - Nginx 连接池中的连接不会一直保留,是根据
keepalive_timeout设置的持续时间关闭的.
graph LR
A[客户端请求] --> B{Nginx}
B --> C{连接池有空闲?}
C -->|有| D[复用连接]
C -->|无| E[新建连接]
D --> F[发送请求到后端]
E --> F
F --> G{请求完成}
G --> H{连接池未满?}
H -->|未满| I[放回连接池]
H -->|已满| J[关闭连接]
I --> K{闲置超时? keepalive_timeout}
K -->|超时| J
K -->|未超时| I
灰度环境
- 灰度环境 即 新功能 + 线上环境的环境. 可以在 正式环境中进行小范围的访问新功能.
- 作用:
- 灰度测试
- AB对照
- 减少风险
- 逐步发布与监控
灰度环境策略
| 灰度策略 | 条件来源 | 适用场景 |
|---|---|---|
| Cookie / Session | 用户身份标记 | 内测用户、VIP 抢先体验 |
| IP 地址 | 网络来源 | 地域灰度、局域网优先 |
| 请求头 | A/B 测试标记 | 功能测试、多版本切换 |
| 百分比 | 预设随机分流 | 逐步上线新功能 |
基于用户 Cookie 或 Session 的灰度发布
- 用于:
- 测试人员进行灰度测试
- VIP 抢先体验新功能
server {
listen 80;
server_name example.com;
location / {
# 判断用户是否有灰度发布标识
if ($http_cookie ~* "gray_test=true") {
# 如果用户标记为灰度用户,转发到新功能的服务
proxy_pass http://new_feature_backend; # 新功能后端服务
}
else {
# 否则,转发到旧版本的服务
proxy_pass http://old_feature_backend; # 旧版本服务
}
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;
}
}
基于 IP 地址的灰度发布
- 用于 :
- 按地区或网络环境发布新功能
- 限定某些区域的灰度发布
http {
upstream old_backend {
server old_feature_backend;
}
upstream new_backend {
server new_feature_backend;
}
server {
listen 80;
server_name example.com;
location / {
# 假设使用 IP 地址哈希来进行灰度发布
set $is_gray 0;
if ($remote_addr ~* "^(192\.168\.1\.[0-9]{1,3})$") {
set $is_gray 1; # 某些 IP 范围分配到新功能
}
if ($is_gray = 1) {
proxy_pass http://new_backend;
}
else {
proxy_pass http://old_backend;
}
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;
}
}
}
基于请求头的灰度发布(AB 测试)
- 用途
- AB 测试和功能实验
- 多版本并行测试
server {
listen 80;
server_name example.com;
location / {
# 假设通过 HTTP 请求头中的 X-Version 标识来区分版本
if ($http_x_version = "new") {
proxy_pass http://new_feature_backend; # 新版本服务
}
else {
proxy_pass http://old_feature_backend; # 旧版本服务
}
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;
}
}
基于百分比的灰度发布
- 作用
- 逐步发布新功能
- 风险控制和流量管理
server {
listen 80;
server_name example.com;
location / {
# 随机分配请求
set $random_number $math_random;
# 设置阈值,假设将 30% 的流量分配给新功能
if ($random_number < 0.3) {
proxy_pass http://new_feature_backend; # 新功能服务
}
else {
proxy_pass http://old_feature_backend; # 旧版本服务
}
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;
}
}
缓存
Nginx 的 HTTP 缓存功能主要用于提升网站性能和减轻后端服务器负担。它通常用于反向代理场景,通过缓存静态或动态请求的响应结果,避免频繁访问后端。
缓存区域统一定义
http {
proxy_cache_path /var/cache/nginx # 缓存文件存储目录
levels=1:2 # 目录结构层级,提升查找效率
keys_zone=my_cache:50m # 定义缓存区域名和内存大小(索引)
max_size=2g # 最大磁盘缓存空间
inactive=60m # 超过 60 分钟未访问将被移除
use_temp_path=off; # 提升缓存写入性能,避免临时路径
include /etc/nginx/conf.d/*.conf; # 载入其他配置文件
}
反向代理缓存后端接口(适用于 GET 查询类 API)
- 目的: 减少后端压力,加快响应速度。
- 场景: 常用在 内容不频繁变更 的接口
location ~* ^/api/(posts|users|ranking)/ {
proxy_pass http://backend;
proxy_cache my_cache; # 使用名为 my_cache 的缓存区域
proxy_cache_valid 200 10m; # 对 200 响应缓存 10 分钟
proxy_cache_methods GET HEAD; # 仅缓存 GET 和 HEAD 方法
proxy_cache_use_stale error timeout updating; # 后端出错或更新时使用旧缓存响应
add_header X-Cache-Status $upstream_cache_status; # 添加缓存状态头部(HIT/MISS/BYPASS)
}
缓存动态页面(如文章页、商品详情页)
- 目的: 加快页面加载速度,适用于不登录状态下的页面访问。
- 场景: 常用在 不频繁变化的页面
location /article/ {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_key "$scheme$host$request_uri"; # 自定义缓存 key,避免参数造成缓存穿透
proxy_cache_valid 200 302 5m; # 对 200 和 302 响应缓存 5 分钟
proxy_cache_bypass $cookie_auth; # 有 auth cookie 时不使用缓存
proxy_no_cache $cookie_auth; # 有 auth cookie 时不保存缓存
add_header X-Cache $upstream_cache_status;
}
静态资源缓存加速
- 目的: 充分利用浏览器缓存,减少资源重复加载,降低带宽压力。
- 场景: 静态资源
location ~* \.(jpg|jpeg|png|gif|css|js|ico|woff|woff2|ttf|eot)$ {
root /var/www/public;
expires 30d; # 告诉浏览器此文件可缓存 30 天
access_log off; # 禁止记录访问日志,减少磁盘 IO
}
微服务内部接口缓存
- 目的: 减轻内部公共服务负载,避免重复获取重复数据。
- 场景: 内部常用的接口
location /internal/metadata {
proxy_pass http://internal-service;
proxy_cache my_cache;
proxy_cache_valid 200 5m; # 缓存 200 响应 5 分钟
proxy_cache_lock on; # 多个请求同时来时只允许第一个穿透后端
proxy_cache_use_stale updating; # 后端更新期间使用旧缓存
}
补充场景
前端部署和后端 fallback
- 目的: 尝试使用 某个目录
- 场景: 静态网址部署
location / {
try_files $uri $uri/ /index.html;
}
graph LR
A[用户请求路径] --> B{文件是否存在 $uri}
B -- 是 --> R1[返回 $uri 内容]
B -- 否 --> C{是否存在目录 $uri/}
C -- 是 --> R2[返回 $uri/ 目录索引或内容]
C -- 否 --> D[返回 /index.html]
配制 header 头
- 目的: 修改 header 头, 适配请求
- 场景: 需要携带客户端参数, 接口特殊配制
location /api/ {
proxy_pass http://backend:3000;
proxy_set_header Host $host; # 请求原始的 Host
proxy_set_header X-Real-IP $remote_addr; # 请求者真实 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 转发链条上的 IP 列表,追加当前客户端 IP
}
gzip 压缩配置
- 目的: 压缩静态资源提高传输效率
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1k;
gzip_comp_level 6;
限速限流
- 目的: 防止爬虫或攻击设置
http {
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=1r/s;
server {
location /api/ {
limit_req zone=req_limit_per_ip burst=5 nodelay; # 每个 IP 每秒 1 个请求,最多突发 5 个
}
}
}
Nginx + WebSocket 支持
location /ws/ {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
直给内容
location = /111/ {
default_type text/plain;
return 200 "111 success";
}