面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

服务端阅读 05月27日 22:13

Nginx 如何进行安全配置?有哪些安全最佳实践?

Nginx 如何进行安全配置?有哪些安全最佳实践?核心思路是:隐藏信息、限制访问、加密传输、防御攻击,四层递进。一、隐藏服务器指纹攻击者第一步是信息收集,版本号是最直接的突破口。server_tokens off;关掉之后,响应头和错误页不再暴露 Nginx 版本。面试追问:还能怎么隐藏? 可以用 more_set_headers 模块改掉 Server 字段本身,或者在前端反代层抹掉这个头。二、访问控制与限流IP 限制和速率限制是防暴力攻击的第一道门。# IP 白名单location /admin { allow 192.168.1.0/24; deny all;}# 限流limit_req_zone $binary_remote_addr zone=req:10m rate=10r/s;limit_req zone=req burst=20 nodelay;limit_conn_zone $binary_remote_addr zone=conn:10m;limit_conn conn 10;面试追问:burst 和 nodelay 区别是什么? burst 允许突发排队,nodelay 让排队的请求立即处理而不延时等待,否则超出的请求会被延迟处理。三、SSL/TLS 与安全头HTTPS 是底线配置,安全头加固浏览器端防护。ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;ssl_prefer_server_ciphers on;ssl_session_cache shared:SSL:50m;ssl_session_tickets off;add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;add_header X-Frame-Options "SAMEORIGIN" always;add_header X-Content-Type-Options "nosniff" always;add_header Content-Security-Policy "default-src 'self'" always;面试追问:为什么关 sslsessiontickets? 默认的 session ticket key 是明文保存在 worker 共享内存中的,多台 Nginx 之间无法复用,且存在前向安全性问题。集群部署时应手动轮换 key 或直接关闭。四、文件与目录防护禁止访问隐藏文件和敏感后缀,堵住信息泄露的口子。location ~ /\. { deny all; }location ~* \.(htaccess|ini|log|sql|bak|swp)$ { deny all; }autoindex off;五、超时与缓冲区防止慢速攻击和缓冲区溢出。client_body_timeout 10;client_header_timeout 10;keepalive_timeout 5;send_timeout 10;client_max_body_size 10m;client_header_buffer_size 1k;面试追问:如果只改一个配置,改哪个? 先关 server_tokens,零成本高风险。然后上 HTTPS,这是生产环境硬性要求。限流和访问控制按业务场景逐步加。常见误区用 if 正则匹配 SQL 注入或 XSS 关键词来拦截攻击,这是错误的。Nginx 的 if 在 location 中行为不稳定,且正则容易被编码绕过。防注入应交给 WAF(如 ModSecurity)或应用层参数校验,Nginx 只做流量层防护。
服务端阅读 05月27日 22:13

Nginx 性能调优需要关注哪些关键参数?

