当前位置: 首页 > news >正文

深入剖析Nginx架构及其不同使用场景下的配置

一、Nginx 整体架构概览

1. Nginx简介

Nginx 是采用 C 语言 编写的高性能 Web 服务器、反向代理服务器及邮件代理服务器,特点是:高并发、高可用、低内存占用、模块化设计

架构核心理念:

  • Master-Worker 多进程模型

  • 事件驱动(Event-Driven) + 异步非阻塞

  • 高度模块化设计


2. 进程模型

Nginx 的进程模型非常轻量,通常包含:

1. Master 进程

  • 启动时由 shell 进程 fork 出来

  • 主要负责:

    • 读取配置文件

    • 管理 Worker 子进程(启动/重启/关闭)

    • 平滑升级(不间断服务)

2. Worker 进程

  • 实际处理请求的进程

  • 默认情况下每个 CPU 一个 worker(可配置)

  • 每个 worker 独立工作,通过 epoll 等机制异步处理连接

3. Cache Manager/Loader(可选)

  • 用于管理磁盘缓存(如 proxy_cache)

  • 管理缓存的过期与空间

Worker 之间互不通信,避免锁竞争,共享资源通常通过共享内存实现。


3. 事件驱动与异步非阻塞机制

Nginx 使用Reactor 模型 + 非阻塞 IO,事件模型封装成 ngx_event 模块,底层可选择:

  • Linux: epoll

  • BSD: kqueue

  • Windows: IOCP

  • Others: select/poll

每个 worker 维护一个事件循环(event loop),处理以下类型事件:

  • 新连接事件(accept)

  • 读写事件(read/write)

  • 定时器事件(超时)

  • 信号事件

示例事件循环伪代码:

while (true) {events = epoll_wait(epoll_fd, timeout);for (event in events) {if (event == read) {handle_read();} else if (event == write) {handle_write();}}process_timers();
}

4. 模块化设计

Nginx 模块系统非常强大,主程序仅提供框架,几乎所有功能都通过模块扩展。

模块分类

类型说明
核心模块与配置、事件循环、进程管理相关
标准模块官方提供,如 http, gzip, rewrite
第三方模块社区开发,如 lua-nginx-module, ngx_brotli
事件模块封装不同操作系统的 IO 模型(epoll/kqueue 等)
过滤模块对请求或响应进行过滤、转换(如 gzip, chunk)
处理模块提供服务逻辑,如 ngx_http_proxy_module

模块生命周期 Hook:

模块通过 Hook 函数注册以下生命周期点:

  • postconfiguration

  • init_module

  • init_process

  • init_thread

  • exit_thread

  • exit_process

  • exit_master


5. 请求处理流程

以 HTTP 请求为例,完整流程如下:

1. 请求接收

  • Worker 进程通过 epoll 监听 socket fd 上的 accept 事件

  • 建立连接后封装为 ngx_connection_t

2. 请求解析

  • 使用状态机解析 HTTP 请求头、方法、URI 等

  • 填充 ngx_http_request_t 结构

3. 查找 Location 配置

  • 基于 URI 匹配 location block

  • 加载对应 handler(如 proxy_pass)

4. 模块链处理

Nginx 通过模块链的方式处理请求,每个模块处理一部分逻辑:

HTTP 请求
→ handler 模块
→ access 模块
→ rewrite 模块
→ content 模块(如 proxy)
→ filter 模块(gzip,chunked)
→ output

每个模块通过 ngx_http_module_t 结构中的回调函数插入处理链。

5. 响应输出

  • 各模块处理完响应后输出到客户端

  • 使用 sendfile + writev 实现 零拷贝


6. 内存管理与连接池

Nginx 有自己的一套高性能内存池机制,用于避免频繁 malloc/free:

  • ngx_pool_t: 每个请求创建自己的内存池,生命周期跟随请求

  • 可申请小块内存(<4096)快速分配

  • 请求结束时统一释放内存池,避免内存泄漏

连接相关资源也使用对象池(如 ngx_connection_tngx_buf_t)复用,提高性能。


