Nginx 高併發設定與效能優化實戰
Nginx 高併發:從架構到實戰
Nginx 憑藉事件驅動、非阻塞 I/O 架構,單機即可支撐數萬併發連線。但預設設定遠未發揮其潛力,需要針對業務場景深度調優。
| 優化維度 | 關鍵參數 | 影響範圍 |
|---|---|---|
| 行程模型 | worker_processes, worker_connections | 併發承載能力 |
| 事件模型 | use epoll, multi_accept | 事件處理效率 |
| 負載均衡 | upstream, proxy_next_upstream | 流量分發與容錯 |
| 緩衝與超時 | proxy_buffers, keepalive_timeout | 記憶體與連線復用 |
| 壓縮 | gzip, gzip_comp_level | 傳輸頻寬 |
| 安全 | limit_req, limit_conn | 流量防護 |
一、Nginx 架構:事件驅動與 Worker 行程
Master-Worker 模型
Nginx 採用 Master-Worker 多行程架構:
- Master 行程:讀取設定、綁定埠、管理 Worker(fork/訊號/重啟)
- Worker 行程:獨立處理請求,互不干擾,一個 Worker 崩潰不影響其他
# 檢視 Nginx 行程結構
# ps aux | grep nginx
# root 1234 nginx: master process
# www-data 1235 nginx: worker process
# www-data 1236 nginx: worker process
事件驅動模型
Nginx 基於 Reactor 模式,使用 I/O 多路復用技術:
| I/O 模型 | 平台 | 效能 |
|---|---|---|
epoll |
Linux | 最優,O(1) 事件通知 |
kqueue |
FreeBSD/macOS | 優秀,類似 epoll |
select |
通用 | 較差,fd_set 上限 1024 |
poll |
通用 | 一般,無上限但線性掃描 |
events {
use epoll;
worker_connections 65535;
multi_accept on;
accept_mutex off;
}
multi_accept on讓 Worker 一次接受所有新連線,減少系統呼叫次數。accept_mutex off在高併發下避免驚群效應(Linux 3.9+ 核心已支援SO_REUSEPORT)。
二、核心併發設定
worker_processes
# 自動偵測 CPU 核心數(建議)
worker_processes auto;
# 或手動指定(通常等於 CPU 核心數或其 2 倍)
worker_processes 8;
調優建議:
- 一般設為
auto,與 CPU 核心數一致 - CPU 密集型場景(SSL、gzip)可設為核心數
- I/O 密集型場景可適當增至 2 倍核心數
worker_connections
events {
worker_connections 65535;
}
最大併發連線數 = worker_processes × worker_connections。需同步調整系統檔案描述符限制:
# 暫時修改
ulimit -n 65535
# 永久修改(/etc/security/limits.conf)
* soft nofile 65535
* hard nofile 65535
worker_rlimit_nofile
# Worker 行程最大檔案描述符數
worker_rlimit_nofile 65535;
完整基礎設定
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 65535;
multi_accept on;
accept_mutex off;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
}
三、負載均衡演算法詳解
基本設定
upstream backend {
server 10.0.0.1:8080 weight=5;
server 10.0.0.2:8080 weight=3;
server 10.0.0.3:8080 weight=2;
server 10.0.0.4:8080 backup;
}
五種排程演算法對比
| 演算法 | 指令 | 特點 | 適用場景 |
|---|---|---|---|
| 輪詢 | (預設) | 依序分配,均勻 | 後端效能一致 |
| 加權輪詢 | weight=N |
按權重比例分配 | 後端效能差異 |
| 最少連線 | least_conn |
優先分配給連線數最少的伺服器 | 長連線/請求耗時差異大 |
| IP 雜湊 | ip_hash |
同一 IP 固定分配到同一伺服器 | 需要工作階段保持 |
| 隨機 | random |
隨機選擇 | 無狀態服務 |
| 一致性雜湊 | hash $key consistent |
一致性雜湊環 | 快取伺服器 |
least_conn 設定
upstream api_backend {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
ip_hash 設定
upstream web_backend {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
注意:
ip_hash不支援backup和weight。正式環境建議使用一致性雜湊替代。
一致性雜湊設定
upstream cache_backend {
hash $request_uri consistent;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
四、Upstream 健康檢查
被動健康檢查(內建)
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 10.0.0.3:8080 max_fails=3 fail_timeout=30s;
}
| 參數 | 含義 | 預設值 |
|---|---|---|
max_fails |
失敗次數閾值,超過後標記為不可用 | 1 |
fail_timeout |
標記不可用持續時間 | 10s |
主動健康檢查(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 /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
proxy_next_upstream 容錯
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 3;
五、緩衝與超時調優
Proxy 緩衝
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
| 參數 | 含義 | 建議值 |
|---|---|---|
proxy_buffer_size |
回應標頭緩衝區大小 | 4k-8k |
proxy_buffers |
回應主體緩衝區數量和大小 | 8 16k |
proxy_busy_buffers_size |
忙時緩衝區大小 | proxy_buffers 總大小的一半 |
超時設定
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 30s;
client_body_timeout 12s;
client_header_timeout 12s;
send_timeout 10s;
keepalive_timeout 65s;
keepalive_requests 100;
Upstream Keepalive 連線池
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
keepalive 32;
keepalive_requests 100;
keepalive_timeout 60s;
}
server {
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://backend;
}
}
keepalive 32表示每個 Worker 與後端保持 32 個閒置長連線,避免頻繁 TCP 握手。
六、Gzip 壓縮優化
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_http_version 1.1;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss
application/vnd.ms-fontobject
application/x-font-ttf
font/opentype
image/svg+xml;
gzip_buffers 16 8k;
gzip_disable "msie6";
| 參數 | 說明 | 建議值 |
|---|---|---|
gzip_comp_level |
壓縮級別 1-9 | 4-6(CPU 與壓縮率平衡) |
gzip_min_length |
最小壓縮長度 | 1024(小檔案壓縮反而增大) |
gzip_types |
壓縮的 MIME 類型 | 按需新增,不含圖片 |
gzip_buffers |
壓縮緩衝區 | 16 8k |
七、靜態檔案服務與快取
靜態檔案優化
server {
listen 80;
server_name static.example.com;
root /var/www/static;
location / {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
expires 30d;
add_header Cache-Control "public, immutable";
}
location ~* \.(js|css)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
}
open_file_cache 說明
| 參數 | 含義 |
|---|---|
max=N |
快取最大檔案描述符數 |
inactive=T |
快取存活時間 |
valid=T |
檢查快取有效性的間隔 |
min_uses=N |
在 inactive 時間內最少存取次數 |
errors |
是否快取檔案查找錯誤 |
八、SSL/TLS 效能優化
Session 快取
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
shared:SSL:10m表示所有 Worker 共享 10MB 的 Session 快取,約可快取 40000 個工作階段。
OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
完整 SSL 設定
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
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 on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
ssl_buffer_size 4k;
}
九、限流與防護
請求速率限制(limit_req)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
server {
location /api/ {
limit_req zone=api_limit burst=200 nodelay;
proxy_pass http://backend;
}
}
| 參數 | 含義 |
|---|---|
rate=100r/s |
每個 IP 每秒 100 個請求 |
burst=200 |
允許突發 200 個請求 |
nodelay |
突發請求不延遲,超過直接拒絕 |
併發連線數限制(limit_conn)
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
limit_conn conn_limit 50;
proxy_pass http://backend;
}
}
頻寬限制
location /download/ {
limit_rate 500k;
limit_rate_after 10m;
}
下載前 10MB 不限速,之後限速 500KB/s。
十、反向代理設定
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://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;
proxy_redirect off;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
}
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;
}
}
十一、常見錯誤排查
502 Bad Gateway
原因:Nginx 無法連線到後端服務。
# 檢查後端服務是否運行
curl -I http://10.0.0.1:8080/health
# 檢查 Nginx 錯誤日誌
tail -f /var/log/nginx/error.log | grep 502
# 常見原因
# 1. 後端服務未啟動或崩潰
# 2. 後端埠設定錯誤
# 3. 後端負載過高拒絕連線
# 4. SELinux/防火牆阻斷
504 Gateway Timeout
原因:後端服務回應超時。
# 增大超時時間
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
# 排查步驟
# 1. 檢查後端回應時間
curl -o /dev/null -s -w "time_total: %{time_total}\n" http://backend/api
# 2. 檢查後端日誌是否有慢查詢
# 3. 檢查網路延遲
ping -c 5 10.0.0.1
429 Too Many Requests
原因:觸發限流規則。
# 自訂限流回應
limit_req_status 429;
十二、安全加固
安全回應標頭
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
DDoS 防護
limit_req_zone $binary_remote_addr zone=ddos:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=ddos_conn:10m;
server {
limit_req zone=ddos burst=50 nodelay;
limit_conn ddos_conn 30;
client_body_buffer_size 16k;
client_max_body_size 1m;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
}
禁止敏感路徑
location ~ /\.(git|svn|env) {
deny all;
return 404;
}
location ~* /(wp-admin|phpmyadmin|adminer) {
deny all;
return 404;
}
十三、效能基準測試
wrk 壓測
# 安裝 wrk
git clone https://github.com/wg/wrk.git
cd wrk && make && sudo cp wrk /usr/local/bin/
# 基準測試(12 執行緒,400 連線,持續 30 秒)
wrk -t12 -c400 -d30s http://example.com/
# 帶延遲分佈
wrk -t12 -c400 -d30s --latency http://example.com/
# POST 請求測試
wrk -t4 -c200 -d10s -s post.lua http://example.com/api
ab 壓測
# 安裝 Apache Bench
# Ubuntu: apt install apache2-utils
# 基準測試(200 併發,10000 請求)
ab -n 10000 -c 200 http://example.com/
# 带 Keep-Alive
ab -n 10000 -c 200 -k http://example.com/
壓測結果分析
| 指標 | 含義 | 參考值 |
|---|---|---|
| Requests/sec | 每秒處理請求數 | 靜態資源 > 10000 |
| Latency (p99) | 99% 請求延遲 | < 100ms |
| Transfer/sec | 每秒傳輸資料量 | 看業務需求 |
| Socket errors | 連線錯誤數 | 應為 0 |
十四、FAQ
Q: worker_processes 設為 auto 後,Worker 數量不等於 CPU 核心數?
A: auto 會讀取 /proc/cpuinfo 中的可用核心數。如果容器中設定了 CPU 限額(cgroup),Nginx 1.19+ 才會感知 cgroup 限制。舊版本需手動指定。
Q: worker_connections 設為 65535 後,實際併發還是上不去?
A: 需同步修改系統限制:ulimit -n、net.core.somaxconn、net.ipv4.tcp_max_syn_backlog、fs.file-max。
Q: 負載均衡中 ip_hash 和一致性雜湊怎麼選?
A: ip_hash 簡單但不支援權重和 backup,擴縮容時大量工作階段遷移。一致性雜湊擴縮容只影響相鄰節點,推薦用於快取層。
Q: gzip_comp_level 設多少合適?
A: 4-6 是最佳區間。1-3 壓縮率低,7-9 CPU 開銷大但壓縮率提升微乎其微。實測 level 6 相比 level 9 壓縮率僅差 2-3%,但 CPU 多消耗 50%+。
Q: 如何監控 Nginx 即時狀態?
A: 開啟 stub_status 模組,搭配 Prometheus + Grafana 或 ngxtop 工具即時監控。
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Q: 如何優雅重啟 Nginx 不丟請求?
A: 使用 nginx -s reload,Master 會重新載入設定,啟動新 Worker,舊 Worker 處理完當前請求後退出。
實戰工具推薦:使用 /encode/base64 編碼設定檔案、/encode/hash 產生設定雜湊校驗、/json/format 格式化 Nginx JSON 日誌。
本站提供瀏覽器本地工具,免註冊即可試用 →