Nginx高性能配置:反向代理、負(fù)載均衡與緩存優(yōu)化
一、概述
1.1 背景介紹
Nginx 1.26.x 是當(dāng)前 mainline 分支的最新穩(wěn)定線(xiàn),在 HTTP/3 支持、動(dòng)態(tài)模塊加載和內(nèi)存管理上相比 1.24.x 有明顯改進(jìn)。1.24.x 已進(jìn)入維護(hù)模式,新項(xiàng)目直接選 1.26.x,舊項(xiàng)目建議在下次維護(hù)窗口升級(jí)。
在現(xiàn)代微服務(wù)架構(gòu)中,Nginx 承擔(dān)的角色已遠(yuǎn)超傳統(tǒng) Web 服務(wù)器。它是流量入口的第一道關(guān)卡:接收外部請(qǐng)求、終止 TLS、執(zhí)行負(fù)載均衡、緩存上游響應(yīng)、轉(zhuǎn)發(fā)到后端服務(wù)集群。一個(gè)配置不當(dāng)?shù)?Nginx 實(shí)例,即便后端服務(wù)性能再好,也會(huì)成為整個(gè)系統(tǒng)的瓶頸。
高性能配置的核心矛盾在于:默認(rèn)配置面向通用場(chǎng)景,而生產(chǎn)環(huán)境需要針對(duì)具體硬件、流量模式和業(yè)務(wù)特征做定向調(diào)優(yōu)。worker 進(jìn)程數(shù)、連接數(shù)上限、緩沖區(qū)大小、緩存策略——每一項(xiàng)參數(shù)背后都有對(duì)應(yīng)的系統(tǒng)資源約束,盲目調(diào)大不會(huì)帶來(lái)性能提升,反而可能引發(fā)內(nèi)存壓力或文件描述符耗盡。
1.2 技術(shù)特點(diǎn)
Nginx 采用事件驅(qū)動(dòng)的異步非阻塞架構(gòu),與 Apache 的 prefork/worker 多進(jìn)程模型有本質(zhì)區(qū)別:
事件驅(qū)動(dòng)模型:基于 epoll(Linux)/ kqueue(BSD),單個(gè) worker 進(jìn)程可同時(shí)處理數(shù)萬(wàn)并發(fā)連接,不依賴(lài)線(xiàn)程切換
異步非阻塞 I/O:磁盤(pán)讀寫(xiě)、網(wǎng)絡(luò) I/O 均不阻塞 worker 進(jìn)程,配合aio threads可將文件 I/O 卸載到線(xiàn)程池
低內(nèi)存占用:每個(gè)連接消耗約 10-20KB 內(nèi)存,10000 并發(fā)連接約占用 200MB,遠(yuǎn)低于線(xiàn)程模型
零拷貝傳輸:sendfile系統(tǒng)調(diào)用直接在內(nèi)核態(tài)完成文件到網(wǎng)絡(luò)的數(shù)據(jù)傳輸,繞過(guò)用戶(hù)態(tài)緩沖區(qū)
模塊化架構(gòu):核心功能精簡(jiǎn),通過(guò)編譯時(shí)模塊或動(dòng)態(tài)模塊擴(kuò)展,避免加載不必要的功能
1.3 適用場(chǎng)景
反向代理:將外部 HTTP/HTTPS 請(qǐng)求轉(zhuǎn)發(fā)到內(nèi)網(wǎng)應(yīng)用服務(wù)器,隱藏后端拓?fù)洌y(tǒng)一入口管理
負(fù)載均衡:在多個(gè)后端實(shí)例間分發(fā)流量,支持輪詢(xún)、加權(quán)、IP 哈希、最少連接等策略
靜態(tài)資源服務(wù):直接服務(wù) CSS/JS/圖片等靜態(tài)文件,性能遠(yuǎn)超應(yīng)用服務(wù)器
API 網(wǎng)關(guān):結(jié)合 Lua(OpenResty)或 njs 模塊實(shí)現(xiàn)認(rèn)證、限流、路由等網(wǎng)關(guān)功能
緩存加速:緩存上游響應(yīng),降低后端壓力,提升響應(yīng)速度
SSL 終止:集中處理 TLS 握手,后端服務(wù)使用明文 HTTP,簡(jiǎn)化證書(shū)管理
1.4 環(huán)境要求
| 組件 | 版本要求 | 說(shuō)明 |
|---|---|---|
| 操作系統(tǒng) | Ubuntu 22.04+ / CentOS Stream 8+ | CentOS 7 已 EOL,不建議新部署 |
| Nginx | 1.26.x mainline | 1.24.x stable 可用,1.22.x 及以下避免 |
| OpenSSL | 3.0+ | 支持 TLS 1.3,Ubuntu 22.04 默認(rèn)滿(mǎn)足 |
| CPU | 4核+ | worker 進(jìn)程數(shù)建議與物理核心數(shù)一致 |
| 內(nèi)存 | 4GB+ | 緩存配置需預(yù)留足夠內(nèi)存,建議 8GB+ |
| 磁盤(pán) | SSD,50GB+ | proxy_cache 路徑建議獨(dú)立掛載點(diǎn) |
二、詳細(xì)步驟
2.1 編譯安裝與基礎(chǔ)調(diào)優(yōu)
2.1.1 編譯參數(shù)選擇
包管理器安裝的 Nginx 通常缺少部分高性能模塊,生產(chǎn)環(huán)境建議從源碼編譯以獲得完整控制權(quán)。
# /opt/scripts/build-nginx.sh - Nginx 編譯安裝腳本 #!/bin/bash set-euo pipefail NGINX_VERSION="1.26.2" BUILD_DIR="/tmp/nginx-build" INSTALL_PREFIX="/etc/nginx" # 安裝編譯依賴(lài) apt-get install -y build-essential libpcre3-dev libssl-dev zlib1g-dev libgd-dev libgeoip-dev mkdir -p"${BUILD_DIR}" cd"${BUILD_DIR}" wget"http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" tar -xzf"nginx-${NGINX_VERSION}.tar.gz" cd"nginx-${NGINX_VERSION}" ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --with-threads # 啟用線(xiàn)程池,支持 aio threads --with-file-aio # 異步文件 I/O,大文件傳輸性能提升明顯 --with-http_v2_module # HTTP/2 支持 --with-http_v3_module # HTTP/3 / QUIC 支持(1.25.0+ 正式支持) --with-http_ssl_module --with-http_realip_module # 獲取真實(shí)客戶(hù)端 IP(CDN/代理場(chǎng)景必須) --with-http_stub_status_module # 監(jiān)控狀態(tài)頁(yè) --with-http_gzip_static_module # 預(yù)壓縮靜態(tài)文件,避免每次請(qǐng)求重復(fù)壓縮 --with-http_cache_purge_module # 緩存主動(dòng)清理(需第三方模塊) --with-stream # TCP/UDP 代理(數(shù)據(jù)庫(kù)代理、DNS 負(fù)載均衡) --with-stream_ssl_module --with-pcre-jit # PCRE JIT 加速正則匹配,location 規(guī)則多時(shí)效果顯著 --with-ld-opt="-Wl,-rpath,/usr/local/lib" make -j"$(nproc)" make install
2.1.2 worker 進(jìn)程與連接數(shù)配置
# /etc/nginx/nginx.conf - 主配置文件全局段
user nginx;
# auto 自動(dòng)檢測(cè) CPU 核心數(shù),等價(jià)于手動(dòng)寫(xiě)核心數(shù)
# 綁定 worker 到具體 CPU 核心可減少上下文切換,8核機(jī)器寫(xiě) auto
worker_processes auto;
worker_cpu_affinity auto;
# 單個(gè) worker 可打開(kāi)的最大文件描述符數(shù)
# 必須 >= worker_connections * 2(每個(gè)連接占用2個(gè)fd:客戶(hù)端+上游)
worker_rlimit_nofile 65536;
# 錯(cuò)誤日志級(jí)別:生產(chǎn)用 warn,調(diào)試用 debug(debug 會(huì)產(chǎn)生大量日志,影響性能)
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
# 動(dòng)態(tài)模塊加載(如需要)
load_module modules/ngx_http_geoip_module.so;
events {
# 單 worker 最大并發(fā)連接數(shù)
# 總并發(fā) = worker_processes * worker_connections
# 4核機(jī)器設(shè) 16384,總并發(fā)約 65536
worker_connections 16384;
# 使用 epoll(Linux 最高效的 I/O 多路復(fù)用)
use epoll;
# 允許 worker 一次性接受所有新連接,而非逐個(gè)接受
# 高并發(fā)場(chǎng)景下減少系統(tǒng)調(diào)用次數(shù),低流量場(chǎng)景意義不大
multi_accept on;
}
2.1.3 內(nèi)核參數(shù)調(diào)優(yōu)
Nginx 性能上限受內(nèi)核參數(shù)約束,應(yīng)用層配置再好也無(wú)法突破內(nèi)核限制。
# /etc/sysctl.d/99-nginx-tuning.conf - 內(nèi)核參數(shù)調(diào)優(yōu) # 修改后執(zhí)行 sysctl -p /etc/sysctl.d/99-nginx-tuning.conf 生效 # TCP 連接隊(duì)列長(zhǎng)度,默認(rèn) 128 遠(yuǎn)不夠用,高并發(fā)場(chǎng)景必須調(diào)大 net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 65535 # 允許 TIME_WAIT 狀態(tài)的 socket 被新連接復(fù)用 # 反向代理場(chǎng)景下大量短連接會(huì)產(chǎn)生 TIME_WAIT,不開(kāi)啟會(huì)導(dǎo)致端口耗盡 net.ipv4.tcp_tw_reuse = 1 # 系統(tǒng)最大文件描述符數(shù),必須大于 worker_rlimit_nofile * worker_processes fs.file-max = 1000000 # 網(wǎng)卡接收隊(duì)列長(zhǎng)度,10Gbps 網(wǎng)卡建議調(diào)大 net.core.netdev_max_backlog = 65535 # TCP 接收/發(fā)送緩沖區(qū),影響大文件傳輸和高延遲鏈路性能 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216 # 本地端口范圍,反向代理向上游發(fā)起連接時(shí)使用 # 默認(rèn) 32768-60999,約 28000 個(gè)端口,高并發(fā)場(chǎng)景可能不夠 net.ipv4.ip_local_port_range = 10000 65535
# 應(yīng)用內(nèi)核參數(shù)并驗(yàn)證 sysctl -p /etc/sysctl.d/99-nginx-tuning.conf # 驗(yàn)證關(guān)鍵參數(shù) sysctl net.core.somaxconn net.ipv4.tcp_tw_reuse fs.file-max # 設(shè)置系統(tǒng)級(jí)文件描述符限制(/etc/security/limits.conf) echo"nginx soft nofile 65536">> /etc/security/limits.conf echo"nginx hard nofile 65536">> /etc/security/limits.conf
2.2 反向代理配置
2.2.1 upstream 配置與健康檢查
# /etc/nginx/conf.d/upstream.conf - upstream 定義文件
upstream backend_api {
# keepalive 保持與上游的長(zhǎng)連接池,避免每次請(qǐng)求重新建立 TCP 連接
# 值為連接池中保持的空閑連接數(shù),不是最大連接數(shù)上限
# 后端是 HTTP/1.1 應(yīng)用時(shí),32-64 是合理起點(diǎn)
keepalive 64;
# keepalive_requests:?jiǎn)蝹€(gè)長(zhǎng)連接最多處理的請(qǐng)求數(shù),防止連接老化
keepalive_requests 1000;
# keepalive_timeout:空閑連接保持時(shí)間
keepalive_timeout 60s;
server 10.0.1.11:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.13:8080 weight=2 max_fails=3 fail_timeout=30s;
# backup 服務(wù)器:僅在所有主服務(wù)器不可用時(shí)啟用
server 10.0.1.14:8080 backup;
}
upstream backend_static {
# 靜態(tài)資源服務(wù)器,使用最少連接策略
least_conn;
keepalive 32;
server 10.0.1.21:80 weight=1;
server 10.0.1.22:80 weight=1;
}
2.2.2 proxy_pass 細(xì)節(jié)
proxy_pass 的 trailing slash 是最常見(jiàn)的配置錯(cuò)誤來(lái)源。proxy_pass http://backend/和proxy_pass http://backend行為完全不同:前者會(huì)截?cái)?location 前綴,后者保留完整 URI。
# /etc/nginx/conf.d/proxy-detail.conf
server {
listen 80;
server_name api.example.com;
location /api/ {
# 末尾有斜杠:/api/users -> http://backend/users(截?cái)?/api 前綴)
# 末尾無(wú)斜杠:/api/users -> http://backend/api/users(保留完整路徑)
proxy_pass http://backend_api/;
# 必須傳遞 Host,否則后端無(wú)法識(shí)別虛擬主機(jī)
proxy_set_header Host $host;
# 傳遞真實(shí)客戶(hù)端 IP,后端日志和業(yè)務(wù)邏輯依賴(lài)此值
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;
# 使用 HTTP/1.1 與上游通信,keepalive 必須配合此設(shè)置
proxy_http_version 1.1;
# 清除 Connection 頭,防止 keep-alive 信息傳遞到上游導(dǎo)致連接管理混亂
proxy_set_header Connection "";
# 連接超時(shí):Nginx 與上游建立 TCP 連接的超時(shí)時(shí)間
# 內(nèi)網(wǎng)服務(wù)設(shè) 5s 足夠,超過(guò)說(shuō)明上游有問(wèn)題
proxy_connect_timeout 5s;
# 讀取超時(shí):等待上游響應(yīng)的超時(shí)時(shí)間(兩次讀操作之間的間隔)
# 根據(jù)業(yè)務(wù)最慢接口設(shè)定,不是總響應(yīng)時(shí)間
proxy_read_timeout 60s;
# 發(fā)送超時(shí):向上游發(fā)送請(qǐng)求的超時(shí)時(shí)間
proxy_send_timeout 60s;
# 緩沖區(qū)配置:響應(yīng)先緩沖到 Nginx,再發(fā)給客戶(hù)端
# 關(guān)閉緩沖(proxy_buffering off)適合 SSE/流式響應(yīng)
proxy_buffering on;
proxy_buffer_size 16k; # 響應(yīng)頭緩沖區(qū),通常 4k-16k 足夠
proxy_buffers 8 32k; # 響應(yīng)體緩沖區(qū)數(shù)量和大小
proxy_busy_buffers_size 64k; # 同時(shí)向客戶(hù)端發(fā)送的最大緩沖量
}
}
2.2.3 WebSocket 代理與長(zhǎng)連接保持
# /etc/nginx/conf.d/websocket.conf
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
# 當(dāng)客戶(hù)端不發(fā)送 Upgrade 頭時(shí),Connection 設(shè)為 close
# 避免普通 HTTP 請(qǐng)求被錯(cuò)誤地保持為長(zhǎng)連接
}
server {
listen 443 ssl;
server_name ws.example.com;
location /ws/ {
proxy_pass http://backend_ws;
# WebSocket 升級(jí)握手必須的頭
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket 連接通常長(zhǎng)時(shí)間保持,讀取超時(shí)需要設(shè)長(zhǎng)
# 或設(shè)為 0(永不超時(shí)),但要配合心跳機(jī)制
proxy_read_timeout 3600s;
# 關(guān)閉緩沖,WebSocket 消息需要實(shí)時(shí)傳遞
proxy_buffering off;
}
}
2.2.4 gRPC 反向代理配置
# /etc/nginx/conf.d/grpc.conf
upstream grpc_backend {
server 10.0.1.11:50051;
server 10.0.1.12:50051;
keepalive 32;
}
server {
listen 443 ssl http2; # gRPC 依賴(lài) HTTP/2
server_name grpc.example.com;
ssl_certificate /etc/nginx/ssl/grpc.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/grpc.example.com.key;
location / {
# grpc_pass 替代 proxy_pass,專(zhuān)用于 gRPC 協(xié)議
grpc_pass grpc://grpc_backend;
# gRPC 錯(cuò)誤處理
error_page 502 = /error502grpc;
}
location = /error502grpc {
internal;
default_type application/grpc;
# gRPC 狀態(tài)碼:14 = UNAVAILABLE
add_header grpc-status 14;
add_header content-length 0;
return 204;
}
}
2.3 負(fù)載均衡策略
2.3.1 輪詢(xún)、加權(quán)輪詢(xún)與 ip_hash
# /etc/nginx/conf.d/lb-strategies.conf
# 默認(rèn)輪詢(xún):請(qǐng)求依次分發(fā)到每個(gè) server,適合無(wú)狀態(tài)服務(wù)
upstream rr_backend {
server 10.0.1.11:8080;
server 10.0.1.12:8080;
server 10.0.1.13:8080;
}
# 加權(quán)輪詢(xún):按 weight 比例分發(fā),適合服務(wù)器配置不均的場(chǎng)景
# 下例中 .11 處理 50% 流量,.12 和 .13 各處理 25%
upstream weighted_backend {
server 10.0.1.11:8080 weight=2;
server 10.0.1.12:8080 weight=1;
server 10.0.1.13:8080 weight=1;
}
# ip_hash:同一客戶(hù)端 IP 始終路由到同一后端
# 實(shí)現(xiàn)簡(jiǎn)單的會(huì)話(huà)保持,但存在熱點(diǎn)問(wèn)題(大量用戶(hù)來(lái)自同一 NAT IP)
# 不支持與 weight 同時(shí)使用(1.26.x 已支持,但行為需驗(yàn)證)
upstream iphash_backend {
ip_hash;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
server 10.0.1.13:8080;
}
2.3.2 least_conn 與一致性哈希
# /etc/nginx/conf.d/lb-advanced.conf # least_conn:將請(qǐng)求發(fā)送到當(dāng)前活躍連接數(shù)最少的 server # 適合請(qǐng)求處理時(shí)間差異大的場(chǎng)景(如混合快慢接口) # 比輪詢(xún)更能避免慢請(qǐng)求堆積在某個(gè) server 上 upstream leastconn_backend { least_conn; server 10.0.1.11:8080; server 10.0.1.12:8080; server 10.0.1.13:8080; keepalive 32; } # hash:基于自定義 key 的一致性哈希 # 適合緩存場(chǎng)景:相同 URL 始終路由到同一后端,提高后端緩存命中率 # consistent 參數(shù)啟用一致性哈希,server 增減時(shí)只有少量請(qǐng)求重新分配 upstream hash_backend { hash $request_uri consistent; server 10.0.1.11:8080; server 10.0.1.12:8080; server 10.0.1.13:8080; } # 基于請(qǐng)求頭的哈希(適合 API 網(wǎng)關(guān)按用戶(hù) ID 路由) upstream user_hash_backend { hash $http_x_user_id consistent; server 10.0.1.11:8080; server 10.0.1.12:8080; }
2.3.3 被動(dòng)健康檢查與主動(dòng)健康檢查
開(kāi)源版 Nginx 只支持被動(dòng)健康檢查(請(qǐng)求失敗后標(biāo)記 server 不可用),主動(dòng)健康檢查是商業(yè)版 Nginx Plus 的功能。開(kāi)源替代方案是nginx_upstream_check_module第三方模塊。
# /etc/nginx/conf.d/health-check.conf
upstream backend_with_check {
server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.13:8080 max_fails=3 fail_timeout=30s;
# max_fails:在 fail_timeout 時(shí)間窗口內(nèi),失敗次數(shù)達(dá)到此值則標(biāo)記為不可用
# fail_timeout:不可用狀態(tài)持續(xù)時(shí)間,同時(shí)也是統(tǒng)計(jì)失敗次數(shù)的時(shí)間窗口
# 上例:30秒內(nèi)失敗3次,則該 server 被下線(xiàn)30秒后重新嘗試
keepalive 32;
}
# 如果編譯了 nginx_upstream_check_module,可配置主動(dòng)健康檢查
# upstream backend_active_check {
# server 10.0.1.11:8080;
# server 10.0.1.12:8080;
# check interval=3000 rise=2 fall=3 timeout=1000 type=http;
# check_http_send "HEAD /health HTTP/1.0
";
# check_http_expect_alive http_2xx http_3xx;
# }
2.3.4 會(huì)話(huà)保持方案對(duì)比
| 方案 | 實(shí)現(xiàn)方式 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
|---|---|---|---|---|
| ip_hash | 客戶(hù)端 IP 哈希 | 配置簡(jiǎn)單,無(wú)需后端改造 | NAT 環(huán)境下負(fù)載不均,server 下線(xiàn)時(shí)會(huì)話(huà)丟失 | 小規(guī)模、無(wú) CDN 場(chǎng)景 |
| hash $cookie_session | Cookie 哈希 | 比 ip_hash 更精準(zhǔn) | 需要客戶(hù)端支持 Cookie | 有登錄態(tài)的 Web 應(yīng)用 |
| sticky cookie(Plus) | Nginx 注入 Cookie | 精確綁定,支持 server 下線(xiàn)遷移 | 商業(yè)版功能 | 企業(yè)級(jí)有狀態(tài)應(yīng)用 |
| 應(yīng)用層共享 Session | Redis/Memcached | 徹底無(wú)狀態(tài),水平擴(kuò)展 | 需要改造應(yīng)用代碼 | 推薦方案,新項(xiàng)目首選 |
2.4 緩存優(yōu)化
2.4.1 proxy_cache 配置
# /etc/nginx/nginx.conf - http 段緩存路徑定義
http {
# 緩存路徑配置
# levels=1:2:兩級(jí)目錄結(jié)構(gòu),避免單目錄文件過(guò)多影響文件系統(tǒng)性能
# keys_zone=cache_main:100m:共享內(nèi)存區(qū)名稱(chēng)和大小,100m 約存儲(chǔ) 80萬(wàn)個(gè) key
# max_size=10g:緩存文件總大小上限,超出時(shí) LRU 淘汰
# inactive=60m:60分鐘內(nèi)未被訪(fǎng)問(wèn)的緩存自動(dòng)刪除
# use_temp_path=off:直接寫(xiě)入緩存目錄,避免跨文件系統(tǒng) rename 操作
proxy_cache_path /data/nginx/cache
levels=1:2
keys_zone=cache_main:100m
max_size=10g
inactive=60m
use_temp_path=off;
# 第二個(gè)緩存區(qū),用于靜態(tài)資源(更大的 inactive 時(shí)間)
proxy_cache_path /data/nginx/cache_static
levels=1:2
keys_zone=cache_static:50m
max_size=20g
inactive=7d
use_temp_path=off;
}
2.4.2 緩存策略
# /etc/nginx/conf.d/cache-policy.conf
server {
listen 80;
server_name www.example.com;
# API 接口緩存
location /api/ {
proxy_pass http://backend_api/;
proxy_cache cache_main;
# 緩存 key 設(shè)計(jì):包含 scheme、host、URI 和查詢(xún)參數(shù)
# 如果接口有用戶(hù)態(tài),需要加入 Cookie 或 Authorization 頭
proxy_cache_key "$scheme$host$request_uri";
# 不同響應(yīng)碼的緩存時(shí)間
proxy_cache_valid 200 302 10m; # 成功響應(yīng)緩存10分鐘
proxy_cache_valid 404 1m; # 404 緩存1分鐘,防止穿透攻擊
proxy_cache_valid any 30s; # 其他響應(yīng)碼緩存30秒
# 繞過(guò)緩存的條件:有 Cookie 或特定請(qǐng)求頭時(shí)不使用緩存
# $cookie_session 非空時(shí),認(rèn)為是登錄用戶(hù),不走緩存
proxy_cache_bypass $cookie_session $http_authorization;
proxy_no_cache $cookie_session $http_authorization;
# stale 配置:上游故障時(shí),允許使用過(guò)期緩存響應(yīng)
# 這是提升可用性的關(guān)鍵配置,避免上游抖動(dòng)直接影響用戶(hù)
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# 防止緩存擊穿:同一 key 只允許一個(gè)請(qǐng)求回源,其他請(qǐng)求等待
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
# 在響應(yīng)頭中暴露緩存狀態(tài),便于調(diào)試(生產(chǎn)可關(guān)閉)
add_header X-Cache-Status $upstream_cache_status;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
}
2.4.3 靜態(tài)文件緩存與 expires/Cache-Control
# /etc/nginx/conf.d/static-cache.conf
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# 帶哈希指紋的靜態(tài)資源(如 app.a1b2c3d4.js)可永久緩存
location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
# 瀏覽器緩存1年,CDN 緩存1年
expires 1y;
add_header Cache-Control "public, immutable";
# 開(kāi)啟 gzip 靜態(tài)壓縮(需要預(yù)先生成 .gz 文件)
gzip_static on;
# sendfile 零拷貝傳輸,靜態(tài)文件服務(wù)必開(kāi)
sendfile on;
tcp_nopush on; # 配合 sendfile,批量發(fā)送響應(yīng)頭和文件內(nèi)容
}
# HTML 文件不緩存或短時(shí)緩存(內(nèi)容會(huì)更新)
location ~* .html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# API 響應(yīng):私有緩存,不允許 CDN 緩存
location /api/ {
proxy_pass http://backend_api;
add_header Cache-Control "private, no-cache";
}
}
2.4.4 緩存預(yù)熱與清理
# /opt/scripts/cache-warm.sh - 緩存預(yù)熱腳本 #!/bin/bash set-euo pipefail NGINX_HOST="http://127.0.0.1" URL_LIST="/opt/scripts/warm-urls.txt" CONCURRENCY=10 # 并發(fā)預(yù)熱請(qǐng)求數(shù) warm_cache() { localurl="$1" # 通過(guò) curl 訪(fǎng)問(wèn)觸發(fā)緩存,-s 靜默,-o /dev/null 丟棄響應(yīng)體 curl -s -o /dev/null -w"%{http_code} %{url_effective} " -H"Host: www.example.com" "${NGINX_HOST}${url}" } export-f warm_cache # 使用 xargs 并發(fā)執(zhí)行預(yù)熱 cat"${URL_LIST}"| xargs -P"${CONCURRENCY}"-I{} bash -c'warm_cache "$@"'_ {} echo"Cache warm-up completed"
# /etc/nginx/conf.d/cache-purge.conf
# 需要編譯 ngx_cache_purge 模塊
server {
listen 80;
server_name cache-admin.internal;
# 限制只有內(nèi)網(wǎng)可以訪(fǎng)問(wèn)清理接口
allow 10.0.0.0/8;
allow 192.168.0.0/16;
deny all;
location ~ /purge(/.*) {
proxy_cache_purge cache_main "$scheme$host$1";
}
}
2.5 SSL/TLS 優(yōu)化
2.5.1 TLS 1.3 配置與密碼套件選擇
# /etc/nginx/conf.d/ssl-base.conf - SSL 基礎(chǔ)配置(include 到各 server 塊) # 只啟用 TLS 1.2 和 1.3,TLS 1.0/1.1 已被 RFC 8996 廢棄 ssl_protocols TLSv1.2 TLSv1.3; # TLS 1.2 密碼套件:優(yōu)先 ECDHE(前向保密),禁用 RC4、3DES、MD5 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256ECDHE-ECDSA-AES256-GCM-SHA384ECDHE-ECDSA-CHACHA20-POLY1305DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; # 服務(wù)端優(yōu)先選擇密碼套件(TLS 1.3 中此設(shè)置被忽略) ssl_prefer_server_ciphers off; # DH 參數(shù)文件,防止 Logjam 攻擊 # 生成命令:openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 ssl_dhparam /etc/nginx/ssl/dhparam.pem; # 橢圓曲線(xiàn)選擇:X25519 性能最好,P-256 兼容性最廣 ssl_ecdh_curve X25519secp384r1;
2.5.2 OCSP Stapling 與會(huì)話(huà)復(fù)用
# /etc/nginx/conf.d/ssl-performance.conf # SSL 會(huì)話(huà)緩存:shared 在所有 worker 間共享,10m 約緩存 40000 個(gè)會(huì)話(huà) ssl_session_cache shared10m; ssl_session_timeout 1d; # 會(huì)話(huà)有效期1天,平衡安全性和性能 # TLS 1.3 會(huì)話(huà)票據(jù)(Session Tickets) # 允許客戶(hù)端恢復(fù)會(huì)話(huà),避免完整握手,減少延遲 # 注意:多臺(tái) Nginx 需要共享相同的 ticket key,否則跨機(jī)器無(wú)法復(fù)用 ssl_session_tickets off; # 單機(jī)可開(kāi)啟,集群環(huán)境需要同步 key 或關(guān)閉 # OCSP Stapling:Nginx 主動(dòng)獲取證書(shū)吊銷(xiāo)狀態(tài)并緩存 # 客戶(hù)端無(wú)需單獨(dú)查詢(xún) OCSP 服務(wù)器,減少握手延遲 ssl_stapling on; ssl_stapling_verify on; # 完整證書(shū)鏈(包含中間證書(shū)) ssl_trusted_certificate /etc/nginx/ssl/chain.pem; # DNS 解析器,用于 OCSP 查詢(xún) resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s;
2.5.3 HTTP/2 與 HTTP/3(QUIC) 啟用
# /etc/nginx/conf.d/http2-http3.conf
server {
# HTTP/2:在 listen 指令中添加 http2 參數(shù)(Nginx 1.25.1+ 語(yǔ)法)
listen 443 ssl;
http2 on;
# HTTP/3 / QUIC:基于 UDP,需要 1.25.0+ 且編譯了 --with-http_v3_module
listen 443 quic reuseport;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
include /etc/nginx/conf.d/ssl-base.conf;
include /etc/nginx/conf.d/ssl-performance.conf;
# 告知客戶(hù)端支持 HTTP/3,瀏覽器下次請(qǐng)求會(huì)嘗試 QUIC
add_header Alt-Svc 'h3=":443"; ma=86400';
# HSTS:強(qiáng)制瀏覽器使用 HTTPS,max-age 建議至少 6個(gè)月
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
location / {
proxy_pass http://backend_api;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name www.example.com;
return 301 https://$host$request_uri;
}
三、示例代碼和配置
3.1 完整的生產(chǎn)級(jí) nginx.conf
# /etc/nginx/nginx.conf - 生產(chǎn)級(jí)主配置文件
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65536;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 16384;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 自定義日志格式,包含響應(yīng)時(shí)間和上游信息,便于性能分析
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct=$upstream_connect_time '
'uht=$upstream_header_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
# 零拷貝文件傳輸,靜態(tài)文件服務(wù)必開(kāi)
sendfile on;
# sendfile 開(kāi)啟后才有效:將多個(gè)小包合并成一個(gè) TCP 包發(fā)送,減少網(wǎng)絡(luò)開(kāi)銷(xiāo)
tcp_nopush on;
# 禁用 Nagle 算法,減少小包延遲,對(duì)實(shí)時(shí)性要求高的場(chǎng)景有效
tcp_nodelay on;
# 客戶(hù)端連接保持時(shí)間,65s 是經(jīng)驗(yàn)值,CDN 場(chǎng)景可適當(dāng)調(diào)長(zhǎng)
keepalive_timeout 65;
keepalive_requests 1000;
# 隱藏 Nginx 版本號(hào),減少信息泄露
server_tokens off;
# 客戶(hù)端請(qǐng)求體大小限制,防止大文件上傳耗盡內(nèi)存
client_max_body_size 100m;
client_body_buffer_size 128k;
# 請(qǐng)求頭緩沖區(qū),大 Cookie 或 JWT Token 場(chǎng)景需要調(diào)大
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;
# Gzip 壓縮配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # 1-9,6 是壓縮率和 CPU 消耗的平衡點(diǎn)
gzip_min_length 1024; # 小于 1KB 的響應(yīng)不壓縮,壓縮收益低于開(kāi)銷(xiāo)
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml
application/rss+xml application/atom+xml image/svg+xml;
# 線(xiàn)程池:將阻塞的文件 I/O 操作卸載到獨(dú)立線(xiàn)程,避免阻塞 worker
thread_pool default threads=32 max_queue=65536;
# 緩存區(qū)域定義(供各 server 塊引用)
proxy_cache_path /data/nginx/cache
levels=1:2
keys_zone=cache_main:100m
max_size=10g
inactive=60m
use_temp_path=off;
include /etc/nginx/conf.d/*.conf;
}
3.2 多站點(diǎn)反向代理 + 負(fù)載均衡完整配置
# /etc/nginx/conf.d/production.conf - 生產(chǎn)多站點(diǎn)配置
# API 服務(wù)集群
upstream api_cluster {
least_conn;
keepalive 64;
keepalive_requests 1000;
keepalive_timeout 60s;
server 10.0.1.11:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.1.13:8080 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.1.14:8080 backup;
}
# 靜態(tài)資源服務(wù)器
upstream static_cluster {
server 10.0.1.21:80;
server 10.0.1.22:80;
keepalive 32;
}
# API 網(wǎng)關(guān)
server {
listen 443 ssl;
http2 on;
listen 443 quic reuseport;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
include /etc/nginx/conf.d/ssl-base.conf;
include /etc/nginx/conf.d/ssl-performance.conf;
add_header Alt-Svc 'h3=":443"; ma=86400';
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
# 限流:每個(gè) IP 每秒最多 100 個(gè)請(qǐng)求
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_req zone=api_limit burst=200 nodelay;
location /api/v1/ {
proxy_pass http://api_cluster/;
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_read_timeout 30s;
proxy_send_timeout 30s;
# 啟用緩存(GET 請(qǐng)求)
proxy_cache cache_main;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 5m;
proxy_cache_valid 404 1m;
proxy_cache_bypass $http_cache_control;
proxy_no_cache $http_pragma $http_authorization;
# 緩存命中狀態(tài)頭,便于調(diào)試
add_header X-Cache-Status $upstream_cache_status;
}
# 健康檢查端點(diǎn)不緩存
location /health {
proxy_pass http://api_cluster;
proxy_cache off;
access_log off;
}
}
# 靜態(tài)資源站點(diǎn)
server {
listen 443 ssl;
http2 on;
server_name static.example.com;
ssl_certificate /etc/nginx/ssl/static.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/static.example.com.key;
include /etc/nginx/conf.d/ssl-base.conf;
location ~* .(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
proxy_pass http://static_cluster;
proxy_cache cache_main;
proxy_cache_valid 200 7d;
# 瀏覽器緩存:靜態(tài)資源設(shè)置長(zhǎng)期緩存,配合文件名哈希實(shí)現(xiàn)緩存破壞
expires 30d;
add_header Cache-Control "public, immutable";
# 預(yù)壓縮文件優(yōu)先(需要 gzip_static 模塊)
gzip_static on;
}
}
3.3 緩存集群配置示例
# /etc/nginx/conf.d/cache-cluster.conf - 多級(jí)緩存配置 # 定義多個(gè)緩存區(qū)域,按內(nèi)容類(lèi)型分離 proxy_cache_path /data/nginx/cache/api levels=1:2 keys_zone=cache_api:50m max_size=5g inactive=30m use_temp_path=off; proxy_cache_path /data/nginx/cache/static levels=1:2 keys_zone=cache_static:100m max_size=20g inactive=7d use_temp_path=off; # 緩存鎖:防止緩存擊穿(多個(gè)請(qǐng)求同時(shí)穿透到上游) proxy_cache_lock on; proxy_cache_lock_timeout 5s; proxy_cache_lock_age 5s; # 后臺(tái)更新:緩存過(guò)期時(shí)先返回舊內(nèi)容,后臺(tái)異步更新 # 避免緩存過(guò)期瞬間大量請(qǐng)求打到上游 proxy_cache_background_update on; # 上游不可用時(shí)使用過(guò)期緩存(降級(jí)策略) proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; server { listen 80; server_name cache.example.com; location /api/ { proxy_pass http://api_cluster; proxy_cache cache_api; proxy_cache_key "$scheme$host$uri$is_args$args"; proxy_cache_valid 200 302 5m; proxy_cache_valid 404 1m; # 忽略上游的 Set-Cookie,防止帶 Cookie 的響應(yīng)被緩存 proxy_ignore_headers Set-Cookie; proxy_hide_header Set-Cookie; add_header X-Cache-Status $upstream_cache_status; add_header X-Cache-Date $upstream_http_date; } location /static/ { proxy_pass http://static_cluster; proxy_cache cache_static; proxy_cache_key "$uri"; # 靜態(tài)資源 key 不含 scheme/host,跨域共享緩存 proxy_cache_valid 200 7d; proxy_cache_use_stale error timeout updating; expires 30d; add_header Cache-Control "public, max-age=2592000, immutable"; } }
四、最佳實(shí)踐和注意事項(xiàng)
4.1 最佳實(shí)踐
4.1.1 性能優(yōu)化
# /etc/nginx/conf.d/performance.conf - 性能優(yōu)化配置集合
http {
# sendfile + tcp_nopush 組合:零拷貝傳輸 + 批量發(fā)送
# sendfile 讓內(nèi)核直接將文件數(shù)據(jù)發(fā)送到網(wǎng)絡(luò),不經(jīng)過(guò)用戶(hù)態(tài)
sendfile on;
tcp_nopush on;
# tcp_nodelay 禁用 Nagle 算法,減少小包延遲
# 與 tcp_nopush 同時(shí)開(kāi)啟時(shí),Nginx 會(huì)先積累數(shù)據(jù)(tcp_nopush),
# 連接進(jìn)入 keepalive 狀態(tài)后再啟用 tcp_nodelay 刷新剩余數(shù)據(jù)
tcp_nodelay on;
# 線(xiàn)程池異步文件 I/O,避免磁盤(pán)讀寫(xiě)阻塞 worker 進(jìn)程
# 適合大文件下載場(chǎng)景,小文件場(chǎng)景收益不明顯
aio threads=default;
aio_write on;
# 直接 I/O:繞過(guò)操作系統(tǒng)頁(yè)緩存,適合大文件且不需要重復(fù)讀取的場(chǎng)景
# 小文件或頻繁訪(fǎng)問(wèn)的文件不要開(kāi)啟,會(huì)降低性能
# directio 512;
# open_file_cache:緩存文件描述符、文件大小和修改時(shí)間
# 避免每次請(qǐng)求都調(diào)用 stat() 系統(tǒng)調(diào)用
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Gzip 壓縮:文本內(nèi)容壓縮率通常 60-80%,顯著減少傳輸量
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_vary on;
gzip_proxied any;
gzip_types
text/plain text/css text/xml text/javascript
application/json application/javascript application/xml
application/rss+xml application/atom+xml image/svg+xml
font/truetype font/opentype application/vnd.ms-fontobject;
}
4.1.2 安全加固
# /etc/nginx/conf.d/security.conf - 安全加固配置
server {
# 隱藏 Nginx 版本號(hào),攻擊者無(wú)法針對(duì)特定版本漏洞
server_tokens off;
# 限制請(qǐng)求方法,只允許 GET/POST/HEAD
if ($request_method !~ ^(GET|POST|HEAD|PUT|DELETE|PATCH|OPTIONS)$) {
return 405;
}
# 防止點(diǎn)擊劫持
add_header X-Frame-Options SAMEORIGIN always;
# 禁止 MIME 類(lèi)型嗅探,防止 XSS 攻擊
add_header X-Content-Type-Options nosniff always;
# XSS 保護(hù)(現(xiàn)代瀏覽器已內(nèi)置,但舊版瀏覽器需要此頭)
add_header X-XSS-Protection "1; mode=block" always;
# 限制請(qǐng)求體大小,防止大文件上傳耗盡內(nèi)存
client_max_body_size 10m;
# 限制請(qǐng)求頭大小,防止 Header 注入攻擊
large_client_header_buffers 4 8k;
# 限流:防止暴力破解和 DDoS
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
location /login {
limit_req zone=login_limit burst=10 nodelay;
limit_conn conn_limit 5;
proxy_pass http://backend_api;
}
# 禁止訪(fǎng)問(wèn)隱藏文件(.git、.env 等)
location ~ /. {
deny all;
access_log off;
log_not_found off;
}
# 禁止訪(fǎng)問(wèn)備份文件
location ~* .(bak|conf|dist|fla|inc|ini|log|psd|sh|sql|swp)$ {
deny all;
}
}
4.1.3 高可用配置(Keepalived + Nginx 雙主)
# /etc/keepalived/keepalived.conf - 主節(jié)點(diǎn)(192.168.1.11)配置 vrrp_script check_nginx { script"/opt/scripts/check-nginx.sh" interval 2 # 每2秒檢查一次 weight -20 # 檢查失敗時(shí)優(yōu)先級(jí)降低20,觸發(fā) VIP 漂移 fall 2 # 連續(xù)失敗2次才認(rèn)為服務(wù)異常 rise 2 # 連續(xù)成功2次才認(rèn)為服務(wù)恢復(fù) } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 # 主節(jié)點(diǎn)優(yōu)先級(jí)高于備節(jié)點(diǎn) advert_int 1 authentication { auth_type PASS auth_pass nginx_ha_2024 } virtual_ipaddress { 192.168.1.100/24 # VIP,對(duì)外提供服務(wù)的 IP } track_script { check_nginx } }
# /opt/scripts/check-nginx.sh - Nginx 健康檢查腳本
#!/bin/bash
set-euo pipefail
# 檢查 Nginx 進(jìn)程是否存在
if! pgrep -x nginx > /dev/null;then
# 嘗試重啟 Nginx
systemctl start nginx
sleep 2
# 重啟后再次檢查,失敗則退出非零狀態(tài)觸發(fā) VIP 漂移
pgrep -x nginx > /dev/null ||exit1
fi
# 檢查 Nginx 是否能正常響應(yīng)請(qǐng)求
http_code=$(curl -s -o /dev/null -w"%{http_code}"http://127.0.0.1/health)
if["${http_code}"!="200"];then
exit1
fi
exit0
4.2 注意事項(xiàng)
4.2.1 配置注意事項(xiàng)
proxy_pass末尾斜杠是最常見(jiàn)的配置錯(cuò)誤:proxy_pass http://backend/會(huì)截?cái)?location 前綴,proxy_pass http://backend則保留完整 URI。在 location 使用正則表達(dá)式時(shí),proxy_pass不能帶 URI 部分(即不能有斜杠后的路徑),否則 Nginx 會(huì)拒絕啟動(dòng)。
worker_connections設(shè)置的是單個(gè) worker 的連接數(shù)上限,包含客戶(hù)端連接和上游連接。作為反向代理時(shí),每個(gè)客戶(hù)端請(qǐng)求至少占用 2 個(gè)連接(客戶(hù)端 + 上游),實(shí)際并發(fā)客戶(hù)端數(shù)約為worker_connections / 2。
proxy_cache_path的keys_zone內(nèi)存區(qū)只存儲(chǔ)緩存 key 的索引,不存儲(chǔ)緩存內(nèi)容本身。100m 的 keys_zone 約能存儲(chǔ) 80 萬(wàn)個(gè) key,緩存內(nèi)容存儲(chǔ)在磁盤(pán)上。
4.2.2 常見(jiàn)錯(cuò)誤
| 錯(cuò)誤現(xiàn)象 | 原因分析 | 解決方案 |
|---|---|---|
| 502 Bad Gateway | 上游服務(wù)不可用或連接超時(shí) | 檢查上游服務(wù)狀態(tài),調(diào)整 proxy_connect_timeout |
| 504 Gateway Timeout | 上游響應(yīng)超時(shí) | 增大 proxy_read_timeout,或優(yōu)化上游接口性能 |
| 413 Request Entity Too Large | 請(qǐng)求體超過(guò) client_max_body_size | 調(diào)大 client_max_body_size 或在上游處理 |
| 499 Client Closed Request | 客戶(hù)端在響應(yīng)前斷開(kāi)連接 | 通常是客戶(hù)端超時(shí),檢查客戶(hù)端超時(shí)設(shè)置 |
| upstream timed out (110) | 上游連接超時(shí) | 檢查上游服務(wù)負(fù)載,調(diào)整超時(shí)參數(shù) |
| no live upstreams while connecting | 所有上游節(jié)點(diǎn)不可用 | 檢查上游服務(wù),調(diào)整 max_fails/fail_timeout |
| worker_connections are not enough | 連接數(shù)耗盡 | 增大 worker_connections 和 worker_rlimit_nofile |
| open() failed (24: Too many open files) | 文件描述符耗盡 | 增大 worker_rlimit_nofile 和系統(tǒng) ulimit |
4.2.3 兼容性問(wèn)題
HTTP/3 (QUIC) 需要防火墻放行 UDP 443 端口,許多企業(yè)網(wǎng)絡(luò)默認(rèn)封鎖 UDP,導(dǎo)致 HTTP/3 降級(jí)到 HTTP/2。Alt-Svc響應(yīng)頭告知瀏覽器支持 HTTP/3,瀏覽器會(huì)在后續(xù)請(qǐng)求中嘗試 QUIC,失敗后自動(dòng)回退,不影響功能。
http2 on指令是 1.25.1 引入的新語(yǔ)法,舊版本使用listen 443 ssl http2。兩種語(yǔ)法不能混用,升級(jí) Nginx 版本后需要統(tǒng)一遷移。
五、故障排查和監(jiān)控
5.1 故障排查
5.1.1 日志分析
# /etc/nginx/nginx.conf - 自定義日志格式
http {
# 詳細(xì)日志格式,包含所有關(guān)鍵性能指標(biāo)
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time ' # 總請(qǐng)求處理時(shí)間
'uct=$upstream_connect_time ' # 與上游建立連接時(shí)間
'uht=$upstream_header_time ' # 收到上游響應(yīng)頭時(shí)間
'urt=$upstream_response_time ' # 上游響應(yīng)總時(shí)間
'cs=$upstream_cache_status ' # 緩存命中狀態(tài)
'ua=$upstream_addr'; # 實(shí)際處理請(qǐng)求的上游地址
# 生產(chǎn)環(huán)境使用緩沖寫(xiě)入,減少磁盤(pán) I/O
access_log /var/log/nginx/access.log detailed buffer=64k flush=10s;
# 錯(cuò)誤日志:warn 級(jí)別記錄重要錯(cuò)誤,不記錄 notice/info 級(jí)別的噪音
error_log /var/log/nginx/error.log warn;
}
# 常用日志分析命令
# 統(tǒng)計(jì)響應(yīng)狀態(tài)碼分布
awk'{print $9}'/var/log/nginx/access.log | sort | uniq -c | sort -rn
# 找出響應(yīng)時(shí)間最慢的10個(gè)請(qǐng)求
awk'{print $NF, $7}'/var/log/nginx/access.log | sort -rn | head -10
# 統(tǒng)計(jì)每分鐘請(qǐng)求量(流量趨勢(shì))
awk'{print $4}'/var/log/nginx/access.log | cut -d: -f1-3 | uniq -c
# 找出請(qǐng)求量最大的 IP(排查 DDoS)
awk'{print $1}'/var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 實(shí)時(shí)監(jiān)控錯(cuò)誤日志
tail -f /var/log/nginx/error.log | grep -E"error|crit|alert|emerg"
5.1.2 常見(jiàn)問(wèn)題排查
502 Bad Gateway 排查流程:
# 1. 確認(rèn)上游服務(wù)是否存活 curl -v http://10.0.1.11:8080/health # 2. 檢查 Nginx 錯(cuò)誤日志中的具體錯(cuò)誤信息 tail -100 /var/log/nginx/error.log | grep"upstream" # 3. 檢查上游連接數(shù)是否耗盡 ss -s # 查看 TCP 連接統(tǒng)計(jì) ss -tn state established | grep :8080 | wc -l # 4. 檢查上游服務(wù)的文件描述符限制 cat /proc/$(pgrep -f"java")/limits | grep"open files"
連接數(shù)耗盡排查:
# 查看當(dāng)前連接數(shù) ss -s # 查看 TIME_WAIT 連接數(shù)(過(guò)多說(shuō)明短連接頻繁) ss -tn state time-wait | wc -l # 查看 Nginx worker 打開(kāi)的文件描述符數(shù) ls /proc/$(pgrep nginx | head -1)/fd | wc -l # 檢查系統(tǒng)文件描述符使用情況 cat /proc/sys/fs/file-nr
5.1.3 調(diào)試模式
# /etc/nginx/conf.d/debug.conf - 臨時(shí)調(diào)試配置(生產(chǎn)環(huán)境用完立即刪除)
# 針對(duì)特定 IP 開(kāi)啟 debug 日志,避免全量 debug 影響性能
error_log /var/log/nginx/debug.log debug;
events {
debug_connection 192.168.1.100; # 只對(duì)此 IP 的連接輸出 debug 日志
}
# 測(cè)試配置文件語(yǔ)法 nginx -t # 查看編譯參數(shù)和模塊列表 nginx -V 2>&1 | tr' '' ' # 重載配置(不中斷現(xiàn)有連接) nginx -s reload # 查看 Nginx 進(jìn)程樹(shù) ps aux | grep nginx # 實(shí)時(shí)查看連接狀態(tài)(需要 stub_status 模塊) curl http://127.0.0.1/nginx_status
5.2 性能監(jiān)控
5.2.1 stub_status 模塊
# /etc/nginx/conf.d/status.conf - 監(jiān)控狀態(tài)頁(yè)
server {
listen 127.0.0.1:8080; # 只監(jiān)聽(tīng)本地,不對(duì)外暴露
server_name localhost;
location /nginx_status {
stub_status;
access_log off;
# 只允許本機(jī)和監(jiān)控服務(wù)器訪(fǎng)問(wèn)
allow 127.0.0.1;
allow 10.0.1.0/24;
deny all;
}
}
# stub_status 輸出示例及含義 # Active connections: 291 # 當(dāng)前活躍連接數(shù) # server accepts handled requests # 16630948 16630948 31070465 # 總接受連接數(shù) / 總處理連接數(shù) / 總請(qǐng)求數(shù) # Reading: 6 Writing: 179 Waiting: 106 # Reading: 正在讀取請(qǐng)求頭的連接數(shù) # Writing: 正在向客戶(hù)端發(fā)送響應(yīng)的連接數(shù) # Waiting: keepalive 空閑連接數(shù)(等待下一個(gè)請(qǐng)求)
5.2.2 Prometheus + nginx-exporter 監(jiān)控
# 安裝 nginx-prometheus-exporter wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v1.3.0/nginx-prometheus-exporter_1.3.0_linux_amd64.tar.gz tar -xzf nginx-prometheus-exporter_1.3.0_linux_amd64.tar.gz # 啟動(dòng) exporter(讀取 stub_status 并轉(zhuǎn)換為 Prometheus 格式) ./nginx-prometheus-exporter -nginx.scrape-uri=http://127.0.0.1:8080/nginx_status -web.listen-address=:9113
# /etc/prometheus/rules/nginx.yml - Prometheus 告警規(guī)則
groups:
-name:nginx
rules:
-alert:NginxHighActiveConnections
expr:nginx_connections_active>10000
for:5m
labels:
severity:warning
annotations:
summary:"Nginx 活躍連接數(shù)過(guò)高"
description:"當(dāng)前活躍連接數(shù){{ $value }},超過(guò)閾值 10000"
-alert:NginxHighErrorRate
# 5xx 錯(cuò)誤率超過(guò) 5%
expr:rate(nginx_http_requests_total{status=~"5.."}[5m])/rate(nginx_http_requests_total[5m])>0.05
for:2m
labels:
severity:critical
annotations:
summary:"Nginx 5xx 錯(cuò)誤率過(guò)高"
5.2.3 關(guān)鍵指標(biāo)與告警閾值
| 指標(biāo)名稱(chēng) | 正常范圍 | 告警閾值 | 說(shuō)明 |
|---|---|---|---|
| 活躍連接數(shù) | < 5000 | > 10000 | 接近 worker_connections 上限時(shí)需擴(kuò)容 |
| 請(qǐng)求處理時(shí)間 | < 200ms | > 1000ms | P99 超過(guò)1秒需排查上游或緩存 |
| 5xx 錯(cuò)誤率 | < 0.1% | > 1% | 上游服務(wù)異常的直接體現(xiàn) |
| 上游響應(yīng)時(shí)間 | < 100ms | > 500ms | 上游服務(wù)性能問(wèn)題 |
| 緩存命中率 | > 80% | < 50% | 緩存策略需要優(yōu)化 |
| 連接等待數(shù)(Waiting) | < 1000 | > 5000 | keepalive 連接過(guò)多,可能需要調(diào)小 keepalive_timeout |
5.3 備份與恢復(fù)
5.3.1 配置備份腳本
# /opt/scripts/nginx-backup.sh - Nginx 配置備份腳本
#!/bin/bash
set-euo pipefail
BACKUP_DIR="/opt/backups/nginx"
NGINX_CONF_DIR="/etc/nginx"
RETENTION_DAYS=30
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/nginx_conf_${TIMESTAMP}.tar.gz"
backup_nginx_config() {
mkdir -p"${BACKUP_DIR}"
# 打包 Nginx 配置目錄
tar -czf"${BACKUP_FILE}"
--exclude="${NGINX_CONF_DIR}/ssl/*.key" # 私鑰單獨(dú)備份,不放在普通備份中
"${NGINX_CONF_DIR}"
echo"備份完成:${BACKUP_FILE}"
echo"備份大小:$(du -sh "${BACKUP_FILE}" | cut -f1)"
}
cleanup_old_backups() {
# 刪除超過(guò)保留期的備份文件
find"${BACKUP_DIR}"-name"nginx_conf_*.tar.gz"
-mtime"+${RETENTION_DAYS}"-delete
echo"已清理${RETENTION_DAYS}天前的備份"
}
verify_backup() {
# 驗(yàn)證備份文件完整性
iftar -tzf"${BACKUP_FILE}"> /dev/null 2>&1;then
echo"備份驗(yàn)證通過(guò)"
else
echo"備份文件損壞!">&2
exit1
fi
}
backup_nginx_config
verify_backup
cleanup_old_backups
5.3.2 灰度發(fā)布與配置回滾
# /opt/scripts/nginx-deploy.sh - 配置灰度發(fā)布腳本
#!/bin/bash
set-euo pipefail
NGINX_CONF_DIR="/etc/nginx"
BACKUP_DIR="/opt/backups/nginx"
deploy_config() {
localnew_config_dir="$1"
localtimestamp
timestamp=$(date +%Y%m%d_%H%M%S)
# 備份當(dāng)前配置
cp -r"${NGINX_CONF_DIR}""${BACKUP_DIR}/nginx_conf_before_deploy_${timestamp}"
echo"當(dāng)前配置已備份到:${BACKUP_DIR}/nginx_conf_before_deploy_${timestamp}"
# 復(fù)制新配置
rsync -av --delete"${new_config_dir}/""${NGINX_CONF_DIR}/"
# 測(cè)試新配置語(yǔ)法
if! nginx -t;then
echo"新配置語(yǔ)法錯(cuò)誤,回滾...">&2
rsync -av --delete"${BACKUP_DIR}/nginx_conf_before_deploy_${timestamp}/""${NGINX_CONF_DIR}/"
exit1
fi
# 熱重載(不中斷現(xiàn)有連接)
nginx -s reload
echo"配置部署成功,已熱重載"
}
rollback_config() {
localbackup_path="$1"
if[ ! -d"${backup_path}"];then
echo"備份目錄不存在:${backup_path}">&2
exit1
fi
rsync -av --delete"${backup_path}/""${NGINX_CONF_DIR}/"
ifnginx -t && nginx -s reload;then
echo"回滾成功"
else
echo"回滾失敗,請(qǐng)手動(dòng)檢查配置">&2
exit1
fi
}
case"${1:-}"in
deploy) deploy_config"${2}";;
rollback) rollback_config"${2}";;
*) echo"用法:$0{deploy |rollback }";;
esac
六、總結(jié)
6.1 技術(shù)要點(diǎn)回顧
worker 配置:worker_processes auto+worker_cpu_affinity auto+worker_rlimit_nofile 65536,三者配合才能充分利用多核并支撐高并發(fā)
內(nèi)核參數(shù):somaxconn、tcp_tw_reuse、file-max是必須調(diào)整的三個(gè)參數(shù),不調(diào)整會(huì)在中等流量下觸發(fā)瓶頸
反向代理:proxy_http_version 1.1+proxy_set_header Connection ""+keepalive是啟用上游長(zhǎng)連接的完整組合,缺一不可
緩存設(shè)計(jì):proxy_cache_use_stale配置上游降級(jí)策略,proxy_cache_lock防止緩存擊穿,proxy_cache_background_update避免緩存過(guò)期時(shí)的流量尖刺
TLS 優(yōu)化:TLS 1.3 + OCSP Stapling + 會(huì)話(huà)緩存,三者疊加可將 TLS 握手延遲降低 50% 以上
6.2 進(jìn)階學(xué)習(xí)方向
OpenResty / njs:在 Nginx 中嵌入 Lua 或 JavaScript 邏輯,實(shí)現(xiàn) JWT 驗(yàn)證、動(dòng)態(tài)路由、A/B 測(cè)試等 API 網(wǎng)關(guān)功能,無(wú)需引入獨(dú)立網(wǎng)關(guān)組件
Nginx Unit:Nginx 官方的應(yīng)用服務(wù)器,支持動(dòng)態(tài)配置(無(wú)需重載),可直接運(yùn)行 Python/PHP/Node.js 應(yīng)用,適合替代 uWSGI/Gunicorn
eBPF + Nginx:使用 eBPF 在內(nèi)核層面監(jiān)控 Nginx 的網(wǎng)絡(luò)行為,實(shí)現(xiàn)零侵入的性能分析和安全審計(jì)
6.3 參考資料
Nginx 官方文檔- 權(quán)威參考,指令說(shuō)明以此為準(zhǔn)
Nginx 源碼- 理解內(nèi)部實(shí)現(xiàn)的最直接途徑
nginx-prometheus-exporter- 官方 Prometheus 集成
Mozilla SSL Configuration Generator- TLS 配置生成工具,覆蓋主流瀏覽器兼容性
附錄
A. 命令速查表
# 配置測(cè)試與重載 nginx -t # 測(cè)試配置文件語(yǔ)法 nginx -T # 測(cè)試并輸出完整配置(含 include 文件) nginx -s reload # 熱重載配置(不中斷連接) nginx -s reopen # 重新打開(kāi)日志文件(日志切割后使用) nginx -s quit # 優(yōu)雅停止(等待現(xiàn)有請(qǐng)求完成) nginx -s stop # 立即停止 # 進(jìn)程管理 systemctl start nginx # 啟動(dòng) systemctl stop nginx # 停止 systemctl reload nginx # 重載(等同于 nginx -s reload) systemctl status nginx # 查看狀態(tài) # 日志分析 tail -f /var/log/nginx/error.log # 實(shí)時(shí)查看錯(cuò)誤日志 nginx -V 2>&1 | tr' '' ' # 查看編譯參數(shù) # 連接狀態(tài) ss -tn state established dst :80 # 查看到80端口的連接 ss -s # 連接統(tǒng)計(jì)摘要 curl http://127.0.0.1/nginx_status# 查看 stub_status # 緩存管理 find /data/nginx/cache -typef | wc -l # 統(tǒng)計(jì)緩存文件數(shù)量 du -sh /data/nginx/cache # 查看緩存占用空間
B. 配置參數(shù)詳解
| 參數(shù) | 默認(rèn)值 | 推薦值 | 說(shuō)明 |
|---|---|---|---|
| worker_processes | 1 | auto | worker 進(jìn)程數(shù),auto 自動(dòng)匹配 CPU 核數(shù) |
| worker_connections | 512 | 16384 | 單 worker 最大連接數(shù) |
| worker_rlimit_nofile | 系統(tǒng)默認(rèn) | 65536 | worker 進(jìn)程文件描述符上限 |
| keepalive_timeout | 75s | 65s | 客戶(hù)端 keepalive 超時(shí) |
| proxy_connect_timeout | 60s | 5s | 與上游建立連接超時(shí) |
| proxy_read_timeout | 60s | 60s | 等待上游響應(yīng)超時(shí) |
| client_max_body_size | 1m | 10m-100m | 請(qǐng)求體大小限制 |
| gzip_comp_level | 1 | 6 | 壓縮級(jí)別,6 是性能與壓縮率平衡點(diǎn) |
| proxy_cache_lock | off | on | 防止緩存擊穿 |
| open_file_cache max | - | 10000 | 文件描述符緩存條目數(shù) |
C. 術(shù)語(yǔ)表
| 術(shù)語(yǔ) | 英文 | 解釋 |
|---|---|---|
| 反向代理 | Reverse Proxy | 代表后端服務(wù)接收客戶(hù)端請(qǐng)求,客戶(hù)端不直接訪(fǎng)問(wèn)后端 |
| 負(fù)載均衡 | Load Balancing | 將流量分發(fā)到多個(gè)后端實(shí)例,提升吞吐量和可用性 |
| 上游 | Upstream | Nginx 轉(zhuǎn)發(fā)請(qǐng)求的目標(biāo)服務(wù)器或服務(wù)器組 |
| 緩存擊穿 | Cache Breakdown | 熱點(diǎn) key 過(guò)期瞬間大量請(qǐng)求同時(shí)穿透到上游 |
| 緩存穿透 | Cache Penetration | 請(qǐng)求不存在的數(shù)據(jù),每次都穿透緩存打到上游 |
| 驚群效應(yīng) | Thundering Herd | 多個(gè)進(jìn)程/線(xiàn)程同時(shí)被喚醒競(jìng)爭(zhēng)同一資源 |
| 前向保密 | Forward Secrecy | 即使私鑰泄露,歷史會(huì)話(huà)數(shù)據(jù)也無(wú)法被解密 |
| OCSP 裝訂 | OCSP Stapling | 服務(wù)端預(yù)先獲取證書(shū)吊銷(xiāo)狀態(tài)并附在 TLS 握手中 |
| 零拷貝 | Zero-Copy | 數(shù)據(jù)在內(nèi)核態(tài)直接傳輸,不經(jīng)過(guò)用戶(hù)態(tài)緩沖區(qū) |
| 事件驅(qū)動(dòng) | Event-Driven | 通過(guò)事件通知機(jī)制處理 I/O,而非為每個(gè)連接分配線(xiàn)程 |
-
服務(wù)器
+關(guān)注
關(guān)注
14文章
10251瀏覽量
91481 -
負(fù)載均衡
+關(guān)注
關(guān)注
0文章
133瀏覽量
12875 -
nginx
+關(guān)注
關(guān)注
0文章
186瀏覽量
13112
原文標(biāo)題:Nginx高性能配置:反向代理、負(fù)載均衡與緩存優(yōu)化
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Linux上Nginx獲得最佳性能的8種方法
nginx重啟命令linux步驟是什么?
nginx重啟命令linux步驟是什么?
nginx錯(cuò)誤頁(yè)面配置
主要學(xué)習(xí)下nginx的安裝配置
ECS配置lnmp的詳細(xì)步驟資料說(shuō)明
Nginx的詳細(xì)知識(shí)點(diǎn)講解
詳解Nginx高性能的HTTP和反向代理服務(wù)器
Nginx的特點(diǎn)和作用 Nginx常用命令和核心配置
Nginx 如何實(shí)現(xiàn)高性能低消耗
nginx負(fù)載均衡配置介紹
Nginx配置終極指南
Nginx高性能配置詳細(xì)步驟
評(píng)論