Nginx 性能调优需要关注哪些关键参数?Nginx 调优的核心思路是:减少不必要的系统调用、充分利用内核零拷贝能力、压缩传输体积、避免连接浪费。下面按影响程度从大到小逐项说明。Worker 进程与连接worker_processes 设为 auto,让 Nginx 自动匹配 CPU 核心数。worker_rlimit_nofile 调到 100000,避免文件描述符耗尽。每个 worker 的 worker_connections 可设 65535,理论最大并发 = worker 数 × 65535。multi_accept on 让 worker 一次性接收所有就绪连接,accept_mutex off 在高并发下减少锁争用。worker_processes auto;worker_rlimit_nofile 100000;events { worker_connections 65535; use epoll; multi_accept on; accept_mutex off;}零拷贝与传输优化sendfile on 跳过用户态拷贝,数据从内核直接到 socket。tcp_nopush on 让数据攒满一个包再发,配合 sendfile 减少系统调用次数。tcp_nodelay on 禁用 Nagle 算法,避免小包延迟。三者同时开启并不矛盾:tcpnopush 在 sendfile 阶段生效,最后一个包由 tcpnodelay 立即发出。sendfile on;tcp_nopush on;tcp_nodelay on;Gzip 压缩压缩能将文本响应体积缩减 60%-80%,直接降低带宽和传输耗时。gzip_comp_level 建议设 4-6,再高收益递减但 CPU 开销上升。gzip_min_length 设 1024,避免压缩小响应反而变大。别忘了通过 gzip_types 覆盖 JSON、SVG 等常见 MIME 类型。gzip on;gzip_vary on;gzip_min_length 1024;gzip_comp_level 5;gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;连接复用与超时keepalive_timeout 控制客户端长连接保持时间,默认 75s,可视业务缩短到 30-60s。keepalive_requests 限制单连接最大请求数,防止连接泄漏。对上游服务器也要开长连接:upstream 块中 keepalive 32 保持 32 条空闲连接,减少反复握手开销。keepalive_timeout 60s;keepalive_requests 1000;upstream backend { server 10.0.0.1:8080; keepalive 32;}缓冲区与文件缓存client_body_buffer_size 和 client_header_buffer_size 按业务调整,过小会触发临时文件写入拖慢请求。open_file_cache 缓存频繁访问的文件描述符,减少磁盘 stat 调用,对静态资源场景效果显著。client_header_buffer_size 2k;client_body_buffer_size 128k;open_file_cache max=10000 inactive=20s;open_file_cache_valid 30s;open_file_cache_min_uses 2;日志降耗写日志是高并发下的隐性瓶颈。静态资源 access_log off 直接关掉;动态请求的日志加 buffer=32k flush=5s,写操作先进内存再批量落盘。追问:调了参数怎么验证效果?用 wrk 或 ab 做基准测试,对比调优前后的 QPS、P99 延迟和错误率。生产环境通过 stub_status 模块持续监控活跃连接数和请求处理量。记住一个原则:每次只改一个参数,观察效果后再改下一个,否则无法定位哪个改动真正有效。
服务端阅读 05月27日 22:13

Nginx 日志怎么配置?有哪些格式和优化方法?

Nginx 如何配置日志?有哪些日志格式和优化方法?Nginx 提供了访问日志(accesslog)和错误日志(errorlog)两种日志类型。面试中常考的是日志格式自定义、条件记录和性能优化三条主线。访问日志与自定义格式访问日志通过 log_format 定义格式,再用 access_log 引用。常用三种格式:main 格式:记录 IP、请求行、状态码、Referer、UA、耗时等基础信息detailed 格式:在 main 基础上增加 upstream 地址、状态、X-Forwarded-For、request_idJSON 格式:用 escape=json 转义,方便 ELK/Grafana Loki 等工具直接解析log_format main "$remote_addr - $remote_user [$time_local] " ""$request" $status $body_bytes_sent " ""$http_referer" "$http_user_agent" " "$request_time $upstream_response_time";log_format json_combined escape=json "{" ""time_local":"$time_local", ""remote_addr":"$remote_addr", ""request":"$request", ""status":"$status", ""request_time":"$request_time"" "}";access_log /var/log/nginx/access.log main;追问:accesslog 和 errorlog 有什么区别? accesslog 记录每次请求的详细信息,可自定义格式;errorlog 记录服务器错误,不支持自定义格式,只能设级别(debug/info/notice/warn/error/crit/alert/emerg)。日志性能优化高并发场景下日志写入会成为瓶颈,核心优化手段:关闭不必要的日志:静态资源、健康检查路径用 access_log off缓冲写入:access_log ... buffer=32k flush=5s,减少磁盘 I/O 次数gzip 压缩:access_log ... gzip=9,节省磁盘空间条件记录:用 map + if= 只记录特定状态码或慢请求map $status $loggable { ~^[23] 0; default 1;}access_log /var/log/nginx/access.log main if=$loggable;location ~* \.(css|js|jpg|png|gif|ico)$ { access_log off;}access_log /var/log/nginx/access.log main buffer=32k flush=5s;追问:buffer 和 flush 参数分别控制什么? buffer 控制缓冲区大小,写满才刷盘;flush 控制最大等待时间,超时强制刷盘。两者配合保证日志既不丢又不多写。日志轮转与分离单文件日志会无限增长,必须配合 logrotate 轮转:# /etc/logrotate.d/nginx/var/log/nginx/*.log { daily rotate 14 compress delaycompress missingok sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid) endscript}kill -USR1 让 Nginx 重新打开日志文件,不会中断服务。按业务分离日志同样重要:API 请求写独立文件,不同 server 块各写各的,便于精准排查问题。常用变量速查| 变量 | 说明 ||------|------|| $remoteaddr | 客户端 IP || $status | 响应状态码 || $requesttime | 请求总耗时 || $upstreamresponsetime | 上游响应时间 || $httpxforwarded_for | 真实客户端 IP |生产环境建议用 JSON 格式 + 缓冲写入 + logrotate 轮转 + 条件过滤,四板斧组合基本够用。
服务端阅读 05月27日 22:12