7. 配置解析系统

Nginx 配置文件是模块驱动的,结构清晰。

配置解析过程:

  1. Master 进程读取配置文件(nginx.conf

  2. 每个模块注册自己的配置指令及解析函数

  3. 创建配置结构体,填入配置参数

  4. 绑定到 ngx_cycle_t

支持嵌套结构、变量引用($host)、include 等高级配置特性。


8. 零拷贝机制(Zero Copy)

为了提升性能,Nginx 避免数据拷贝,使用以下机制:

技术说明
sendfile()直接从磁盘文件到 socket,无需中转缓冲区
mmap()映射文件到内存
writev()将多个缓冲区一次性写入 socket
splice()在 pipe 与 socket 之间传输,无需用户态

这些机制显著降低了 CPU 消耗和内存拷贝,提高了吞吐量。


9. 共享内存与缓存管理

Nginx 提供共享内存机制支持:

  • 状态统计模块(如 stub_status)

  • 缓存(proxy_cache, fastcgi_cache)

  • 限流(limit_req, limit_conn)

  • Nginx Plus 状态页

通过 ngx_shm_zone_t 管理共享内存区域,使用 slab 分配器精细管理内存块。


10. 日志系统

Nginx 日志系统也高度模块化:

  • access_log, error_log

  • 格式化配置灵活:log_format

  • 支持异步写入、缓存 flush、缓冲池等

  • 每个请求独立生成 ngx_log_t 对象


11. Nginx 底层架构图示

         ┌────────────────────┐│    Master 进程      │└────────────────────┘│┌────────────┴────────────┐▼                         ▼
┌─────────────┐         ┌─────────────┐
│ Worker 进程 │  ...    │ Worker 进程 │
└─────────────┘         └─────────────┘│ epoll / kqueue / IOCP▼
┌──────────────────────────────────────┐
│       Reactor 模型:事件循环         │
├──────────────────────────────────────┤
│ Connection Pool + 内存池 + 模块链    │
├──────────────────────────────────────┤
│ HTTP / TCP 模块处理,输出响应        │
└──────────────────────────────────────┘

12. 小结

关键模块技术点
高性能异步非阻塞 IO,sendfile
高并发多 worker,事件驱动
模块化所有功能模块驱动
内存管理内存池、连接池
高扩展性插件化模块架构

二、Nginx配置详解并结合使用场景深入分析

1. 主配置(全局配置块)

主配置一般出现在 nginx.conf 的最上层,用于控制整个服务器级别的行为。

常见配置项:

配置项含义和作用
user指定 worker 子进程运行的系统用户
worker_processes启动的 worker 数量,建议设置为 CPU 核心数
worker_cpu_affinity绑定 CPU,提高性能(用于多核)
error_log全局错误日志路径及级别(`debug
pid指定 pid 文件路径
worker_rlimit_nofile最大文件描述符限制

示例:

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

使用场景分析:

  • 高并发服务:建议 worker_processes 设置为 auto,根据 CPU 自动适配。

  • Debug 排查问题时:可以临时设置 error_logdebug


2. events 块配置(事件模型)

控制 Nginx 的事件处理机制,位于 nginx.confevents 块中。

常见配置项:

配置项含义和作用
worker_connections每个 worker 支持的最大连接数(非客户端连接)
use强制指定事件模型(如 epoll/kqueue)
multi_accept是否每次尽可能多接受新连接

示例:

events {use epoll;worker_connections 10240;
}

使用场景分析:

  • 高连接量网站:worker_connections * worker_processes 决定最大并发连接数。

  • 性能调优:使用 epollkqueue(操作系统支持前提下)可显著提升性能。


3. http 块配置(Web 服务核心)

这是 Nginx 配置中最重要的一部分,包含:

  • 虚拟主机配置(server

  • 路由与 location 规则

  • 缓存、代理、gzip 等模块

  • 日志、限速、连接控制等功能


4. server 块(虚拟主机配置)

一个 server 表示一个网站服务,可监听不同端口/域名。

常见配置项:

配置项含义和作用
listen指定监听的端口和地址
server_name指定虚拟主机域名
root指定 web 根目录
index默认首页文件
error_page自定义错误页

示例:

server {listen 80;server_name www.example.com;root /var/www/example;index index.html index.htm;error_page 404 /404.html;
}

使用场景分析:

  • 部署多个站点时,通过 server_namelisten 实现虚拟主机划分。

  • 多端口监听(如 80 和 443)可以写多个 server


5. location 块(请求路由匹配)

定义请求 URI 匹配规则和处理方式,是 HTTP 配置的核心。

匹配类型:

类型示例含义
精确匹配location = /foo严格等于 /foo 时生效
前缀匹配location /img/URI 以 /img/ 开头
正则匹配location ~ \.php$匹配以 .php 结尾的路径

示例:

location / {try_files $uri $uri/ =404;
}location /images/ {root /data;
}location ~ \.php$ {fastcgi_pass 127.0.0.1:9000;
}

使用场景分析:

  • 静态资源分流:不同类型资源设置不同缓存头、路径。

  • 正则匹配动态请求,如 PHP、API 等。


6. 反向代理(proxy)

用于将客户端请求转发到后端服务器,是 Nginx 的核心能力之一。

常见配置项:

配置项说明
proxy_pass设置代理后端地址
proxy_set_header设置请求头信息,传递客户端信息
proxy_connect_timeout连接后端超时时间
proxy_read_timeout读取响应超时时间
proxy_redirect修改后端跳转地址

示例:

location /api/ {proxy_pass http://backend_server/api/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;
}

使用场景分析:

  • 微服务网关:按路径路由不同服务。

  • 解决跨域问题:配合 add_header 设置 CORS。


7. 负载均衡配置(upstream)

Nginx 作为七层负载均衡器,可配置多台后端服务。

配置示例:

upstream backend {server 10.0.0.1:8080 weight=3;server 10.0.0.2:8080 max_fails=2 fail_timeout=30s;
}server {location / {proxy_pass http://backend;}
}

支持算法:

  • round-robin(默认)

  • least_conn

  • ip_hash

  • hash $request_uri consistent;(需第三方模块)

使用场景分析:

  • 动态后端多副本:如服务部署多个 pod 实例,使用 upstream 配置调度。

  • 实现后端故障自动摘除(max_fails, fail_timeout)。


8. 限流与连接控制

请求限速:

limit_req_zone $binary_remote_addr zone=req_limit:10m rate=1r/s;server {location /login/ {limit_req zone=req_limit burst=5;}
}

并发连接数限制:

limit_conn_zone $binary_remote_addr zone=addr:10m;server {location / {limit_conn addr 1;}
}

使用场景分析:

  • 防止暴力破解、接口刷爆:对登录、注册接口限速。

  • 限制单个 IP 并发连接,防止 DDoS。


9. 安全控制

拒绝某 IP:

deny 192.168.1.1;
allow 192.168.0.0/16;

强制 HTTPS:

server {listen 80;return 301 https://$host$request_uri;
}

设置头防御:

add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";

10. 缓存配置

静态资源缓存:

location ~* \.(jpg|png|gif|css|js)$ {expires 30d;access_log off;
}

反向代理缓存(proxy_cache):

proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache_zone:10m inactive=60m;location /api/ {proxy_cache cache_zone;proxy_pass http://backend;proxy_cache_valid 200 1h;
}

11. 日志配置

log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;

使用场景分析:

  • 业务分析:配合 ELK 分析用户行为。

  • 安全审计:统计恶意请求、慢请求等。


12. 常用变量(部分)

变量名含义
$remote_addr客户端 IP
$http_user_agent客户端 UA
$request_uri请求 URI
$host请求的 Host 头
$upstream_addr实际转发到的后端地址(proxy)

13. 小结:分类速查表

分类功能
主配置进程管理、日志、用户
eventsIO 模型、最大连接数
http/server网站配置、虚拟主机
location路由控制、反向代理、限速
upstream负载均衡、服务池
cache缓存目录、缓存策略
security黑名单、头安全、重定向
logging日志格式与存储路径

三、Nginx如何解决跨域问题

1. 什么是跨域?为什么会出现跨域问题?

1.1 浏览器的同源策略(Same-Origin Policy)

同源策略要求:只有协议、域名、端口都相同,才能互相访问资源

http://example.com:80/api/user ✅
http://example.com:8080/api/user ❌ (端口不同)
https://example.com/api/user ❌ (协议不同)
http://other.com/api/user ❌ (域名不同)

1.2 跨域行为触发场景

当以下前端行为访问非同源资源时,会触发跨域限制:

  • 使用 XMLHttpRequest, fetch, axios 发起请求

  • 请求类型为非简单请求(如 PUT, DELETE, application/json

  • 请求带有自定义头(如 Authorization

  • 页面中嵌入 <iframe><img><script> 等外部域资源


2. 跨域类型与浏览器行为

2.1 简单请求

满足以下条件被认为是“简单请求”:

  • 方法为 GET / POST / HEAD

  • 请求头不超出:

    • Accept, Accept-Language, Content-Language, Content-Type(必须是表单类型)

  • 不带 Authorization、自定义 headers 等

浏览器行为:

直接发请求 + 检查响应头是否包含允许跨域的信息(如 Access-Control-Allow-Origin


2.2 非简单请求(复杂请求)

如:

axios.post("http://api.server.com/data", data, {headers: { "Content-Type": "application/json" },
});

浏览器行为:

  1. 先发一条 OPTIONS 请求(预检请求,Preflight)

  2. 服务端必须响应对应的 CORS 头信息

  3. 如果 OPTIONS 返回成功,再发真正的业务请求


3. Nginx 解决跨域的原理与配置

Nginx 本身不受跨域限制(因为它不是浏览器),但它可以作为中间层,通过添加 CORS 响应头或做代理来解决跨域。


4. Nginx 解决跨域的两种方式


方式一:添加 CORS 响应头(推荐)

场景:前端直接请求后端 API(后端已部署在 Nginx 上)

原理

添加以下 HTTP 响应头,使浏览器信任该请求的跨源访问:

Header 名称说明
Access-Control-Allow-Origin允许的跨域源(* 或具体域名)
Access-Control-Allow-Methods允许的请求方法(如 GET,POST,PUT
Access-Control-Allow-Headers允许的请求头(如 Authorization
Access-Control-Allow-Credentials是否允许携带 Cookie(需具体域名,不能 *
Access-Control-Max-Age预检请求缓存时间(秒)
Nginx 配置示例:
server {listen 80;server_name api.example.com;location /api/ {add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods GET,POST,OPTIONS;add_header Access-Control-Allow-Headers Authorization,Content-Type;if ($request_method = OPTIONS ) {add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods GET,POST,OPTIONS;add_header Access-Control-Allow-Headers Authorization,Content-Type;add_header Content-Length 0;add_header Content-Type text/plain;return 204;}proxy_pass http://backend_server;}
}
注意事项:
  • 如果前端要带 cookie,Access-Control-Allow-Origin 不能是 *,必须指定具体域名,且加上:

add_header Access-Control-Allow-Credentials true;

方式二:通过 Nginx 反向代理解决跨域

场景:前端请求相同源的 Nginx,Nginx 再转发请求至后端不同源

这种方式从浏览器的角度看“没有跨域”,因为访问的地址始终是前端部署在同源的 Nginx。

原理

通过 Nginx 配置,将 /api/* 的请求转发到后端真实地址:

server {listen 80;server_name frontend.example.com;location /api/ {proxy_pass http://backend.example.com/;proxy_set_header Host $host;}
}

前端请求示例:

axios.get("/api/user");
  • 前端以为在请求本域 /api/user(不触发 CORS)

  • 实际 Nginx 代理到 http://backend.example.com/user

✅ 这种方案彻底绕开浏览器同源限制,适用于内网 API 服务或多服务聚合。


5. 浏览器跨域判断原理总结

请求行为浏览器做什么服务端需要响应什么
简单请求直接发请求返回 Access-Control-Allow-Origin
非简单请求先发预检(OPTIONS),再发正式请求返回 Access-Control-Allow-Origin、Methods、Headers 等
withCredentials跨域携带 Cookie响应头中 Allow-Origin 不能是 * 且加 Allow-Credentials:true

6. 实践场景推荐方案

场景推荐方式是否支持 Cookie
前端直连后端 API(已配置 CORS)添加 CORS 响应头
前端请求同域 Nginx,由其反代后端反向代理
多服务统一网关接口聚合网关反向代理统一出口
后端无法配置 CORS(第三方 API)通过 Nginx 转发或服务中转

7. 常见错误与排查建议

错误描述可能原因
No 'Access-Control-Allow-Origin'未设置 CORS 响应头或设置不正确
OPTIONS 请求返回 404/405后端或 Nginx 未正确处理预检请求
cookie 不生效使用了 * 而非具体域名;未设置 withCredentials
Access-Control-Allow-Headers 缺失设置了自定义头,但未在响应中声明允许

8. 补充:后端语言设置 CORS 的方式(参考)

后端语言配置方式(示意)
Java (Spring Boot)@CrossOrigin 或 CORS Filter
Node.js (Express)cors 中间件
Python Flaskflask-cors
PHPheader('Access-Control-Allow-Origin: *')

9. 小结

项目原理Nginx 做法
跨域限制同源策略,浏览器拦截非同源请求添加 CORS 响应头 or 使用反向代理绕开
简单请求直接发请求,校验响应头添加 Access-Control-Allow-Origin
非简单请求发起预检(OPTIONS)再请求对 OPTIONS 请求添加响应并返回 204
带 Cookie需指定域名 + Allow-Credentials: trueNginx 配置中同时设置域名和 credentials

四、Nginx令牌桶限流

令牌桶(Token Bucket)算法是一种用于 限流(Rate Limiting) 的核心算法,广泛用于:

  • 接口限流(如 Nginx、网关、API Server)

  • 网络通信(如路由器 QoS)

  • 服务熔断和拒绝策略(如 Sentinel、Envoy)

1. 令牌桶算法的核心思想

✅ 定义

令牌桶算法通过以固定速率往桶中放令牌(token),请求来临时从桶中取令牌,只有成功取到令牌的请求才被允许执行。


✅ 模型图解:

+------------------+       请求到达       +--------------------+
| 令牌定时器       |--------------------->| 尝试从桶中取一个令牌 |
| 每隔 T 毫秒放 1 个 |                    |   若取成功 => 通过    |
| 令牌到桶中       |                     |   否则 => 拒绝/等待  |
+------------------+                     +--------------------+

2. 核心参数

参数含义
rate(速率)每秒生成多少个令牌(如 10 token/sec)
capacity(桶大小)桶中最多容纳多少令牌(避免 burst 时过载)
tokens当前桶中实际令牌数量
lastRefillTime上次放令牌的时间,用于计算应补充多少令牌

3. 请求流程(标准流程)

每当有一个请求到来:

  1. 刷新令牌数量:根据当前时间 - lastRefillTime 计算该放入多少令牌。

  2. 更新令牌数:桶中现有令牌数 = min(旧令牌 + 补充数, capacity)

  3. 检查令牌是否足够

    • 有令牌:取一个令牌,允许通过

    • 无令牌:请求被限流(丢弃/等待/排队等策略)


4. 代码实现(简化版本,Java 示例)

class TokenBucket {private final int capacity;private final int rate;private double tokens;private long lastRefillTimestamp;public TokenBucket(int capacity, int rate) {this.capacity = capacity;this.rate = rate;this.tokens = capacity;this.lastRefillTimestamp = System.currentTimeMillis();}public synchronized boolean allowRequest() {long now = System.currentTimeMillis();long deltaTime = now - lastRefillTimestamp;// 计算该生成多少新令牌double newTokens = deltaTime * rate / 1000.0;tokens = Math.min(capacity, tokens + newTokens);lastRefillTimestamp = now;if (tokens >= 1) {tokens -= 1;return true;} else {return false;}}
}

5. 与漏桶算法的对比

项目令牌桶 Token Bucket漏桶 Leaky Bucket
控流方式请求需要令牌,按速率放令牌请求入队,队列以固定速率“漏出”
允许突发请求✅(桶内有余令牌)❌(请求被固定速率漏出)
限制速率平均速率受限,最大速率受桶容量限制严格平滑速率输出
典型用途Nginx 限流、API 限流、Redis 哨兵视频流输出、网络 QoS

6. 令牌桶的使用场景分析

1. Nginx 限流(使用漏桶 + 令牌桶思想)

limit_req_zone $binary_remote_addr zone=req_limit:10m rate=5r/s;location /api/ {limit_req zone=req_limit burst=10 nodelay;
}
  • rate=5r/s:速率 = 5 个令牌/秒

  • burst=10:桶容量 = 10,允许突发 10 次

  • nodelay:有令牌立即放行(令牌桶特性)

本质是令牌桶思想:按速率补充令牌,有余量可突发请求。


2. 微服务 API 接口限流(如 Sentinel)

// 每秒最多允许 100 个请求
RateLimiter limiter = RateLimiter.create(100); // Guava 实现的令牌桶if (limiter.tryAcquire()) {// 执行请求逻辑
} else {// 拒绝或降级
}

7. 常见扩展策略

1. 令牌时间过期控制

  • 可以为每个 token 附加 TTL,避免长时间积累失控

2. 按 IP/接口限流

  • key = client_ipkey = user_id + path,每个维度单独维护一个桶

3. 集群令牌桶

  • 分布式系统中,常结合 Redis 实现分布式令牌桶


8. 图解理解令牌桶

⏳ 时间轴演示(假设速率 5 r/s,容量 10)

t = 0s    tokens = 10 (满)
t = 0.2s  请求1来 => ✅
t = 0.4s  请求2来 => ✅
...
t = 1s    tokens += 5
t = 1.2s  请求10来 => ✅(用完 token)
t = 1.3s  请求11来 => ❌(没令牌)

9. 总结

关键点说明
控制平均速率固定速率补充令牌,控制长期请求平均速率
支持突发流量桶内积累的令牌可以一次性消耗,支持短时间高并发
高性能易实现时间窗口 + 数学补偿,无需复杂调度器
使用广泛应用于网关、限流器、API 请求控制、DDOS 防护等

相关文章:

  • 男的和女的做那个视频网站抖音怎么推广
  • 顺德公司网站制作惠州seo管理
  • 建设银行泰安分行网站市场推广
  • 100m做电影网站东莞网站设计
  • 做推广用那个网站吗宁波seo快速优化教程
  • 温州 网站优化株洲seo排名
  • Ubuntu下布署mediasoup-demo
  • 【LLM安全】MCP(模型上下文协议)及其关键漏洞、技术细节
  • VUE3入门很简单(2)--- 计算属性
  • 力扣网C语言编程题:搜索二维矩阵的普通解法与二分查找法
  • 面试150 文本左右对齐
  • 用Dockerfile点亮你的容器化世界:从零到精通
  • 基于定制开发开源AI智能名片S2B2C商城小程序源码的H5游戏开发模式创新研究
  • 【音视频】Ubuntu下配置ffmpeg库
  • 网络路由策略与过滤策略原理及实验脚本
  • 【零基础学AI】 第6讲:数据可视化基础
  • 【STM32】[特殊字符] WWDG(窗口看门狗)学习笔记
  • 【unitrix】 4.7 库数字取反(not.rs)
  • Vue 3 高级编程技巧
  • 《天行数据查询系统项目介绍》
  • 2025.6.26总结
  • 云原生 Cloud Native
  • uniapp打包ios和苹果应用安装/上架详细指南
  • MySQL (二):范式设计
  • LeetCode 2302.统计得分小于K的子数组数目
  • 基于 Faker 生成测试数据:user_agent、日期、人名等