第九章 缓存机制
9.1 浏览器缓存(expires)
nginx
# 方式一:expires 指令
location ~* \.(jpg|png|gif|css|js)$ {
expires 30d; # 30天过期
}
# 方式二:Cache-Control(更灵活,推荐)
location ~* \.(css|js)$ {
add_header Cache-Control "public, max-age=2592000, immutable";
}
# 不缓存动态内容
location /api/ {
add_header Cache-Control "no-store, no-cache, must-revalidate";
add_header Pragma "no-cache";
}
缓存策略建议:
| 资源类型 | 策略 | 说明 |
|---|---|---|
| HTML | no-cache |
每次验证,保证最新 |
| CSS/JS(带hash) | immutable, max-age=1y |
文件名含hash,永久缓存 |
| 图片/字体 | max-age=30d |
较长缓存 |
| API 响应 | no-store |
禁止缓存 |
9.2 代理缓存(proxy_cache)
nginx
http {
# 定义缓存区域
proxy_cache_path /var/cache/nginx
levels=1:2 # 目录层级
keys_zone=my_cache:10m # 共享内存区域(存key)
max_size=10g # 磁盘最大缓存
inactive=60m # 60分钟未访问则清除
use_temp_path=off; # 不使用临时路径
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 301 302 10m; # 成功响应缓存10分钟
proxy_cache_valid 404 1m; # 404 缓存1分钟
proxy_cache_key "$scheme$host$request_uri";
# 添加缓存状态头(调试用)
add_header X-Cache-Status $upstream_cache_status;
# 值:HIT / MISS / EXPIRED / BYPASS / STALE
}
}
}
9.3 缓存控制策略
nginx
# 指定条件绕过缓存
proxy_cache_bypass $http_cache_control $cookie_nocache;
# 指定不缓存的条件
proxy_no_cache $arg_nocache $http_pragma;
# 后端宕机时使用过期缓存(容灾)
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
# 缓存锁(防止缓存击穿)
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
# 手动清除缓存(需要 ngx_cache_purge 模块)
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge my_cache "$scheme$host$1";
}
第十章 架构设计
10.1 单机部署
Client → Nginx → 本机应用(Node/Java/Python)
最简单的部署方式,适合小型项目和开发环境。
10.2 反向代理架构
┌────────────────┐
Client ──→ Nginx ──→│ App Server │
│ (单台后端) │
└────────────────┘
适合中小型项目,Nginx 负责 SSL 终端、静态资源、请求转发。
10.3 负载均衡架构
┌─── App Server 1
Client ──→ Nginx ──┤─── App Server 2
(LB) └─── App Server 3
水平扩展,Nginx 按策略分发流量。
10.4 微服务网关架构
┌─────────────┐
│ Nginx 网关 │
│ (路由/鉴权) │
└──┬──┬──┬────┘
│ │ │
┌──────┘ │ └──────┐
▼ ▼ ▼
┌────────┐┌────────┐┌────────┐
│用户服务 ││商品服务 ││订单服务 │
└────────┘└────────┘└────────┘
nginx
# 微服务网关配置示例
upstream user_service { server 10.0.1.1:8001; server 10.0.1.2:8001; }
upstream product_service { server 10.0.2.1:8002; server 10.0.2.2:8002; }
upstream order_service { server 10.0.3.1:8003; server 10.0.3.2:8003; }
server {
listen 443 ssl;
location /api/user/ { proxy_pass http://user_service; }
location /api/product/ { proxy_pass http://product_service; }
location /api/order/ { proxy_pass http://order_service; }
}
10.5 CDN + Nginx
Client → CDN 边缘节点 → Nginx 源站 → App Server
CDN 缓存静态资源,减少源站压力。Nginx 作为源站负责动态内容和回源策略。
nginx
# 源站配置:设置 CDN 友好的缓存头
location ~* \.(css|js|jpg|png)$ {
add_header Cache-Control "public, max-age=31536000";
add_header CDN-Cache-Control "max-age=86400"; # CDN 专用缓存头
}
10.6 高可用(Keepalived)
VIP: 192.168.1.100
┌──────────┐
│ 虚拟 IP │
└────┬─────┘
┌───────┴───────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Nginx Master│ │ Nginx Backup│
│ (MASTER) │ │ (BACKUP) │
│ 优先级 100 │ │ 优先级 90 │
└─────────────┘ └─────────────┘
Master 宕机 → VIP 自动漂移到 Backup
bash
# /etc/keepalived/keepalived.conf(Master 节点)
vrrp_script check_nginx {
script "/usr/bin/killall -0 nginx"
interval 2
weight -20
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
virtual_ipaddress {
192.168.1.100
}
track_script {
check_nginx
}
}
第十一章 安全体系
11.1 HTTPS 安全加固
nginx
# TLS 安全最佳实践
ssl_protocols TLSv1.2 TLSv1.3; # 禁用旧协议
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:P-256;
# OCSP Stapling(加速证书验证)
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 valid=300s;
11.2 防 DDoS
nginx
# 连接级限制
limit_conn_zone $binary_remote_addr zone=ddos_conn:10m;
limit_conn ddos_conn 50; # 每 IP 50 连接
# 请求级限制
limit_req_zone $binary_remote_addr zone=ddos_req:10m rate=30r/s;
limit_req zone=ddos_req burst=50 nodelay;
11.3 防 CC 攻击
nginx
# 针对特定接口严格限流
location /api/login {
limit_req zone=strict_limit burst=5 nodelay; # 每秒2次
# 验证 User-Agent(拦截简单爬虫)
if ($http_user_agent ~* "curl|wget|python|scrapy") {
return 403;
}
}
11.4 安全 Header
nginx
server {
# 防止点击劫持
add_header X-Frame-Options "SAMEORIGIN" always;
# 防止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" always;
# XSS 防护
add_header X-XSS-Protection "1; mode=block" always;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# CSP 内容安全策略
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'" always;
# 隐藏 Nginx 版本号
server_tokens off;
}
11.5 限流与黑名单
nginx
# 使用 geo 模块定义黑名单
geo $blocked_ip {
default 0;
1.2.3.4 1;
5.6.7.0/24 1;
}
server {
if ($blocked_ip) {
return 444; # 直接关闭连接,不返回任何内容
}
}
# 或使用外部文件
# include /etc/nginx/blocklist.conf;
第十二章 运维与部署
12.1 配置热更新
bash
# 平滑重载(不中断服务)
nginx -t && nginx -s reload
# 原理:
# 1. Master 读取新配置
# 2. 启动新的 Worker 进程
# 3. 旧 Worker 处理完当前请求后退出
# 4. 全程不中断已建立的连接
12.2 滚动发布
nginx
upstream backend {
server 10.0.0.1:8080; # 先更新这台
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
# 滚动流程:
# 1. 标记 server1 为 down → reload
# 2. 更新 server1 应用
# 3. 恢复 server1 → reload
# 4. 对 server2、server3 重复
12.3 灰度发布
nginx
upstream stable { server 10.0.0.1:8080; }
upstream canary { server 10.0.0.2:8080; }
# 方式一:按 Cookie
map $cookie_version $backend {
"canary" canary;
default stable;
}
# 方式二:按 IP 百分比
split_clients "$remote_addr" $backend {
10% canary; # 10% 流量到金丝雀
* stable; # 90% 流量到稳定版
}
server {
location / {
proxy_pass http://$backend;
}
}
12.4 Docker 部署
dockerfile
# Dockerfile
FROM nginx:1.24-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY conf.d/ /etc/nginx/conf.d/
COPY html/ /usr/share/nginx/html/
EXPOSE 80 443
yaml
# docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:1.24-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./conf.d:/etc/nginx/conf.d:ro
- ./ssl:/etc/nginx/ssl:ro
- ./logs:/var/log/nginx
restart: unless-stopped
12.5 Kubernetes 部署
yaml
# Ingress Controller(K8s 中 Nginx 的典型用法)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts: [app.example.com]
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
第十三章 故障排查
13.1 启动失败
bash
# 检查配置语法
nginx -t
# 常见原因:
# - 配置文件语法错误(缺少分号、括号不匹配)
# - 端口被占用(见13.2)
# - 权限不足(80端口需要root)
# - 证书文件路径错误或证书过期
13.2 端口占用
bash
# 查看端口占用
sudo lsof -i :80
sudo netstat -tlnp | grep :80
sudo ss -tlnp | grep :80
# 终止占用进程
sudo kill -9 <PID>
# 或修改 Nginx 监听端口
13.3 403 错误
bash
# 排查清单:
# 1. 文件权限:Nginx Worker 用户是否有读权限
ls -la /var/www/html/
chmod -R 755 /var/www/html/
chown -R nginx:nginx /var/www/html/
# 2. SELinux 限制(CentOS)
getenforce
setsebool -P httpd_read_user_content 1
# 或临时关闭:setenforce 0
# 3. 没有 index 文件且未开启 autoindex
# 4. allow/deny 规则拦截
13.4 404 错误
bash
# 排查清单:
# 1. root 路径配置错误
# 2. location 匹配不到
# 3. try_files 配置问题(SPA 应用常见)
# 4. proxy_pass URI 拼接错误(带不带 / 的区别)
# 调试:开启 debug 日志
error_log /var/log/nginx/error.log debug;
13.5 502 / 504 错误
bash
# 502 Bad Gateway:后端服务没响应
# 排查:
# 1. 后端服务是否启动
curl http://127.0.0.1:8080/health
# 2. upstream 地址是否正确
# 3. 后端服务是否崩溃(查看后端日志)
# 504 Gateway Timeout:后端响应超时
# 解决:调大超时时间
proxy_connect_timeout 60s;
proxy_read_timeout 120s;
proxy_send_timeout 60s;
13.6 域名解析问题
bash
# 检查 DNS 解析
nslookup example.com
dig example.com
# Nginx 中使用域名做 upstream 时的坑:
# Nginx 启动时解析一次 DNS,之后不再更新!
# 解决方案:
resolver 8.8.8.8 valid=30s;
set $backend "http://dynamic-host.example.com";
proxy_pass $backend; # 使用变量才会触发动态解析
13.7 性能瓶颈分析
bash
# 查看 Nginx 连接状态
curl http://localhost/nginx_status
# 查看系统资源
top -p $(pgrep -d, nginx) # CPU/内存
ss -s # 连接统计
ulimit -n # 文件描述符上限
# 常见瓶颈及解决:
# - worker_connections 不够 → 增大
# - 文件描述符不够 → ulimit -n 65535
# - CPU 满 → 检查 gzip level、正则匹配
# - 内存不够 → 减小 buffer、限制缓存大小
# - 磁盘 I/O → 开启 sendfile、使用 SSD
第十四章 进阶扩展
14.1 OpenResty(Lua)
OpenResty = Nginx + LuaJIT,支持在 Nginx 中嵌入 Lua 代码,实现复杂业务逻辑。
nginx
# 使用 Lua 实现动态限流
location /api/ {
access_by_lua_block {
local limit = require "resty.limit.req"
local lim, err = limit.new("my_limit", 100, 50)
local delay, err = lim:incoming(ngx.var.remote_addr, true)
if not delay then
return ngx.exit(429)
end
}
proxy_pass http://backend;
}
# 使用 Lua 操作 Redis
location /cache {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:connect("127.0.0.1", 6379)
local val = red:get("my_key")
ngx.say(val)
}
}
Lua 执行阶段:
| 阶段 | 指令 | 用途 |
|---|---|---|
| rewrite | rewrite_by_lua |
URL 重写 |
| access | access_by_lua |
鉴权、限流 |
| content | content_by_lua |
生成响应内容 |
| log | log_by_lua |
自定义日志 |
| header_filter | header_filter_by_lua |
修改响应头 |
| body_filter | body_filter_by_lua |
修改响应体 |
14.2 动态配置
nginx
# 使用 Consul + consul-template 动态更新 upstream
# consul-template 模板:
upstream backend {
{{range service "web"}}
server {{.Address}}:{{.Port}};
{{end}}
}
# 或使用 Nginx Plus 的动态 upstream API
# 或使用 OpenResty + lua-resty-dns 动态解析
14.3 API 网关实现
nginx
# 完整的 API 网关配置
server {
listen 443 ssl;
# 统一鉴权
location /api/ {
access_by_lua_block {
local token = ngx.req.get_headers()["Authorization"]
if not token then return ngx.exit(401) end
-- 验证 JWT token...
}
# 限流
limit_req zone=api burst=20 nodelay;
# 路由转发
location /api/user/ { proxy_pass http://user_svc; }
location /api/order/ { proxy_pass http://order_svc; }
location /api/product/ { proxy_pass http://product_svc; }
}
}
14.4 HTTP/2 与 HTTP/3
nginx
# HTTP/2(需要 HTTPS)
server {
listen 443 ssl http2;
# http2_push /css/style.css; # Server Push(已被弃用)
# http2_max_concurrent_streams 128;
}
# HTTP/3(QUIC,Nginx 1.25+)
server {
listen 443 ssl;
listen 443 quic reuseport; # QUIC 监听
ssl_protocols TLSv1.3; # HTTP/3 要求 TLS 1.3
add_header Alt-Svc 'h3=":443"; ma=86400'; # 告知浏览器支持 HTTP/3
# 开启 0-RTT(加速连接建立)
ssl_early_data on;
}
14.5 模块开发
c
// 自定义模块基本结构(C 语言)
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
ngx_str_t response = ngx_string("Hello from custom module!");
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
ngx_http_send_header(r);
ngx_buf_t *b = ngx_create_temp_buf(r->pool, response.len);
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;
b->last_buf = 1;
ngx_chain_t out = { .buf = b, .next = NULL };
return ngx_http_output_filter(r, &out);
}
常用第三方模块:
| 模块 | 功能 |
|---|---|
| ngx_cache_purge | 手动清除缓存 |
| ngx_brotli | Brotli 压缩(比 gzip 更优) |
| headers-more | 灵活操作 HTTP 头 |
| lua-nginx-module | 嵌入 Lua 脚本 |
| njs | 嵌入 JavaScript |
第十五章 对比与选型
15.1 Nginx vs Apache
| 维度 | Nginx | Apache |
|---|---|---|
| 架构 | 事件驱动,异步非阻塞 | 进程/线程模型(prefork/worker) |
| 并发能力 | 数万级 | 千级 |
| 内存消耗 | 极低 | 较高 |
| 静态文件 | 极快 | 较慢 |
| 动态内容 | 需反代到后端 | 直接集成(mod_php) |
| .htaccess | ❌ 不支持 | ✅ 支持 |
| 模块加载 | 编译时确定(动态模块需重编译) | 运行时动态加载 |
| 适用场景 | 高并发、反向代理、负载均衡 | 传统 PHP 项目、共享主机 |
结论 :新项目首选 Nginx;老旧 PHP 项目或需要 .htaccess 时用 Apache。
15.2 Nginx vs Tomcat
| 维度 | Nginx | Tomcat |
|---|---|---|
| 定位 | Web Server / 反向代理 | Java Servlet 容器 |
| 静态文件 | 极强 | 较弱 |
| 动态内容 | 不直接处理 | 运行 Java 应用 |
| 并发能力 | 数万级 | 数百到数千 |
典型组合 :Client → Nginx(SSL终端 + 静态资源 + 负载均衡) → Tomcat(Java 应用)
15.3 Nginx vs Envoy
| 维度 | Nginx | Envoy |
|---|---|---|
| 开发语言 | C | C++ |
| 配置方式 | 静态文件 | 动态 API(xDS) |
| 服务发现 | 需第三方 | 原生支持 |
| 可观测性 | 基础 | 丰富(分布式追踪、指标) |
| 热更新 | reload(微秒级中断) | 热重启(零中断) |
| 适用场景 | 通用 Web/反向代理/LB | Service Mesh(Istio Sidecar) |
选型建议:
- 传统 Web 项目:Nginx(成熟稳定、资料丰富)
- 云原生/Service Mesh:Envoy(Istio 默认 Sidecar)
- 需要 Lua 扩展:OpenResty(Nginx + Lua)
- 需要商业支持:Nginx Plus
附录:生产环境完整配置模板
nginx
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 65535;
multi_accept on;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
# ── 日志 ──
log_format main '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent $request_time';
access_log /var/log/nginx/access.log main;
# ── 性能 ──
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
# ── 压缩 ──
gzip on;
gzip_vary on;
gzip_min_length 1k;
gzip_comp_level 4;
gzip_types text/plain text/css application/json
application/javascript text/xml image/svg+xml;
# ── 安全 ──
server_tokens off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
# ── 限流 ──
limit_req_zone $binary_remote_addr zone=global:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;
# ── 缓存 ──
proxy_cache_path /var/cache/nginx levels=1:2
keys_zone=cache:10m max_size=5g inactive=60m;
# ── 引入站点配置 ──
include /etc/nginx/conf.d/*.conf;
}