Nginx 监控运维怎么做?stub_status、Prometheus、ELK 怎么选?

答案前置:Nginx 监控运维的核心思路Nginx 监控围绕三条线展开:指标采集(stub_status / 日志)→ 存储与展示(Prometheus+Grafana / ELK / Zabbix)→ 告警与响应(阈值告警 + 自动化脚本)。面试中常考的不是你背了多少工具名,而是能不能说清楚每一步为什么这么做、不同规模场景怎么选型。内置指标:stub_status 能拿到什么?stub_status 是 Nginx 自带的状态模块,开启后在指定路径暴露一组关键指标:location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all;}访问后返回:Active connections(当前活跃连接数)、accepts/handled/requests(累计连接与请求数)、Reading/Writing/Waiting(读请求头、写响应、空闲等待的连接数)。追问:Waiting 数量大说明什么? 如果 Active connections ≈ Waiting,说明大量连接是 keep-alive 空闲态,连接复用率高是好事;但如果同时 Writing 偏低而请求排队,就要检查上游响应是否过慢。日志监控:比 stub_status 更细的粒度stubstatus 只有粗粒度指标,真正定位问题靠日志。关键是自定义 logformat 加入上游响应时间:log_format detailed '$remote_addr - [$time_local] "$request" $status ' 'rt=$request_time uct=$upstream_connect_time ' 'uht=$upstream_header_time urt=$upstream_response_time';access_log /var/log/nginx/detailed.log detailed;request_time 是总耗时,upstream_response_time 是上游处理耗时,两者差值就是 Nginx 自身开销。如果差值大,排查 Nginx 层面的缓冲、压缩或 DNS 解析。对于 ELK 场景,直接输出 JSON 格式日志省掉 Logstash 的 grok 解析:log_format json_log escape=json '{"time":"$time_local","ip":"$remote_addr",' '"status":$status,"rt":$request_time,"urt":"$upstream_response_time"}';access_log /var/log/nginx/json.log json_log;Prometheus + Grafana:云原生场景首选nginx-prometheus-exporter 把 stub_status 的指标转为 Prometheus 格式,Grafana 做可视化:# prometheus.ymlscrape_configs: - job_name: 'nginx' static_configs: - targets: ['localhost:9113']选型逻辑: 容器化/K8s 环境下 Prometheus 是事实标准,开箱即用 Service Discovery,Grafana 社区模板丰富。Nginx Plus 用户还可以用官方 nginx-plus-exporter 拿到更细的 upstream 指标。ELK Stack:日志深度分析场景当需求不只是看指标曲线,而是要按 IP、URL、状态码做聚合分析和历史追溯,ELK 更合适。Filebeat 采集 → Logstash 清洗 → Elasticsearch 存储 → Kibana 可视化,链路长但灵活度高。选型对比: Prometheus 适合指标型监控(数字曲线),ELK 适合日志型分析(文本检索+聚合)。小团队二选一推荐 Prometheus,监控告警闭环更短。Zabbix:传统企业环境的选择Zabbix 通过 Agent 调用 stub_status 页面,用正则提取指标配置监控项。适合已有 Zabbix 基建的企业,不推荐新项目为 Nginx 单独搭 Zabbix。告警:监控闭环的关键有监控没告警等于没监控。核心告警规则:5xx 比率超阈值(如 > 1%)触发 criticalActive connections 突增超过 2 倍标准差触发 warningupstreamresponsetime P99 > 2s 触发 warningPrometheus 用 Alertmanager 配路由和静默,ELK 用 Watcher 或 ElastAlert,Zabbix 自带触发器机制。运维常用命令速查nginx -t # 测试配置语法nginx -s reload # 平滑重载,不中断连接nginx -s quit # 优雅停止,处理完当前请求后退出nginx -s reopen # 重新打开日志文件(配合 logrotate)日志轮转用 logrotate,配置 postrotate 里发 USR1 信号让 Nginx 重新打开文件句柄,避免写入已轮转的老文件。面试追问方向stub_status 的 Waiting 和 keep-alive 是什么关系? Waiting 连接就是 keep-alive 空闲连接,keepalive_timeout 控制超时回收。Nginx 502 怎么排查? 先查 upstream 是否存活,再看 Nginx error log 里 connect() failed 的具体原因,最后检查 proxy_read_timeout 配置。如何不重启更新配置? nginx -t && nginx -s reload,reload 会 fork 新 worker 加载新配置,老 worker 处理完手头请求后退出。Prometheus 和 ELK 怎么选? 指标监控选 Prometheus(轻量、告警闭环好),日志分析选 ELK(全文检索、聚合灵活),大团队通常两套都搭。
服务端阅读 05月27日 22:12

