Nginx 的架构本质 Nginx 的高性能不是偶然的,而是基于三个核心架构设计:
事件驱动的异步非阻塞模型 :一个 worker 进程用 epoll 处理数万并发连接,不需要为每个连接创建线程
多进程 + 单线程 worker :master 进程管理 worker,worker 进程单线程处理请求,避免锁竞争
请求处理阶段化 :把请求处理分成 11 个阶段(POST_READ、SERVER_REWRITE、FIND_CONFIG、REWRITE、POST_REWRITE、PREACCESS、ACCESS、POST_ACCESS、PRECONTENT、CONTENT、LOG),每个模块可以在不同阶段介入
理解 Nginx 的关键是理解它为什么快 ——不是因为它用了什么黑科技,而是因为它避免了传统 Web 服务器(Apache prefork)的性能杀手:线程/进程创建开销、上下文切换、锁竞争、阻塞 IO。
事件驱动模型深度解析 worker 进程的工作循环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 while (true) { // 1. 处理事件(epoll_wait 返回的就绪事件) events = epoll_wait(epfd, event_list, max_events, timeout); // 2. 逐个处理事件 for each event in events: if (event is new connection): accept() → 创建新连接 → 注册到 epoll if (event is readable): 读取请求 → 处理 → 生成响应 if (event is writable): 发送响应数据 if (event is timer): 处理超时事件 // 3. 处理定时器(红黑树管理的定时器) expire_timers(); }
关键:worker 进程永远不会阻塞——所有 IO 都是非阻塞的,等待 IO 时可以处理其他连接。这就是为什么一个 worker 能处理数万并发连接。
epoll 的优势 Nginx 在 Linux 上使用 epoll 作为事件通知机制。相比传统的 select/poll:
select :最多 1024 个文件描述符,每次调用都要拷贝整个 fd 集合,O(n) 遍历
poll :没有 1024 限制,但仍然是 O(n) 遍历
epoll :用红黑树管理 fd,就绪事件用链表存储,O(1) 插入/删除,只返回就绪事件,不需要遍历所有 fd
epoll 的两个模式:
LT(Level Triggered,水平触发) :只要 fd 就绪,每次 epoll_wait 都会返回。Nginx 默认用 LT,更安全
ET(Edge Triggered,边缘触发) :只在状态变化时返回一次。性能更好,但需要一次性读完所有数据,否则可能丢失事件
惊群问题与解决 当多个 worker 进程都在监听同一个端口时,新连接到来会唤醒所有 worker(惊群),但只有一个能 accept 成功,其他被无谓唤醒。
Nginx 的解决:
accept_mutex (旧方案):worker 进程竞争一个互斥锁,只有拿到锁的 worker 才把监听 fd 加入 epoll
SO_REUSEPORT (新方案,Linux 3.9+):内核层面的负载均衡,每个 worker 绑定同一个端口,内核自动把连接分配给不同的 worker。性能更好,已成为默认
性能调优的层次 第一层:worker 进程与连接 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 worker_processes auto;worker_cpu_affinity auto;worker_rlimit_nofile 65535 ;events { worker_connections 10240 ; use epoll ; multi_accept on ; }
最大并发连接数 = worker_processes × worker_connections。但实际能支撑的并发还受限于文件描述符限制和内存。
第二层:内核参数调优 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 fs.file-max = 1000000 net.core.somaxconn = 65535 net.core.netdev_max_backlog = 65535 net.core.rmem_default = 262144 net.core.rmem_max = 16777216 net.core.wmem_default = 262144 net.core.wmem_max = 16777216 net.ipv4.tcp_max_syn_backlog = 65535 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_tw_reuse = 1 net.ipv4.ip_local_port_range = 1024 65535 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216 net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_slow_start_after_idle = 0 net.core.default_qdisc = fq net.ipv4.tcp_congestion_control = bbr
1 2 3 4 5 6 sysctl -p * soft nofile 65535 * hard nofile 65535
第三层:HTTP 优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 http { sendfile on ; tcp_nopush on ; tcp_nodelay on ; keepalive_timeout 65 ; keepalive_requests 1000 ; client_header_timeout 10s ; client_body_timeout 10s ; send_timeout 10s ; client_max_body_size 50m ; server_names_hash_bucket_size 64 ; server_names_hash_max_size 2048 ; include /etc/nginx/mime.types; default_type application/octet-stream; }
第四层:gzip / Brotli 压缩 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 http { gzip on ; gzip_vary on ; gzip_proxied any; gzip_comp_level 6 ; gzip_min_length 1024 ; gzip_buffers 16 8k ; gzip_http_version 1 .1 ; gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml application/rss+xml image/svg+xml font/ttf font/otf; }
第五层:静态资源缓存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 server { location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ { expires 30d ; add_header Cache-Control "public, immutable" ; access_log off ; } location ~* \.(css|js)$ { expires 7d ; add_header Cache-Control "public, immutable" ; access_log off ; } location ~* \.(woff|woff2|ttf|otf|eot)$ { expires 30d ; add_header Cache-Control "public, immutable" ; access_log off ; } location ~* \.html$ { add_header Cache-Control "no-cache, no-store, must-revalidate" ; } }
第六层:代理优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 http { upstream backend { least_conn; 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 10.0.0.3:8080 backup; keepalive 32 ; keepalive_timeout 60s ; keepalive_requests 1000 ; } server { location / { proxy_pass http://backend; proxy_http_version 1 .1 ; proxy_set_header Connection "" ; 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 ; proxy_connect_timeout 5s ; proxy_send_timeout 30s ; proxy_read_timeout 60s ; proxy_buffering on ; proxy_buffer_size 4k ; proxy_buffers 8 4k ; proxy_busy_buffers_size 8k ; proxy_next_upstream error timeout http_500 http_502 http_503; proxy_next_upstream_tries 2 ; } } }
第七层:SSL/TLS 优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 server { listen 443 ssl http2; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3 ; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off ; ssl_session_cache shared:SSL:10m ; ssl_session_timeout 1d ; ssl_session_tickets off ; ssl_stapling on ; ssl_stapling_verify on ; resolver 8.8.8.8 1.1.1.1 valid=300s ; resolver_timeout 5s ; ssl_ecdh_curve X25519:prime256v1:secp384r1; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; }
高级功能 1. 限流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 http { limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_conn_zone $binary_remote_addr zone=conn_limit:10m ; server { location /api/ { limit_req zone=req_limit burst=20 nodelay; limit_conn conn_limit 20 ; } } }
2. 访问控制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 server { location /admin/ { allow 10.0.0.0 /8 ; allow 192.168.0.0 /16 ; deny all; } location /protected/ { auth_basic "Restricted" ; auth_basic_user_file /etc/nginx/.htpasswd; } }
3. 缓存代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 / { proxy_pass http://backend; proxy_cache my_cache; proxy_cache_valid 200 10m ; proxy_cache_valid 404 1m ; proxy_cache_use_stale error timeout updating http_500 http_502 http_503; proxy_cache_lock on ; add_header X-Cache-Status $upstream_cache_status ; } } }
4. WebSocket 代理 1 2 3 4 5 6 7 8 9 10 server { location /ws/ { proxy_pass http://backend; proxy_http_version 1 .1 ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection "upgrade" ; proxy_read_timeout 86400 ; proxy_send_timeout 86400 ; } }
性能监控与诊断 1. stub_status 模块 1 2 3 4 5 6 7 8 server { location /nginx_status { stub_status on ; access_log off ; allow 127.0.0.1 ; deny all; } }
输出:
1 2 3 4 Active connections: 1234 server accepts handled requests 56789 56789 123456 Reading: 10 Writing: 20 Waiting: 1204
Active connections:当前活跃连接数
accepts:总接受连接数
handled:总处理连接数
requests:总请求数
Reading:正在读取请求头的连接
Writing:正在发送响应的连接
Waiting:保持长连接等待请求的连接
2. 关键指标监控
QPS(每秒请求数) :requests 差值 / 时间
并发连接数 :Active connections
连接队列 :ss -lnt 中 Recv-Q 列
错误率 :5xx 响应占比
响应时间 :上游响应时间($upstream_response_time)
带宽 :网络接口流量
3. 日志优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 http { log_format detailed '$remote_addr - $remote_user [$time_local ] ' '"$request " $status $body_bytes_sent ' '"$http_referer " "$http_user_agent " ' 'rt=$request_time uct="$upstream_connect_time " ' 'uht="$upstream_header_time " urt="$upstream_response_time "' ; access_log /var/log/nginx/access.log detailed; location ~* \.(jpg|png|css|js)$ { access_log off ; } }
常见性能问题排查 1. 高 CPU 使用率
检查 worker_processes 是否等于 CPU 核心数
用 perf 火焰图分析 CPU 时间花在哪里
检查是否有过多的正则匹配(location 配置)
检查 SSL 握手开销(是否启用了会话缓存)
2. 高内存使用率
检查 worker_connections 是否过大(每个连接约占 10KB 内存)
检查 proxy_buffer_size / proxy_buffers 是否过大
检查缓存(proxy_cache)是否占用过多
检查是否有内存泄漏(长时间运行后内存持续增长)
3. 高延迟
检查上游响应时间($upstream_response_time)
检查网络延迟(ping、mtr)
检查 DNS 解析时间(resolver 配置)
检查 SSL 握手时间(是否启用了 OCSP Stapling、会话缓存)
检查是否有磁盘 IO 瓶颈(静态文件读取)
4. 连接数打满
检查 worker_connections 是否足够
检查文件描述符限制(ulimit -n)
检查 keepalive_timeout 是否过长(长连接占用)
检查是否有慢客户端(发送/接收数据很慢,占用连接)
Nginx 与其他 Web 服务器对比
特性
Nginx
Apache (event MPM)
Caddy
架构
事件驱动,异步非阻塞
事件驱动,多线程
事件驱动,Go 协程
静态文件
极快
快
快
动态内容
需反向代理
可直接处理(mod_php)
需反向代理
配置
复杂但灵活
复杂
简单(自动 HTTPS)
模块
需编译时加载
运行时加载
Go 插件
社区
最大
大
增长中
总结 Nginx 的高性能源于其事件驱动的异步非阻塞架构、多进程单线程 worker 设计、以及请求处理的阶段化模型。性能调优是一个系统性工程,需要从七个层次入手:worker 进程配置、内核参数、HTTP 优化、压缩、缓存、代理优化、SSL 优化。
调优的关键是先找到瓶颈,再有针对性地调参数 。不要盲目复制网上的”最优配置”——不同的场景(静态文件、反向代理、API 网关、CDN 节点)有不同的最优配置。用数据说话,用监控验证,才能找到真正适合自己的配置。
Nginx 是一个功能极其丰富的 Web 服务器,本文覆盖了性能调优的核心内容,但还有很多高级功能(Lua 脚本、WAF、流量镜像、A/B 测试等)值得深入学习。掌握 Nginx 的原理和调优方法,是每个运维和后端开发者的必备技能。