主题
Nginx · 高频面试题(30+)
涵盖中前端、后端、运维 / SRE 三类岗位的真题。难度从 ⭐ 入门到 ⭐⭐⭐⭐⭐ 专家。每题都给"简短答案 + 展开"两种深度,你可以按场合(电话面 / 现场白板)选用。
🌱 入门题(⭐ — ⭐⭐)
1. Nginx 是什么?为什么比 Apache 快?
简短答:Nginx 是高性能 HTTP / 反向代理服务器;它用事件驱动 + 异步非阻塞模型,单进程靠 epoll 就能 hold 几万连接,而 Apache 默认是"一连接一线程"模型,并发上万就内存爆炸。
展开:
- Nginx:master + N 个 worker(N=CPU 核数),worker 是单线程事件循环
- Apache:传统 prefork(每连接一个进程,几 MB 一个)或 worker(线程,几百 KB 一个)
- 现代 Apache 也支持 event MPM,差距比以前小,但 Nginx 仍然是入口层默认选择
比喻:Apache 是"一桌一服务员",Nginx 是"一服务员看 50 桌,谁招手就过去"。
2. Nginx 是单线程还是多线程?
简短答:多进程 + 每进程单线程。1 个 master 进程 + N 个 worker 进程(N=CPU 核数),每个 worker 内部是事件循环(单线程)。
展开:
- master:负责读配置、管理 worker(启停)、处理信号
- worker:处理实际请求;每个 worker 是独立进程,崩了不影响别人
- 不同 worker 之间通过共享内存 / 文件锁协作
3. 正向代理 vs 反向代理?
简短答:
- 正向代理:代理客户端——你 → VPN → Google。服务器不知道真实客户端是谁。
- 反向代理:代理服务器——用户 → Nginx → 真正的后端。客户端不知道后端有几台。
记忆口诀:正向代客、反向代服。
4. nginx -s reload 和 restart 的区别?
简短答:
reload:master 进程重新读配置,启新 worker 处理新连接,老 worker 处理完老连接后优雅退出。不断连。restart:完全重启 nginx 进程,所有连接都被切断。
最佳实践:改完配置一定 nginx -t 测试语法,再 nginx -s reload。
5. 改了 nginx.conf 不 reload 会怎样?
答:不会生效。Nginx 是启动时读配置加载到内存,不会自动监听文件变化。reload 是显式命令。
6. Nginx 配置文件的层级结构?
答:5 层洋葱:
main
└─ events { ... }
└─ http {
└─ server {
└─ location { ... }
}
}外层指令默认被内层继承;内层重新定义会覆盖外层。
7. worker_processes 应该设几个?
答:auto(= CPU 核心数)是默认推荐值。
展开:
- CPU 密集型场景(SSL 终止、压缩多):
auto - I/O 密集型(大量代理 + keepalive):可以
2 × CPU 核数试试 - 单核小机器(学习):1 也行
8. 同一个端口能配多个网站吗?
答:能,靠 server_name 区分(虚拟主机):
nginx
server { listen 80; server_name a.com; ... }
server { listen 80; server_name b.com; ... }请求过来时 Nginx 根据 Host 头匹配 server_name。都没匹配上 → 走 default_server(如果声明)或第一个 server 块。
🌿 进阶题(⭐⭐⭐)
9. SPA history 模式刷新页面 404,怎么解决?
答:
nginx
location / {
try_files $uri $uri/ /index.html;
}原理:用户在 /about 刷新 → 浏览器真实发 GET /about → Nginx 在硬盘上找 /about 文件,找不到。try_files 让 Nginx 在找不到时回退到 /index.html,浏览器拿到 HTML → JS 跑起来 → 前端路由接管 → 渲染 /about。
10. root 和 alias 的区别?
答:
| 配置 | 请求 /static/foo.js 实际找的文件 |
|---|---|
location /static/ { root /var/www; } | /var/www/static/foo.js(保留前缀) |
location /static/ { alias /var/cdn/; } | /var/cdn/foo.js(截掉前缀) |
口诀:root = 在这个目录下找原 URL、alias = 把 URL 前缀替换成这个目录。
11. 怎么让浏览器和 CDN 强缓存静态资源?
答:构建工具输出文件名带 hash(app.a3f9.js)+ Nginx 设:
nginx
location ~* \.[a-f0-9]{8,}\.(js|css|png|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}immutable 让浏览器刷新都不再问服务器,是目前最强的缓存指令。
12. proxy_pass 末尾的 / 有什么影响?
答:
| 配置 | URL 行为 |
|---|---|
proxy_pass http://b/; | 截掉 location 前缀再拼路径 |
proxy_pass http://b; | 完整透传 URL |
例 location /api/ proxy_pass http://b/:访问 /api/users/1 → 后端收到 /users/1。
13. 怎么让后端拿到客户端真实 IP?
答:配 5 个 header:
nginx
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_set_header X-Forwarded-Host $host;后端读 X-Real-IP 或 X-Forwarded-For 第一个 IP。
14. X-Forwarded-For 能被伪造吗?怎么防?
答:能伪造。这是请求头,客户端能任意写。
防御:
- 入口的 Nginx 应该重写这个头,而不是拼接:nginx
proxy_set_header X-Forwarded-For $remote_addr; # 重写!别用 $proxy_add_x_forwarded_for - 后端只信任来自已知代理 IP的 X-Forwarded-For
- 业务上做"真实 IP + 行为"的多维度风控
15. Nginx 代理 WebSocket 要注意什么?
答:4 件事:
nginx
location /ws/ {
proxy_pass http://ws_backend/;
proxy_http_version 1.1; # 必须
proxy_set_header Upgrade $http_upgrade; # 透传
proxy_set_header Connection "upgrade"; # 改写
proxy_read_timeout 3600s; # 拉长超时
}少任何一个 → WS 第一时间断开。
16. Nginx 有哪些负载均衡算法?
答:
| 算法 | 关键字 | 场景 |
|---|---|---|
| 轮询(默认) | (无) | 通用 |
| 加权轮询 | weight=N | 机器配置异构 |
| IP 哈希 | ip_hash; | 老式会话粘性 |
| 最少连接 | least_conn; | 处理时长波动大 |
| 一致性哈希 | hash $key consistent | 缓存命中(需 Plus 或 OpenResty) |
17. ip_hash 解决会话粘性还有什么问题?
答:
- 移动用户 IP 频繁切换 → 频繁丢 session
- 公司 / 学校 / 家庭出口 IP 共享 → 多人挤一台后端,负载不均
- 后端节点变动会导致大量重哈希(不像一致性哈希那样温和)
现代做法:把 session 放 Redis,用任何算法都行。
18. Nginx 怎么剔除挂掉的后端?
答:
被动健康检查(开源版自带):
nginxupstream backend { server 10.0.0.1 max_fails=3 fail_timeout=30s; }主动健康检查(开源版没有!需要 Nginx Plus / Tengine / OpenResty):
nginxupstream backend { server 10.0.0.1; health_check uri=/healthz interval=5s; }
大厂生产一般用 Tengine 或 APISIX 替代开源版 Nginx,就为了主动健康检查。
19. 怎么让 Nginx 与上游用长连接?
答:3 件事配齐:
nginx
upstream backend {
keepalive 64; # ① 保持 64 条空闲长连接
}
location /api/ {
proxy_pass http://backend/;
proxy_http_version 1.1; # ② 必须 HTTP/1.1
proxy_set_header Connection ""; # ③ 清空 Connection 头
}20. location 5 种修饰符的优先级是?
答(必背):
= > ^~ + 最长前缀 > ~ / ~*(按文件顺序) > 普通最长前缀 > /精确 → 前缀阻断 → 正则按顺序 → 长前缀 → / 兜底。
21. ^~ 和 ~ 的区别?
答:
^~:前缀匹配(不是正则!)匹配上后不再尝试任何正则规则。~:正则匹配(区分大小写),按配置顺序找第一个。
22. if 在 location 里为啥被官方说"evil"?
答:
- 行为反直觉:
if (x = 1)在 location 里和在 server 里语义不同 - 容易写出死循环(rewrite 后再次匹配 if)
- 嵌套 if + rewrite 几乎无法预测
替代:能用 try_files / map 解决就别用 if。if 仅在配 return / rewrite 时算"可用"。
🌳 高级题(⭐⭐⭐⭐)
23. HTTPS 比 HTTP 慢吗?
答:握手会慢 1-2 个 RTT(TLS 1.3 是 1-RTT),但:
- HTTP/2 多路复用 → 实际加载更快
- OCSP Stapling → 减一次外联
- TLS 1.3 0-RTT → 能"零握手"复用会话
结论:现代 HTTPS 不是性能负担,反而整体更快。
24. HSTS 的作用?怎么部署?
答:HTTP Strict Transport Security——让浏览器记住"必须用 HTTPS 访问"。即使用户输 http://,浏览器也自动改成 https://。
nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;注意:是单向的——一旦设了 1 年,未来 1 年内你不能降级回 HTTP。新手谨慎,先 max-age=300 试试。
25. Let's Encrypt 证书怎么自动续签?
答:
bash
# certbot 自带定时任务(apt 装的会自动 enable systemd timer)
sudo systemctl list-timers | grep certbot
# 或者 cron:每天凌晨检查
0 2 * * * certbot renew --quiet && nginx -s reload证书 90 天有效期,certbot 在剩 30 天时才真签。
26. 强缓存 vs 协商缓存?
答:
- 强缓存:
Cache-Control: max-age=N/Expires。命中后不发请求,浏览器直接用本地。 - 协商缓存:
ETag/Last-Modified。每次都发请求,服务器对比后返 200(变了)或 304 Not Modified(不变)。
| 状态码 | 含义 |
|---|---|
| 200 (cache) | 强缓存命中(DevTools 显示 from disk/memory cache) |
| 304 | 协商缓存命中(不传 body) |
27. proxy_cache 缓存了登录态怎么办?
答:用 proxy_cache_bypass 排除带敏感头的请求:
nginx
proxy_cache_bypass $http_authorization $cookie_session;
proxy_no_cache $http_authorization $cookie_session;带 Authorization 头或 session cookie → 不命中缓存、也不写入缓存。
28. 怎么对接口做灰度发布(用 Nginx)?
答:用 split_clients + 多 upstream:
nginx
split_clients "${remote_addr}${http_user_agent}" $version {
5% "v2";
* "v1";
}
upstream v1 { server 10.0.0.1; }
upstream v2 { server 10.0.0.2; }
server {
location / {
proxy_pass http://$version;
}
}5% 用户去 v2,95% 还是 v1。也可按 cookie / 用户 ID hash 路由。
29. Nginx 怎么做限流?
答:两种限流:
nginx
# 1. 限请求数(滑动窗口)
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=20r/s;
server {
location /api/ {
limit_req zone=mylimit burst=40 nodelay; # 平时 20rps,可突发 40
}
}
# 2. 限连接数
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
limit_conn conn_limit 10; # 同一 IP 最多 10 条并发
}
}burst + nodelay 含义:把超出 rate 的请求放队列里,最多 burst 个;nodelay 让队列里的请求立刻发,不延迟(这个组合最常用)。
30. Nginx 的 if (...)、map、split_clients 各适合什么?
答:
| 指令 | 适合场景 | 一句话 |
|---|---|---|
if | 单一条件 + return / rewrite | 简单判断 |
map | 把变量映射成另一个变量(KV 表) | UA / Host / Path 多分支 |
split_clients | 按比例分流(A/B / 灰度) | 流量切分 |
map 例子:
nginx
map $http_user_agent $is_mobile {
default 0;
~*Mobile|Android|iPhone 1;
}
server {
location / {
if ($is_mobile) {
rewrite ^ /m$uri last;
}
}
}31. Nginx 怎么实现 CORS 跨域?
答:在 location 加响应头 + 处理 OPTIONS 预检:
nginx
location /api/ {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Max-Age 1728000;
add_header Content-Length 0;
return 204;
}
add_header Access-Control-Allow-Origin "*" always;
proxy_pass http://backend/;
}现代项目更推荐不要让前端跨域——同一个 Nginx 既挂前端又反代
/api,前端调/api就是同源,没有跨域问题(参见第 5 章)。
32. Nginx 默认进程数 auto 怎么算的?
答:取逻辑 CPU 核数(包括超线程的虚拟核)。在容器里有时会拿到宿主机的核数(比容器实际限制多),需要手动设:
nginx
worker_processes 4; # 或者读 /proc/self/cgroup33. Nginx 怎么排查"请求慢"?
答:3 步:
加
$request_time/$upstream_response_time到 access_log:nginxlog_format main '... rt=$request_time urt=$upstream_response_time';看慢请求 Top:
bashawk '{print $NF, $7}' access.log | sort -rn | head判断瓶颈:
request_time大、upstream_response_time小 → 客户端网络慢、SSL 握手慢- 两个都大 → 后端慢,去查后端
urt远大于request_time→ ……不可能(urt ≤ rt)
🎓 专家题(⭐⭐⭐⭐⭐)
34. Nginx 的事件驱动模型,为什么 epoll 比 select 快?
答:
- select:每次都把整个 fd 数组从用户态拷到内核,O(n) 遍历找就绪
- poll:同上,但用链表无 1024 限制
- epoll:内核维护红黑树 + 就绪链表,仅返回有事件的 fd,O(1)
epoll 还支持边缘触发(ET):只有 fd 状态变化时通知一次,配合非阻塞 I/O 性能极高。
35. 一个 Nginx worker 能扛多少连接?瓶颈在哪?
答:理论上 = worker_connections(默认 512,调大到 10240)。实际瓶颈:
- 文件描述符上限:
ulimit -n、worker_rlimit_nofile - 内存:每个连接约 1~10KB(含读写缓冲)
- CPU:上下文切换、TLS 握手算力
- 网络:网卡带宽 / 包率
- 后端:upstream 响应慢,连接堆积
单 Nginx 抗 10 万 - 100 万并发是常规水平(Cloudflare 单机更高)。
36. accept_mutex 是什么?现代要不要开?
答:早期 Linux 内核多 worker 同时 accept() 会有"惊群"问题——所有 worker 被唤醒,但只有一个能拿到连接。accept_mutex on 让 worker 排队 accept。
现代:Linux 3.9+ 支持 SO_REUSEPORT、Nginx 1.9.1+ 自动启用,没有惊群问题了 → accept_mutex off 性能更好。
37. Nginx 如何热升级(不停服务换二进制)?
答:6 步:
bash
# 1. 替换二进制(备份旧的)
cp /usr/sbin/nginx /usr/sbin/nginx.old
cp /path/to/new/nginx /usr/sbin/nginx
# 2. 给 master 发 USR2 信号 → 启动一个新 master + 新 worker(带 .oldbin pid 文件)
kill -USR2 $(cat /run/nginx.pid)
# 3. 让老 worker 优雅退出(处理完老连接)
kill -WINCH $(cat /run/nginx.pid.oldbin)
# 4. 验证新版本无问题后,让老 master 也退出
kill -QUIT $(cat /run/nginx.pid.oldbin)
# 5. 如果新版本有 bug,回滚:
kill -HUP $(cat /run/nginx.pid.oldbin) # 老 master 拉起新 worker
kill -QUIT $(cat /run/nginx.pid) # 干掉新 master原理:
USR2让老 masterfork+exec新 master,socket 文件描述符通过环境变量传递给新进程,所以新老版本可以同时监听 80 端口而不冲突。
38. Nginx Plus / Tengine / OpenResty / APISIX 的区别?
答:
| 产品 | 出身 | 关键差异 |
|---|---|---|
| Nginx 开源版 | 官方 | 基础 |
| Nginx Plus | 商业(F5) | 主动 health_check、动态 upstream、监控 |
| Tengine | 阿里 | 主动 health_check、动态共享、双 11 抗住 |
| OpenResty | 章亦春 | Nginx + LuaJIT,可在 Nginx 里写业务 |
| APISIX | Apache | 基于 OpenResty,云原生 API 网关、有控制台 |
选型:
- 个人 / 小项目 → 开源 Nginx
- 大流量、要主动健康检查 → Tengine
- 要在边缘写业务(限流、鉴权、WAF)→ OpenResty
- 现代 API 网关 → APISIX
39. 怎么让 Nginx 支持 HTTP/3 (QUIC)?
答:Nginx 1.25+ 默认编译支持 QUIC:
nginx
listen 443 ssl http2;
listen 443 quic reuseport; # ← QUIC 监听
add_header Alt-Svc 'h3=":443"; ma=86400'; # 通告浏览器升级到 H3
ssl_protocols TLSv1.3; # QUIC 仅支持 TLS 1.3QUIC 基于 UDP,握手更快、抗丢包更强(0-RTT 复用)。移动网络下提升明显。
40. Nginx 一次完整请求的生命周期?
答(11 阶段,经典面试题):
1. POST_READ 读完请求头
2. SERVER_REWRITE server 块的 rewrite
3. FIND_CONFIG 找 location
4. REWRITE location 内的 rewrite
5. POST_REWRITE 检查 rewrite 后是否要重新找 location
6. PREACCESS 限流 / 限连接(limit_req / limit_conn)
7. ACCESS 鉴权 / IP 黑白名单(auth_basic / allow / deny)
8. POST_ACCESS 检查 access 阶段结果
9. PRECONTENT try_files
10. CONTENT 生成响应(static / proxy_pass / fastcgi)
11. LOG 写 access logOpenResty 的强大就在于:可以在每个阶段插入 Lua 代码(
access_by_lua/content_by_lua等)。
🎯 终极题(白板手写题)
41. 白板:写一份生产级 Nginx 配置,要求支持
- HTTPS + HTTP/2 + HSTS
- 80 → 443 跳转
- SPA history fallback
- API 反向代理 + 负载均衡(3 后端,least_conn)
- WebSocket
- 静态资源 1 年强缓存
- 5xx 跳到自定义 50x.html
答案:见 10 章 · 实战 的
default.conf,能默写出来 = 拿到 Offer 的"决心证明"。
总结 · 学完这 41 题你会变成什么样
入门 ⭐ ─────► 知道 Nginx 是干嘛的
进阶 ⭐⭐⭐ ──► 能独立部署一个项目,看懂 nginx.conf
高级 ⭐⭐⭐⭐ ─► 能改大厂的网关配置,定位 5xx
专家 ⭐⭐⭐⭐⭐ ► 能讲事件模型 / 热升级 / 11 阶段,进 SRE / 架构组祝你拿 Offer! 🚀
回到入口 → 0 · README