Nginx 如何配置 WebSocket 代理?

Nginx 如何配置 WebSocket 代理?WebSocket 建立在 HTTP/1.1 之上,通过 Upgrade 机制将 HTTP 连接升级为全双工长连接。Nginx 默认会清除 Upgrade 头,所以必须手动配置才能正确代理 WebSocket。核心配置(三行必写)location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";}proxy_http_version 1.1:WebSocket 要求 HTTP/1.1,Nginx 默认用 1.0Upgrade $http_upgrade:转发客户端的协议升级请求Connection "upgrade":告知 Nginx 这不是普通 HTTP,需要保持升级状态推荐用 map 管理 Connection 头多 location 场景下,硬编码 "upgrade" 会导致非 WebSocket 请求也被标记。用 map 按需切换更安全:map $http_upgrade $connection_upgrade { default upgrade; '' close;}server { location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; }}没有 Upgrade 头时走 close,普通请求不受影响。超时:为什么连着连着就断了?Nginx 的 proxy_read_timeout 默认 60 秒。WebSocket 是长连接,如果 60 秒内没有数据传输,Nginx 会主动断开。解决办法:proxy_read_timeout 3600s; # 1小时proxy_send_timeout 3600s;proxy_connect_timeout 60s; # 建连超时保持短即可按业务调,不是越大越好。过长超时意味着僵死连接不会被回收。WSS(WebSocket over TLS)在 SSL server 块里照加那三行即可,Nginx 负责 TLS 卸载,后端仍用 ws://:server { listen 443 ssl; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; }}负载均衡要注意会话保持WebSocket 是有状态长连接,轮询策略会导致重连时切到不同后端。必须用 ip_hash:upstream ws_backend { ip_hash; server 10.0.0.1:8080; server 10.0.0.2:8080;}如果后端是无状态的(如用 Redis Pub/Sub 做消息同步),也可以用轮询。追问:连接断开怎么排查?查 Nginx error log,确认是否超时断开检查 Upgrade / Connection 头是否正确转发确认 proxy_buffering off 已设置,避免数据被缓冲检查防火墙或 CDN 是否拦截长连接用 curl -H "Upgrade: websocket" 手动测试握手是否返回 101
服务端阅读 05月27日 22:11

Nginx 反向代理怎么配置?

Nginx 反向代理怎么配置?反向代理是 Nginx 最核心的用途之一:客户端请求先到 Nginx,再由 Nginx 转发给后端服务器,客户端感知不到真实后端的存在。和正向代理(代理客户端出国)相反,反向代理代理的是服务端。最小可用配置server { listen 80; server_name example.com; location / { proxy_pass http://192.168.1.100:8080; 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_pass 指定后端地址,三条 proxy_set_header 是标配——不带这些头,后端拿到的全是 Nginx 的 IP,日志和鉴权都会出问题。多后端负载均衡upstream backend { server 192.168.1.100:8080 weight=3; server 192.168.1.101:8080 weight=1; server 192.168.1.102:8080 backup;}server { listen 80; location / { proxy_pass http://backend; }}四种策略选哪个?轮询(默认)无状态通用;ip_hash 保会话粘性但分布不均;least_conn 适合长连接;加权轮询按机器性能分配。生产环境常用加权轮询 + 健康检查。WebSocket 代理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 3600s;}不加 Upgrade 头,WebSocket 握手直接失败;proxy_read_timeout 不加长,空闲连接会被 Nginx 主动断开,这是最常见的踩坑点。面试追问:反向代理和正向代理的区别?反向代理代理服务端,客户端不知道真实后端是谁;正向代理代理客户端,服务端不知道真实客户端是谁。一句话:正向代理帮客户端藏身份,反向代理帮服务端藏身份。生产环境别漏这些超时三件套:proxy_connect_timeout、proxy_send_timeout、proxy_read_timeout,默认 60s,慢接口要调大缓冲默认开着,大文件上传场景注意 proxy_buffer_size 和 proxy_buffers 调大HTTPS 场景在 Nginx 做 SSL 终止,后端走内网 HTTP,证书只管 Nginx 一层proxy_redirect off 防止后端 302 重定向把内网地址暴露给客户端
服务端阅读 05月27日 22:10

Nginx 如何配置 HTTPS 和 SSL 证书?

答案Nginx 启用 HTTPS 的核心是在 server 块中监听 443 端口并指定证书与私钥路径:server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m;}同时配置 HTTP 自动跳转 HTTPS:server { listen 80; server_name example.com; return 301 https://$host$request_uri;}追问一:SSL 证书有哪些类型?怎么选?自签名证书:测试用,浏览器不信任Let's Encrypt:免费 DV 证书,90 天有效期,Certbot 自动申请与续期商业证书(OV/EV):CA 机构签发,验证组织身份,适合生产环境Let's Encrypt 申请示例:sudo certbot --nginx -d example.com -d www.example.com追问二:如何提升 HTTPS 安全性?四个关键措施:仅启用 TLS 1.2+,禁用 SSLv3 和 TLS 1.0HSTS 头,防止降级攻击:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;OCSP Stapling,减少证书验证延迟:ssl_stapling on; ssl_stapling_verify on;强密钥,至少 2048 位 RSA 或 256 位 ECC追问三:证书链不完整怎么办?浏览器验证证书需要完整的信任链。若缺少中间证书,需将服务器证书与中间证书合并:cat example.com.crt intermediate.crt > bundle.crtNginx 中指向合并后的文件:ssl_certificate /etc/nginx/ssl/bundle.crt;追问四:多域名如何共用证书?通配符证书(*.example.com)覆盖子域SAN 证书支持多个域名,Certbot 申请时加多个 -d 参数SNI(Server Name Indication)让同一 IP 托管多张证书,Nginx 原生支持配置验证用 nginx -t,无停机重载用 nginx -s reload。
服务端阅读 05月27日 21:52

Nginx 的事件驱动模型是什么?如何实现高并发?

答案Nginx 采用事件驱动 + 非阻塞 I/O 模型,核心是 Master-Worker 进程架构 + epoll 事件循环。每个 Worker 进程单线程运行一个事件循环,通过 epoll 同时监听数千个连接的读写事件,事件就绪时回调处理,I/O 等待期间不阻塞进程,从而用少量进程支撑数万并发连接。事件驱动核心机制epoll 的工作方式:内核维护一个就绪队列,只有活跃连接才会触发事件通知,时间复杂度 O(1)。与传统 select/poll 的 O(n) 轮询不同,epoll 不受 FD 数量影响——这正是 Nginx 解决 C10K 问题的根基。事件循环流程:Worker 进程启动 → 注册监听 FD 到 epoll → epoll_wait 阻塞等待事件 → 事件就绪返回 → 回调处理(accept/read/write) → 继续 epoll_wait连接状态机:每个连接在 Worker 内部以状态机方式管理,经历 等待读 → 处理请求 → 等待写 → 发送响应 → 等待新请求(keepalive) 的状态转换,I/O 等待时让出 CPU 给其他连接处理。Master-Worker 进程模型worker_processes auto; # 通常等于 CPU 核心数worker_rlimit_nofile 65535; # 文件描述符上限events { worker_connections 10240; # 单 Worker 最大连接数 use epoll; # Linux 选择 epoll multi_accept on; # 一次 accept 多个连接 accept_mutex off; # 高并发下关闭,减少锁争用}Master:管理 Worker 生命周期,加载配置,不处理业务请求Worker:各自独立运行事件循环,互不干扰,进程隔离保证稳定性理论并发:worker_processes × worker_connections,4 Worker × 10240 = 40960 并发与 Apache 的本质区别| 对比维度 | Nginx | Apache (prefork) ||---------|-------|------------------|| 模型 | 事件驱动,非阻塞 | 每连接一个进程,阻塞 || 内存 | 10 连接 vs 10 连点约 2MB | 10 连接约 200MB || C10K | 原生支持 | 受限于进程数 || 上下文切换 | 极少 | 频繁 |高并发调优关键参数worker_processes:设为 auto 或 CPU 核心数worker_connections:根据内存调整,通常 10240-65535accept_mutex:高并发下关闭(off),低并发开启防惊群系统级:fs.file-max、net.core.somaxconn、tcp_tw_reuse追问epoll 的 LT 和 ET 模式有什么区别?Nginx 默认用哪个? — LT 水平触发会重复通知,ET 边沿触发只通知一次,Nginx 默认 LT,配合非阻塞 I/O 确保数据读完为什么 Worker 单线程还能处理上万连接? — 因为 99% 时间连接在等 I/O,事件驱动只在 I/O 就绪时才占用 CPUaccept_mutex 是什么?什么时候该关? — 惊群控制锁,防止所有 Worker 同时争抢新连接。连接数远大于 Worker 数时关闭可提升吞吐
服务端阅读 05月27日 21:45

Nginx 的负载均衡有哪些策略?如何配置?

Nginx 负载均衡有哪些策略?如何配置?Nginx 通过 upstream 模块实现负载均衡,内置 5 种策略,另有第三方扩展策略。面试核心答案:轮询(默认)、加权轮询、最少连接、IP 哈希、一致性哈希。1. 轮询(Round Robin,默认)按顺序依次分配请求,服务器性能相近时使用。upstream backend { server 192.168.1.100:8080; server 192.168.1.101:8080;}2. 加权轮询(Weighted Round Robin)权重越高分配越多,适用于服务器性能不均。upstream backend { server 192.168.1.100:8080 weight=3; server 192.168.1.101:8080 weight=1;}3. 最少连接(Least Connections)将请求分给当前活动连接数最少的服务器,适用于请求处理时间差异大的场景。upstream backend { least_conn; server 192.168.1.100:8080; server 192.168.1.101:8080;}4. IP 哈希(IP Hash)同一客户端 IP 始终分配到同一台服务器,实现会话保持。upstream backend { ip_hash; server 192.168.1.100:8080; server 192.168.1.101:8080;}注意:ip_hash 在后端服务器增减时会导致大量请求重新分配,一致性哈希可解决此问题。5. 一致性哈希(Hash)基于指定 key(如 URI、Cookie)做哈希,consistent 参数启用一致性哈希算法,减少服务器变动时的映射抖动。upstream backend { hash $request_uri consistent; server 192.168.1.100:8080; server 192.168.1.101:8080;}服务器状态参数upstream backend { server 192.168.1.100:8080 weight=3 max_fails=3 fail_timeout=30s; server 192.168.1.101:8080 weight=2 max_fails=3 fail_timeout=30s; server 192.168.1.102:8080 down; # 永久下线 server 192.168.1.103:8080 backup; # 备用,主服务不可用时启用 server 192.168.1.104:8080 max_conns=100; # 最大并发连接数}策略选择速查| 场景 | 推荐策略 ||---|---|| 服务器性能相近 | 轮询 || 服务器性能不均 | 加权轮询 || 请求处理时间差异大 | 最少连接 || 需要会话保持 | IP 哈希 / 一致性哈希 || 需要缓存命中 | 一致性哈希(基于 URI) |完整配置示例http { upstream backend { least_conn; server 192.168.1.100:8080 weight=3 max_fails=3 fail_timeout=30s; server 192.168.1.101:8080 weight=2 max_fails=3 fail_timeout=30s; server 192.168.1.103:8080 backup; keepalive 32; } server { listen 80; server_name 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; } }}健康检查开源版 Nginx 仅支持被动健康检查(通过 max_fails / fail_timeout 判断),商业版 Nginx Plus 提供主动健康检查。面试追问Q:iphash 和一致性哈希的区别?iphash 以客户端 IP 为 key,后端变动时映射大规模失效;一致性哈希通过虚拟环减少变动影响,且可自定义 key(URI、Cookie 等),灵活性更高。Q:Nginx 负载均衡能做四层转发吗?能。使用 stream 模块可做 TCP/UDP 四层负载均衡,配置方式与 HTTP 的 upstream 类似。Q:如何实现更精细的会话保持?Nginx Plus 支持 sticky cookie 指令;开源版可配合一致性哈希 hash $cookie_jsessionid consistent 实现基于 Cookie 的会话粘滞。
服务端阅读 02月21日 16:58

Nginx 如何优化静态资源?有哪些优化策略?

Nginx 如何优化静态资源?有哪些优化策略?Nginx 在提供静态资源方面表现优异,通过合理的配置可以显著提升静态资源的加载速度和用户体验。启用高效文件传输:http { # 启用 sendfile sendfile on; # 启用 tcp_nopush tcp_nopush on; # 启用 tcp_nodelay tcp_nodelay on; server { listen 80; server_name example.com; root /var/www/html; location / { try_files $uri $uri/ =404; } }}Gzip 压缩:http { # 启用 Gzip gzip on; gzip_vary on; gzip_min_length 1024; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml; gzip_disable "msie6"; # 静态资源预压缩 gzip_static on; server { listen 80; server_name example.com; root /var/www/html; location / { try_files $uri $uri/ =404; } }}浏览器缓存:server { listen 80; server_name example.com; root /var/www/html; # 静态资源长期缓存 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # HTML 文件短期缓存 location ~* \.html$ { expires 1h; add_header Cache-Control "public, must-revalidate"; } # 不缓存动态内容 location ~* \.php$ { expires off; add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"; } location / { try_files $uri $uri/ =404; }}文件缓存:http { # 打开文件缓存 open_file_cache max=100000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; server { listen 80; server_name example.com; root /var/www/html; location / { try_files $uri $uri/ =404; } }}静态资源分离:server { listen 80; server_name example.com; # 主站点 location / { root /var/www/html; try_files $uri $uri/ =404; } # 静态资源 location /static/ { root /var/www/static; expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # 图片资源 location /images/ { root /var/www/images; expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # 字体文件 location /fonts/ { root /var/www/fonts; expires 1y; add_header Cache-Control "public, immutable"; access_log off; add_header Access-Control-Allow-Origin *; }}CDN 集成:server { listen 80; server_name example.com; root /var/www/html; # 重写静态资源 URL 到 CDN location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { return 301 https://cdn.example.com$request_uri; } location / { try_files $uri $uri/ =404; }}图片优化:server { listen 80; server_name example.com; root /var/www/html; # 图片缓存 location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; # WebP 支持 if ($http_accept ~* "webp") { rewrite ^(.+)\.(jpg|png)$ $1.webp last; } } # 图片防盗链 location ~* \.(jpg|jpeg|png|gif)$ { valid_referers none blocked example.com *.example.com; if ($invalid_referer) { return 403; } } location / { try_files $uri $uri/ =404; }}字体文件优化:server { listen 80; server_name example.com; root /var/www/html; # 字体文件 location ~* \.(woff|woff2|ttf|otf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; # CORS 支持 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "GET, OPTIONS"; add_header Access-Control-Allow-Headers "Origin, Content-Type"; } location / { try_files $uri $uri/ =404; }}静态资源预加载:server { listen 80; server_name example.com; root /var/www/html; location = / { add_header Link "</style.css>; rel=preload; as=style, </script.js>; rel=preload; as=script, </image.jpg>; rel=preload; as=image"; try_files $uri $uri/ =404; } location / { try_files $uri $uri/ =404; }}HTTP/2 推送:server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; root /var/www/html; # HTTP/2 推送 location = / { http2_push /style.css; http2_push /script.js; http2_push /image.jpg; try_files $uri $uri/ =404; } location / { try_files $uri $uri/ =404; }}静态资源合并:# 使用第三方模块 ngx_http_concat_moduleserver { listen 80; server_name example.com; root /var/www/html; # CSS 合并 location /static/css/ { concat on; concat_types text/css; concat_unique on; concat_max_files 10; } # JS 合并 location /static/js/ { concat on; concat_types application/javascript; concat_unique on; concat_max_files 10; } location / { try_files $uri $uri/ =404; }}完整静态资源优化配置:user nginx;worker_processes auto;worker_rlimit_nofile 65535;events { worker_connections 10240; use epoll; multi_accept on;}http { # 基础优化 sendfile on; tcp_nopush on; tcp_nodelay on; # Gzip 压缩 gzip on; gzip_vary on; gzip_min_length 1024; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml; gzip_disable "msie6"; gzip_static on; # 文件缓存 open_file_cache max=100000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; # 静态资源长期缓存 map $sent_http_content_type $expires { default off; text/html 1h; text/css 1y; application/javascript 1y; ~image/ 1y; ~font/ 1y; } server { listen 80; server_name example.com; root /var/www/html; index index.html; # 静态资源优化 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires $expires; add_header Cache-Control "public, immutable"; access_log off; } # 字体文件 CORS location ~* \.(woff|woff2|ttf|otf|eot)$ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "GET, OPTIONS"; add_header Access-Control-Allow-Headers "Origin, Content-Type"; } # 图片防盗链 location ~* \.(jpg|jpeg|png|gif)$ { valid_referers none blocked example.com *.example.com; if ($invalid_referer) { return 403; } } # 主路由 location / { try_files $uri $uri/ =404; } # 禁止访问隐藏文件 location ~ /\. { deny all; access_log off; log_not_found off; } }}静态资源优化最佳实践:启用压缩:使用 Gzip 压缩文本资源合理缓存:根据资源类型设置缓存时间文件分离:将静态资源分离到独立域名或 CDN预压缩:使用 gzip_static 预压缩静态文件HTTP/2:启用 HTTP/2 提升加载速度图片优化:使用 WebP 格式,启用图片压缩字体优化:使用 WOFF2 格式,启用 CORS监控性能:使用 Lighthouse 等工具监控性能定期清理:清理未使用的静态资源版本控制:使用文件名哈希实现缓存更新