Appearance
第4章 Nginx 与应用访问排障
对应简历:技能第 4 条「熟悉 Nginx……的部署和日志分析,熟悉登录失败、连接超时、服务异常等典型问题的排查路径」;项目一职责「输出部署指南与常见问题文档」、P1-2「处理登录失败、服务不可用等问题,定位问题层级」。 支持版定位:用户报"系统打不开/登录不上/页面报错",入口几乎都是 Nginx——本章把 502/504/登录异常/日志分析/证书问题五条链路背成条件反射,负载均衡只保留基础一节。 实操背景:银行数币平台前端就是 Nginx 1.25.1 源码编译(统信 ARM)+ 80 跳 443 + 证书 + /prod-api/ 反代后端 8080,本章案例全部出在这个真实环境。
4.1 Nginx 基础与排障入口 【必背】
标准回答:Nginx 是高性能 HTTP 服务器和反向代理,架构是"master + worker 事件驱动":master 管配置加载、端口绑定和 worker 的创建回收,worker 单线程 epoll 处理海量连接,worker 崩了 master 自动补起——这套架构决定了它排障的两个入口:配置入口(nginx.conf 及 include 的 conf.d)和进程入口(master/worker 状态)。 支持岗的排障动作有个固定开场三连:nginx -t 校验配置语法——任何配置变更前后必跑,语法错误 master 会拒绝加载新配置、继续用旧配置运行,是最安全的失败形态;ps -ef | grep nginx 看 master 和 worker 进程在不在;ss -lntp | grep :443 确认端口在监听。 再看两类日志:access_log 记每个请求(状态码、耗时、来源),error_log 记 Nginx 自身错误(upstream 连不上、证书加载失败、权限拒绝),四个入口覆盖 Nginx 类报障的九成。
还有两个支持场景高频动作要会说:nginx -s reload 平滑重载——master 先校验新配置、起新 worker 加载、老 worker 处理完存量连接再退出,服务不断线,改完配置的标准动作是"nginx -t → reload → tail error_log + curl 验证"三连收尾;nginx -V 看编译参数——确认 ssl、stream、stub_status 模块在不在,我编译部署的 Nginx 1.25.1 这些模块是一次配齐的。
追问链:
- 追问1:改了配置 reload 没生效,可能是什么? → 答:按可能性三查:一是改错了文件——nginx.conf include 了 conf.d 下多个文件,改的不是实际生效的那个,
nginx -T(大写)能把全部生效配置 dump 出来核对,这是最稳的验证;二是 reload 前没跑 nginx -t,配置有语法错被 master 拒绝加载,error_log 里有记录、服务继续用旧配置——所以"改完没生效又没报错"先看 error_log;三是改的指令层级不对,比如 server_name 冲突被别的 server 块抢了匹配。我的变更纪律是"nginx -t 校验 → reload → nginx -T 核对 → curl 验证"四步,一步不少。 - 追问2:Nginx 起不来报 "bind() to 0.0.0.0:443 failed (98: Address already in use)"? → 答:端口被占用,
ss -lntp | grep :443找到占用进程分三种处理:是残留的旧 Nginx——正常 stop 掉再启;是别的服务规划冲突——改 Nginx 监听端口(我们银行项目负载均衡监听 16443 而不是 6443 就是同样的端口避让逻辑);是 TIME_WAIT 堆积——加 reuseport 或等回收。生产上动端口前先确认归属,这是变更纪律:kill 占用进程是最后手段,且要确认那不是别人的业务。 - 追问3:worker 进程数和连接数怎么理解,排障时用得上吗? → 答:worker 数等于 CPU 核数(worker_processes auto),理论并发 = worker 数 × worker_connections。排障时它有三个用途:报 Too many open files 是句柄上限不够,要配 worker_rlimit_nofile 和系统 ulimit;连接数异常增长要对比 worker_connections 和实际连接水位;worker 反复崩溃看 error_log 是配置段错误还是资源耗尽。理解架构不是为了背参数,是为了报障时知道"哪一层的行为对应哪个配置"——这是把 Nginx 从黑盒变白盒的过程。
关联话术:"银行数币平台的 Nginx 是我在统信 ARM 环境源码编译部署的:./configure 带 ssl、stub_status、stream 模块,80 端口 301 跳 443、443 挂客户 CA 证书服务前端静态页、/prod-api/ 反代本地 8080 后端 jar——这套结构是我亲手搭的,所以本章每条排查链我都能对着自己的配置讲。 "
实操模板(排障开场三连,背熟):
bash
nginx -t && nginx -s reload # 校验后平滑重载
ps -ef | grep [n]ginx # master/worker 在不在
ss -lntp | grep -E ':80|:443' # 端口监听
tail -n 50 /var/log/nginx/error.log # 自身错误
nginx -T 2>/dev/null | grep -n 'proxy_pass' # 核对生效配置4.2 502 Bad Gateway 排查链路 【必背】
标准回答:502 的含义是"Nginx 作为代理,从后端拿到了无效响应或根本连不上后端"——一句话:后端死了或不可达,方向明确。 我的排查链五步:第一步看后端进程:ps -ef | grep java(或 jps -l)确认后端 jar/服务活着,进程没了就是第一答案——后端崩溃或被 OOM 杀掉(dmesg | grep -i kill 交叉验证);第二步看后端端口:ss -lntp | grep :8080 确认在监听且监听地址正确——很多应用重启后绑定失败或只听 127.0.0.1,Nginx 就连不上;第三步看 Nginx error_log:connect() failed / connection refused / no live upstreams 这些原文直接指出失败类型——refused 是后端没听,timeout 是后端太慢(那是 504 方向),no live upstreams 是健康检查把后端全摘了;第四步看 SELinux 和防火墙:Nginx 作为代理进程被 SELinux 拦截网络连接是经典坑(ausearch -m avc 查),内网防火墙变更也可能拦掉 Nginx 到后端的流量;第五步看后端自己的崩溃日志:OOM 前的 GC 日志、启动失败的堆栈,把根因递给开发或二线。
经验分布上"后端没起或崩了"占 502 的大多数——所以前两步是最快的定位动作,两分钟内能回答七成案例。 支持岗处理 502 的产出标准:确定是哪台后端、什么失败类型(拒绝连接/无响应/被摘除)、根因在哪一层、是恢复还是转派。
追问链:
- 追问1:怎么快速确认是哪台后端出的 502? → 答:靠 access_log 的 $upstream_addr 变量——它记录每个请求实际命中的后端地址,我的 log_format 永远带着这个变量("日志为排障而设计")。
grep ' 502 ' access.log | awk '{print $NF}' | sort | uniq -c按 upstream_addr 统计,502 集中在哪台一目了然;再到那台机器上 curl 后端端口复现验证。如果日志没配 upstream_addr,就只能逐台 curl 排除——所以交付时配好日志格式,是给未来的自己省时间。 - 追问2:后端进程在、端口也听着,还是 502? → 答:往下查三层:一是后端"假活"——进程在但线程池/连接池耗尽、应用内部死锁,TCP 能握手但应用不处理,curl 后端一个健康接口或真实接口看返回什么(挂起还是 5xx),这种要抓线程栈(jstack)转开发;二是 Nginx 到后端路径被拦——SELinux avc 拒绝、iptables 出方向规则,在 Nginx 主机上 curl 后端端口验证;三是 proxy_pass 配置错误——端口写错、路径拼接错,nginx -T 核对生效配置。层层递进的逻辑是"每一步排除一个变量",502 的疑难杂症都能这样收敛。
- 追问3:用户报 502,你的第一步动作和第一句话是什么? → 答:第一动作不是敲命令,是确认影响面——"所有用户都打不开还是部分功能报错?"全站 502 是后端全挂,按应急处理;个别接口 502 是特定后端问题,按普通工单走。第一句话是给预期:"我在查后端服务状态,两分钟内给您结论"——支持岗的响应节奏感很重要:502 这类问题定位极快,快速给一句"后端服务异常,正在重启恢复"比闷头查五分钟体验好得多。技术能力和沟通节奏是支持岗的两条腿,这个题我特意把沟通放在答案里。
关联话术:"502 是我在银行驻场处理频率最高的访问类故障:数币平台后端 jar 偶发被 OOM 杀掉,我的处理路径固定在五步链里——ps、ss、error_log 三连两分钟定位,低峰重启恢复,OOM 证据交给开发调内存。 '先定位层级、再给用户预期、最后归因转派'这个节奏,就是支持岗处理 502 的完整动作。"
实操模板(502 五步链,背熟):
bash
ps -ef | grep java; jps -l # 1 后端进程
ss -lntp | grep :8080 # 2 后端端口与监听地址
tail -n 30 /var/log/nginx/error.log # 3 失败类型原文
grep ' 502 ' /var/log/nginx/access.log | awk '{print $NF}' | sort | uniq -c # 哪台后端
ausearch -m avc -ts recent 2>/dev/null | tail -5 # 4 SELinux 拦截
curl -v --max-time 3 http://127.0.0.1:8080/health # 后端直连复现4.3 504 Gateway Timeout 与"页面慢"排查 【必背】
标准回答:504 的含义和 502 一句话区分:502 是后端死,504 是后端慢——TCP 连接建立了(或正在建立)但在 proxy_read_timeout 窗口内没等到完整响应。 排查方向因此完全不同:504 第一步看是"谁慢"——日志里对比 $request_time 和 $upstream_response_time:两者接近且都大,慢在后端应用本身;request_time 远大于 upstream_response_time,慢在 Nginx 收发或网络传输。 第二步慢在后端就下钻:应用慢日志、慢 SQL(第 3 章路径三)、GC 频率、后端主机 CPU/IO——504 的根因多数在数据库慢查询和代码效率上,运维侧能做的是把它精确定位到"哪个接口、慢多少毫秒、卡在哪一段"。 第三步应急手段:确认是"偶尔慢的长任务"还是"普遍变慢"——前者按需调大 proxy_read_timeout 给长任务让路(导出报表这类场景),后者要限流或扩容保护,不能简单调超时掩盖问题。 第四步预防:给关键接口配耗时监控和慢接口清单,把 504 消灭在用户报障之前。
"页面慢"的报障还要考虑 504 之外的形态:个别资源慢(看 access_log 里耗时 TOP 的 URL)、首次慢后续快(冷启动/缓存问题)、特定时间慢(定时任务挤占资源)——慢的"形状"比慢的"数值"更有诊断价值。
追问链:
- 追问1:大量 499 出现说明什么? → 答:499 是 Nginx 特有状态码:客户端在 Nginx 返回响应前主动断开了连接——"客户不等了"。两个高频成因:后端太慢,客户端(浏览器或上游调用方)超时先撤——大量 499 往往伴随后端 504,本质是同一个慢;客户端自己的超时设得比 Nginx 响应时间短。看到 499 我的第一动作是统计它的 URL 和时段分布,判断是不是某几个慢接口拖的,然后到客户端侧核对超时配置。499 和 504 是同一枚硬币的两面:一个记录客户放弃,一个记录 Nginx 放弃,都指向后端耗时。
- 追问2:proxy_read_timeout 调多大合适?调大有什么风险? → 答:默认 60 秒,是否调大看业务形态:报表导出、文件处理这类合法长任务可以给到 300 秒甚至更长,并且最好给长任务单独的 location 配置而不是全局调大;全局调大的风险是真正的故障(后端卡死)也要等满超时才释放连接,故障感知变慢、连接堆积。配套动作是长任务异步化——提交任务立刻返回、后台执行、轮询结果,这才是根治。我调超时参数的原则:"超时是保护机制,调大是给例外开窗,开窗要有范围"。
- 追问3:用户说"时快时慢",怎么查? → 答:用日志把"快慢"量化:access_log 里按 $request_time 排序看 TOP 慢请求集中在哪些 URL、哪些时段、命中哪台后端(upstream_addr)——如果慢集中在某台后端,是那台的问题(负载不均、资源差);集中在某时段,看那个时段的定时任务或流量高峰;集中在特定接口,把接口名交给开发查代码。用户口中的"时快时慢"翻译成日志语言就是"request_time 的分布长什么样"——分布一出来,快慢的规律立刻可见。这是把主观报障变成客观证据的典型手法。
关联话术:"慢类报障在支持岗占比很高,我的价值是把'感觉慢'变成'哪里慢多少':银行平台一次'系统很卡'的报障,我用 access_log 的耗时统计十分钟定位到报表接口的慢 SQL(全表扫描),给出'接口名 + 平均耗时 + 慢 SQL 指纹'交给开发——当天加索引恢复。 支持岗不写业务代码,但能把慢的问题精确递到写代码的人手上。"
4.4 登录异常排查链路 【必背】
标准回答:"无法登录"是驻场支持最高频的复合型报障——它可能是网络、入口、应用、会话、证书任何一层的问题,我的排查链按"从入口往里、从网络到应用"七步走,这是我在银行驻场两年打磨出来的固定路径。 第一步用户侧网络:用户到平台入口能不能通——ping/telnet 平台地址 443 端口(用户电脑上测或让用户配合测),不通是网络层问题(VPN、代理、网段隔离);第二步入口层:Nginx 进程和 443 监听是否正常、证书是否过期(浏览器报证书错误是用户最常描述的"打不开");第三步后端服务:jps/ps 确认后端 jar 活着、8080 在监听;第四步后端日志:登录接口的报错——数据库连接失败、Redis 连接失败、认证服务超时各指向不同组件,错误堆栈直接给方向;第五步数据库层:Vastbase 主备有没有切换过、连接是否正常(第 3 章路径一/二);第六步会话与中间件:Redis 存 session 的场景,Redis 挂了或被清空的表现是"登录成功但马上被踢出/一直跳回登录页"——"登不进去"和"登录后维持不住会话"是两种不同故障;第七步证书链:平台内部组件间用 TLS 的(BCS 证书转 p12 给 Java 用),证书到期会表现为特定功能认证失败。
这条链的实战价值是分层给预期:走完前三步(两分钟)就能告诉用户"问题在服务端还是网络端、影响多大";走完全链(十分钟)能定位到具体组件。 登录类报障用户焦虑度高,"快速给阶段结论"和"最终定位"同样重要。
追问链:
- 追问1:用户说"能登录但一会就掉,反复跳回登录页",查什么? → 答:这是会话保持问题,方向和"登不进去"完全不同:查 session 存储——Redis 是否正常、key 有没有被过期策略清掉、maxmemory 淘汰策略是否把 session 挤掉了(session 和缓存混用一个 Redis 且淘汰策略是 allkeys-lru 的经典事故);查会话粘性——负载均衡多后端且 session 存本机时,请求被分到另一台就丢会话,解法是 session 外置 Redis 或 ip_hash;查 Cookie 域和 HTTPS——Secure Cookie 在 HTTP 下不发送、域不匹配也会导致会话丢失。我在数币平台排查过一次"部分用户反复掉线",根因就是 session 和缓存共用 Redis 且 maxmemory 淘汰把 session 挤掉了——拆实例后根治。
- 追问2:部分用户登录失败、部分正常,怎么定位? → 答:"部分"是金贵线索,先找差异维度:按网络维度——失败的用户是不是同一办公区/同一 VPN 出口(网络层差异);按浏览器维度——是不是特定浏览器或旧版本(前端兼容、证书链:严格校验的 Java 和老安卓对不完整证书链报错);按账号维度——是不是同一批账号(账号锁定、密码过期、权限差异)。做法是拿一个失败用户做对照实验:同一台电脑换浏览器试、同一账号换网络试,两个变量一交叉,问题层基本就锁定了。"全量故障查服务,部分故障查差异"是我处理这类问题的分叉口诀。
- 追问3:证书过期导致的"无法登录"有什么特征?怎么提前防? → 答:特征是浏览器明确报证书警告(NET::ERR_CERT_DATE_INVALID 或"您的连接不是私密连接"),且所有用户、所有网络都一样,curl -v 能看到证书校验失败——和"页面 502"的现象完全不同,问一句"浏览器是不是提示证书不安全"就能预判。排查用
openssl s_client -connect 域名:443 -servername 域名 2>/dev/null | openssl x509 -noout -dates远程看线上实际生效证书的起止日期——注意要看线上而不是看服务器上的文件(文件可能换了没 reload)。预防是自动化:证书到期监控配 30 天/7 天两级告警,续期流程固化进 SOP——证书过期是"低级但致命"的故障,靠日历记必漏,我把它做成了巡检脚本固定项。
关联话术:"登录异常链路是我驻场简历最实的支撑:银行项目两年,'用户报无法登录'我处理过很多次,七步链让我平均五分钟内定位到层——项目一职责原文里'处理登录失败、服务不可用等问题,定位问题层级'写的就是这件事。 面试官问这条,我能从用户侧网络一路讲到 Redis 会话,每一层都有真实案例对应。"
实操模板(登录异常七步,背熟):
bash
# 1 用户侧: ping/telnet 平台IP 443(用户电脑执行)
# 2 入口: ss -lntp | grep :443; openssl s_client -connect <域名>:443 | openssl x509 -noout -dates
ps -ef | grep java; ss -lntp | grep :8080 # 3 后端进程与端口
tail -n 100 app.log | grep -iE 'login|error' # 4 后端日志
mysql -e "select 1"; redis-cli -a '****' ping # 5/6 数据库与Redis连通
# 7 内部证书: openssl x509 -in xxx.p12 相关组件证书有效期4.5 access/error 日志分析 【必背】
标准回答:Nginx 两类日志分工:access_log 记录每个请求——默认格式有客户端 IP、时间、请求行、状态码、字节数、referer、UA;error_log 记 Nginx 自身错误——upstream 连接失败、证书问题、权限拒绝都在这。 我的 log_format 在默认基础上追加三个排障变量:$upstream_addr(请求实际命中的后端——定位哪台机器出问题的钥匙)、$request_time 和 $upstream_response_time(总耗时和纯后端耗时——两者一减就把"慢在 Nginx 还是后端"分开了)。 分析的高频管道五条:TOP IP(awk '{print $1}' | sort | uniq -c | sort -nr | head)、状态码分布(awk '{s[$9]++} END{for(c in s) print c,s[c]}')、5xx 明细与趋势、慢请求 TOP(按 request_time 排序)、某后端的错误集中度(按 upstream_addr 分组统计 5xx)。
支持岗用日志的标准姿势是"先分型再下钻":报障来了先看状态码分布——502 集中是后端死、504 集中是后端慢、403 是权限、499 是客户端等不及,状态码把报障分成四条已知路径;再看时间分布——故障从几点开始,和变更记录对时间线;最后按 URL 和 upstream_addr 收窄到具体接口和后端。 日志分析不追求一次全查,追求每一条管道都指向下一个动作。
追问链:
- 追问1:日志里全是代理 IP 看不到真实客户端怎么办? → 答:反代场景的必然现象——Nginx 记的是直连者。解决两步:如果 Nginx 前面还有一层(云 CLB 或其他代理),让上层透传 X-Forwarded-For,Nginx 用 $http_x_forwarded_for 记录真实来源;Nginx 到后端的应用日志同理透传 X-Real-IP 和 X-Forwarded-For(proxy_set_header 两个头),后端日志格式改取透传值。多级代理时 XFF 是逗号分隔的链,取第一个才是原始客户端——这个细节我在数币平台配过后端日志格式,是实际配过的人才会注意的点。
- 追问2:怎么统计"某接口过去一小时的 5xx 率"? → 答:按时间窗过滤加分组计数:
grep '/prod-api/report' access.log | awk '$9>=500{c++} END{print c}'拿 5xx 数,总请求数去掉 5xx 条件再算一遍,两者相除;要按分钟趋势就把时间字段 substr 到小时分钟再 uniq -c。更实用的姿势是"分母分子一起看":5xx 绝对数涨但流量也涨、比率稳定,可能是正常波动;比率突然抬升才是真异常——支持岗报数据永远带比率,避免用绝对数吓人或漏报。 - 追问3:error_log 里 "connect() failed (111: Connection refused) while connecting to upstream" 怎么解读? → 答:逐段读:connect() failed 是动作失败,111 Connection refused 是内核明确拒绝——目标地址可达但那个端口没人监听,while connecting to upstream 指明发生在连后端阶段。结论:去后端机器查进程和监听(对应 4.2 第一步第二步)。同一位置还可能看到 (110: Connection timed out)——包发出去没回应,方向是后端主机宕机、防火墙 DROP 或链路问题;upstream timed out 是连接建立了但响应超时,方向是后端慢(504 方向)。error_log 的每条报错都是"动作 + 系统错误码 + 阶段"三段结构,读得懂这个结构,Nginx 排障就有地图。
关联话术:"日志分析是支持岗的基本功中的基本功:银行平台的 access/error 日志格式是我设计的——upstream_addr、request_time、upstream_response_time 三件套进 log_format,后来的每一次故障定位都在吃这个设计红利。 '日志为排障而设计'这句话我会在面试里说,它体现的是支持岗的提前量意识。"
实操模板(日志分析五连,背熟):
bash
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head # TOP IP
awk '{s[$9]++} END{for(c in s) print c,s[c]}' access.log | sort -k2 -nr # 状态码分布
awk '$9>=500' access.log | grep -oE '^\[.*\] "GET [^ ]+' | head # 5xx样本
awk '{print $NF,$9}' access.log | grep ' 50[24]' | sort | uniq -c | sort -rn | head # 后端×状态码
awk '$(NF-2)>1.0{print $7,$(NF-2)}' access.log | sort -k2 -rn | head # 慢请求TOP4.6 证书问题排查(过期/SAN/链不完整)【必背】
标准回答:证书类故障我按三种形态讲排查。 第一种过期:特征是浏览器明确报证书警告、所有用户一致,openssl s_client -connect 域名:443 -servername 域名 2>/dev/null | openssl x509 -noout -dates 看线上实际生效证书的 notAfter——注意必须远程探测线上行为而不是看磁盘文件,文件换了没 reload 的"假更新"就靠这一步抓出来。 处理:更换证书文件 → nginx -t 校验 → reload(平滑不断线)→ curl 或 openssl 验证新证书生效。 第二种 SAN 不匹配:特征是"用 A 地址访问报错、用 B 地址正常"——证书的 SAN 字段决定它对哪些域名和 IP 有效,我在银行项目踩过真实一课:单 master 升多 master 后用 VIP 连集群报 x509 错误,openssl x509 -in apiserver.crt -text -noout 看 SAN 列表里没有新 VIP,重新按含 certSANs 的配置签发后解决——教训是"改访问入口地址必须先想证书"。 第三种链不完整:特征是"浏览器正常、Java 客户端或部分老设备报证书链无法验证"——服务器只发了叶子证书没带中间证书,openssl s_client 输出里数证书张数(-showcerts),补齐完整链(叶子 + 中间)解决。
预防统一收口到自动化:证书到期监控 30 天/7 天两级告警、巡检脚本对全部 HTTPS 入口出"域名-到期日"清单、续期走 SOP——证书是"不响不闹到点就炸"的典型,必须工具管不能靠记性。
追问链:
- 追问1:证书换完 reload 后部分用户还是看到旧证书? → 答:三个排查点:一是确认 reload 真的成功——nginx -t 加 error_log,reload 失败会继续用旧配置;二是确认用户访问的入口就是这台——域名解析到多个 IP、CDN 缓存了旧证书、或者用户配了代理,让用户
openssl s_client或浏览器证书详情看生效证书的序列号和有效期对比服务器端;三是浏览器或中间设备缓存——证书本身一般不被缓存但 HSTS 和会话复用(ssl_session_cache)会话票证可能让个别客户端短时间表现异常,等 session timeout 或让用户清状态验证。这个题考的是"分层验证线上行为"的思维:证书问题的证据永远以"用户实际收到的证书"为准。 - 追问2:内部系统用自签证书要注意什么? → 答:三点:信任分发——自签 CA 的证书要导入客户端信任库(Windows 走组策略分发、Linux 放 /etc/pki 或 update-ca-certificates),否则每个客户端都报不信任;SAN 齐全——自签也要把所有访问用的 IP 和域名写进 SAN,我银行项目的 certSANs 坑就是没写全;有效期管理——自签证书没有 CA 方到期提醒,更要进监控清单。银行环境用客户内部 CA 签发、我负责部署和到期更换,这套流程我跑熟了;公网系统则直接用正规 CA 的免费或付费证书,各有各的合规口径。
关联话术:"证书坑是我面试最爱讲的案例之一:SAN 缺失导致 VIP 连集群报错,从 curl -k 能通但 kubectl 报 x509 的现象,到 openssl 看 SAN、重新签发的完整闭环——这个案例的完整版在项目一笔记里,它证明的是'入口一变、先想证书'这条纪律是我用真实事故换来的。 "
4.7 常见状态码速查(403/404/499/301)【理解】
标准回答:状态码是访问排障的分诊台,支持岗要能把常见码翻译成排查方向。 403 Forbidden:Nginx 层高频原因是目录权限(Nginx worker 用户对文件无读权限——chown 到 nginx 运行用户或放宽 r)、autoindex 未开且无默认首页(index 配置)、allow/deny 访问控制拦截;应用层的 403 是业务权限,转开发。 404 Not Found:先分"该不该 404"——资源真不存在还是路径配错;前端单页应用刷新 404 是 history 路由问题,try_files $uri $uri/ /index.html 一行解决(我在数币平台上线时真实踩过并成为交付标配);反代前缀拼接错(proxy_pass 尾斜杠剥不剥)也会造成后端 404。 499:客户端等不及先断开,指向后端慢或客户端超时太短(4.3 已详述)。 301/302:跳转——我的 80 跳 443 用 301 permanent 让浏览器记住;"改了跳转用户还是走老地址"多半是浏览器缓存了 301,清缓存或用 302 过渡。 排障动作标准化:拿到报障先问"具体什么码",码定了方向就定了——这也是我培训客户自助报障时的固定要求:报障带上状态码和截图。
追问链:
- 追问1:静态文件 403,文件权限明明是 644? → 答:644 只保证"有读权限的任何人能读",还要看三样:路径上每一级目录对 Nginx worker 用户有 x(穿越)权限——namei -l 逐级看;worker 进程的实际运行用户是谁(ps 看,默认 nginx 或 www-data,root 起的 master 不代表 worker 是 root);SELinux——文件安全标签和进程域不匹配会拒绝读,ausearch -m avc 确认。三层查完基本必有答案。这类题的高频陷阱就是"只看文件本身权限,忘了目录穿越和 SELinux",我能把三层讲全,说明真排查过。
- 追问2:proxy_pass 尾斜杠的坑怎么讲清楚? → 答:规则一句话:
proxy_pass http://backend/;带尾斜杠时,location 匹配的前缀会被剥掉再拼接;不带斜杠则完整 URI 原样传递。举例:location /prod-api/ + 带斜杠,请求 /prod-api/user/login 到后端变成 /user/login;不带斜杠变成 /prod-api/user/login。带不带取决于前端 baseURL 和后端 context-path 的约定——数币平台前端 baseURL 是 /prod-api、后端根路径,我用带斜杠剥前缀。配错的统一现象是接口全 404。这是 Nginx 配置题里我必举的坑,因为它真实咬过我。
关联话术:"状态码分诊是我给公司 IT 支持团队做过的一次小培训内容:报障三要素——网址、状态码、截图,有这三样我远程十分钟出结论。 让报障人学会提供有效信息,本身就是支持提效的一部分——这个观点配合我建的 FAQ 知识库(第 11 章),构成我'把支持做成体系'的完整叙事。 "
状态码速查表(分诊用,表格豁免背诵):
| 状态码 | 一句话含义 | 首选排查方向 |
|---|---|---|
| 200 | 正常 | — |
| 301/302 | 永久/临时跳转 | 301 被浏览器缓存:用户仍走老地址时清缓存或改用 302 过渡 |
| 403 | 拒绝访问 | 目录穿越权限 → worker 运行用户 → SELinux(namei -l / ausearch) |
| 404 | 资源不存在 | 真没有还是路径错;前端刷新 404 上 try_files;反代尾斜杠核对 |
| 499 | 客户端等不及先断开 | 后端慢或客户端超时过短,统计 URL 分布(4.3) |
| 500 | 后端内部错误 | 看应用异常日志定位堆栈,转开发 |
| 502 | 后端死/无效响应 | 后端进程 → 端口 → error_log → SELinux(4.2 五步链) |
| 503 | 服务不可用 | 限流触发(limit_req)或负载均衡后端全摘除 |
| 504 | 后端慢超时 | 慢 SQL/GC/耗时对比分析(4.3) |
4.8 负载均衡基础(upstream 与高可用入口)【理解】
标准回答:支持岗对负载均衡要掌握到"能看懂、会验证"的程度。 upstream 是 Nginx 的后端服务器组:默认轮询,weight 调权重,backup 备份节点平时不接流量、全挂了才顶上,max_fails/fail_timeout 做"被动健康检查"——转发失败计数到阈值就在时间窗内摘除,开源版没有主动探测,这是和商业版的边界。 我银行项目还配过四层负载:stream 块只认 IP 和端口做 TCP 转发,apiserver 三台 master 的入口就是 Nginx stream 监听 16443 加 Keepalived VIP——Keepalived 用 VRRP 协议让主备共享一个 VIP,主挂了 VIP 漂到备,配 vrrp_script 检测真实服务端口(16443 有没有进程监听)防止"Keepalived 活着但 Nginx 死了"的假高可用。 支持场景里验证负载均衡健康的三板斧:看流量分布——日志里按 upstream_addr 统计各后端请求数;看摘除状态——error_log 的 no live upstreams 或控制台健康检查状态;做故障演练——停一台后端验证流量自动切走。
我的口径是"基础扎实、深度够用":策略选型、健康检查机制、VIP 漂移验证这些我能展开讲细节;LVS 四模式、DR 原理这类深度内容按了解层收口,被深挖用兜底话术。
追问链:
- 追问1:CLB 健康检查把节点摘了,用户访问 502/504,怎么处理? → 答:先看健康检查为什么失败——控制台看检查项配置(检查端口、路径、间隔、阈值),登后端验证该端口服务是否真的健康(curl 检查路径)。常见三类:检查路径配错(探的是 /health 但应用没实现这个路径)、后端真故障(服务挂了,走恢复流程)、检查太灵敏(偶发慢被误判,调大阈值或间隔)。摘除机制本身是保护:修复方向是"让后端真健康",而不是关健康检查——支持岗要能对客户解释"摘除是负载均衡在替你挡故障,我们的工作是修好被摘的那个节点"。项目二 CLB 对 apiserver 的健康检查我配置和演练过,这套话术是有实操底的。
- 追问2:Keepalived 的 VIP 漂移怎么验证? → 答:四步实测流程我做过:
ip addr确认 VIP 初始在主节点;主节点停 Nginx(或直接关机);备节点 ip addr 看到 VIP 漂过来;客户端持续访问验证业务无感(curl VIP 的服务端口)。配套检查脚本的设计要点:检测真实服务端口而不是 Keepalived 自身、interval 平衡灵敏度、weight 降权让 VIP 在服务异常时主动让位。验证完还要验证回切——主恢复后 VIP 是否抢回(默认抢占)。这套验证我在银行多 master 改造时完整做过,故障转移测试也是客户验收项。
关联话术:"负载均衡我按'两个真实方案'讲:银行项目 Nginx+Keepalived 的 VIP 入口(stream 四层 + 健康检查脚本 + 漂移实测)、移动云项目 CLB 托管入口(四层 6443 + 健康检查自动摘除)——自建和托管都做过,支持岗聊入口层故障就有双份底气。 深度细节(LVS 模式、脑裂防范)我知道边界在哪,需要时按了解层答。"
4.9 反向代理透传与真实客户端 IP 【理解】
标准回答:反代场景下"日志里全是代理 IP、后端拿不到真实用户"是高频问题,我按"原理 → 配置 → 验证与坑"三段讲。 原理:Nginx 作为反向代理,后端应用看到的 TCP 来源是 Nginx 而不是用户浏览器,所以必须靠 HTTP 头把真实来源"捎带"过去——约定俗成两个头:X-Real-IP 放真实客户端 IP(单值),X-Forwarded-For(XFF)是链式记录,每经过一层代理就追加一跳,多级代理时第一个值才是原始客户端。 配置:Nginx 侧加两行——proxy_set_header X-Real-IP $remote_addr; 和 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;(后者是"在已有 XFF 后追加当前一跳"的内置变量);后端应用从这两个头取值,应用日志格式也要相应配置,否则配了头也白配。 验证与坑:变更后用一个真实请求对照两端日志的 IP;两个经典坑——一是多级代理(CLB → Nginx → 应用)每一层都要透传,漏一层断一层,云 CLB 场景要确认它是否注入 XFF;二是 XFF 可以被请求方伪造,安全审计取值以第一跳可信代理的写入为准,不能盲信请求自带的头。 这个知识和 4.5 的日志分析直接联动:access_log 配上 $http_x_forwarded_for,才能在代理后面看清真实用户。
追问链:
- 追问1:为什么数币平台的日志格式要专门配这个? → 答:因为平台访问链路是"用户 → Nginx → 后端 jar",后端日志如果直接记 $remote_addr,记到的全是 Nginx 本机地址,来源分析和审计追踪全部失效。我部署时同时配了两处:Nginx 的 proxy_set_header 透传,后端应用的访问日志格式改为取 X-Real-IP;验证方法是客户端访问一次登录接口,两端日志对照看记录的 IP 是否一致——"配置后必验证"是我交付反代的固定动作,这类头配错不会报错、只会安静地记错数据,不验证根本发现不了。
4.10 入口变更纪律:校验、验证、可回滚 【理解】
标准回答:Nginx 配置变更是支持岗的高频动作,我的纪律是"三件套:校验、验证、可回滚",每条都有对应动作和原因。 校验:任何变更前 nginx -t 语法校验——它拦截语法错误(master 会拒绝加载坏配置、继续用旧配置运行,这是最安全的失败形态),但拦不住"语法对、语义错"(proxy_pass 写错端口这类),所以需要第二件。 验证:reload 后立即三连——curl 关键路径看状态码、tail error_log 看新报错、观察 access_log 五分钟看 5xx 是否抬升;重要变更(改 server 块、换证书)还要验证 HTTPS 证书链和 80 跳 443。 可回滚:改前 cp 一份 .conf.bak(配置进 git 更好),出问题一条 cp 加 nginx -t 加 reload 回退——回滚方案要预先想好而不是临场发挥,生产上"先想退路再动手"是纪律不是胆小。 这套三件套在银行客户环境是变更流程的硬要求:变更单写明步骤和回滚方案、操作逐步打勾——支持岗的变更不出事,靠的从来不是手稳,是流程。
追问链:
- 追问1:reload 失败会怎样?最危险的失败形态是什么? → 答:两种失败风险完全不同:语法错误——nginx -s reload 时 master 校验失败、拒绝加载并继续用旧配置,服务不中断但变更没生效,error_log 有记录,这是安全的失败;语义错误——语法通过、reload 成功,但流量打到错误目标(后端端口写错、location 顺序吃掉静态规则),服务"正常地错着",这是最危险的形态,因为它不报任何错。防线就是三件套:nginx -t 拦第一类,reload 后立即 curl 验证关键路径拦第二类,.bak 备份保证发现后一分钟内回退。我的习惯是变更后守五分钟日志再收工——这五分钟专门抓"安静地错着"的语义错误。
4.11 前后端联调高频问题:跨域(CORS)与资源加载 【理解】
标准回答:"系统打不开、接口全报错"有一类根因不在服务端而在浏览器策略,支持岗必须会认,否则后端会白查半天。 CORS 跨域:浏览器同源策略要求协议、域名、端口三者一致,前端页面和接口不同源时,浏览器先发预检请求(OPTIONS),后端必须返回 Access-Control-Allow-Origin 等响应头,否则请求被浏览器拦截——典型现象是"curl 直接调接口完全正常,浏览器里报 blocked by CORS policy"。 排查三步:看浏览器 console 报错是预检失败还是响应缺头;看后端有没有处理 OPTIONS 预检;看 Nginx 有没有统一配置 add_header Access-Control-Allow-*(常见做法是入口层统一加,注意两个坑:add_header 在 4xx/5xx 响应默认不生效要加 always 参数;Nginx 和后端都加会出现重复的 Allow-Origin 头,浏览器判定非法)。 资源加载类问题两件套:静态资源 404 多是路径或 baseURL 配置错、浏览器缓存旧版本——Ctrl+F5 强刷或无痕模式是第一招;HTTPS 页面引用 HTTP 资源被浏览器阻止(mixed content)在证书改造后常见,改资源链接或服务端升级。 这类问题的支持价值在"分诊":五分钟内告诉团队这是浏览器策略问题还是服务故障,方向对了才不浪费排查时间。
追问链:
- 追问1:Nginx 加了 CORS 响应头还是报跨域? → 答:三个高频原因按序查:一是 add_header 在非 2xx/3xx 响应默认不输出——预检 OPTIONS 或报错响应看不到头,要写成
add_header Access-Control-Allow-Origin $http_origin always;(always 让所有状态码都带头);二是头重复——Nginx 和后端各加了一次,浏览器看到两个 Allow-Origin 直接判非法,原则是只在入口层加一份;三是 OPTIONS 预检被 proxy_pass 转给后端而后端不认,在 Nginx 对 OPTIONS 直接返回 204 配合 CORS 头处理。定位方法是用curl -i -X OPTIONS -H "Origin: http://前端地址"直接看响应头实际返回了什么——比在浏览器里猜快得多,三个原因我都在联调支持里真实遇到过。
关联话术:"数币平台的架构是前端和接口同域(Nginx 同源托管前端静态页加 /prod-api/ 反代),从设计上回避了 CORS——这是我给后来项目的建议:入口统一同源反代是最省心的方案。 但联调期测试环境的跨域工单我处理过,'always 参数、头重复、预检 204'三个坑就是当时踩出来的,所以这一节我能讲到命令级。 "
4.12 本章案例
- 【真实项目·支持场景】上线首日"登录后刷新 404"(STAR,约 200 字):背景是数币平台前端上线当天,客户陆续反馈"登录后按 F5 刷新就 404,重新从首页进又正常"。任务是我作为驻场一线快速解决。行动:现象特征指向前端路由而非服务故障——验证 Nginx、后端、登录接口全部正常;确认前端用 history 路由模式,刷新时浏览器把 /user/list 这样的前端路径直接发给 Nginx 找文件,当然不存在;在 443 的 location 加
try_files $uri $uri/ /index.html;,reload 后验证各页面刷新均正常。结果:十分钟闭环,之后"try_files + 反代尾斜杠规则"成为我交付前端项目的标配检查项,这个坑再没出现过第二次。小故障见基本功:现象 → 原理(Nginx 按路径找文件 vs 前端路由是 JS 行为)→ 一行修复 → 固化为标准配置,完整闭环。 - 【真实项目】后端 OOM 引发的间歇性 502(STAR):背景是平台运行数周后用户偶发 502,无规律。任务:找出根因。行动:access_log 按 upstream_addr 统计确认 502 集中在单台后端;error_log 全是 connection refused;登后端发现进程消失,dmesg 有 OOM killer 记录——JVM 堆配置过大加上宿主机内存水位高,内核按策略杀进程;临时方案调小堆上限缓解,正式方案联合开发优化内存并调整宿主机资源分配。结果:502 绝迹,我把"502 → upstream_addr → dmesg OOM"的定位链写进 FAQ——间歇性故障的破案钥匙往往就是日志里的聚合统计。
- 【课程项目】LNMP 动静分离与日志分析实验:Nginx 按后缀拆 location 静态直出、动态反代,ab 压测对比吞吐;用 awk 管道把 access_log 做成 TOP IP/状态码分布/慢请求三张报表——再模拟后端宕机观察 502、调小 proxy_read_timeout 观察 504,把三类状态码的现象亲手造出来看一遍。这个实验把 4.2/4.3/4.5 的排查链路和 awk 分析命令全部跑成实操,面试描述时每个输出都有画面,可信度完全不同。
- 【经典故障】"改了证书用户还是看到旧的":换证书后个别用户浏览器仍报旧证书。定位:nginx -T 确认新配置已加载、openssl 远程探测线上证书已是新证书——最终发现用户访问走的是公司代理且代理侧缓存了会话,清代理缓存解决。教学点:证书问题的证据以"用户实际收到的证书"为准,排查要从服务器端延伸到用户侧链路。
章末自测清单(快问快答)
- Nginx 排障开场三连? → nginx -t 校验、ps 看 master/worker、ss 看端口监听。
- 502 和 504 一句话? → 502 后端死/无效响应(查进程端口),504 后端慢超时(查慢 SQL/GC/耗时)。
- 502 五步链? → 后端进程 → 后端端口监听 → error_log 失败类型 → SELinux/防火墙 → 后端崩溃日志。
- 定位哪台后端 502 靠什么? → access_log 的 $upstream_addr 分组统计;没配就逐台 curl。
- request_time 和 upstream_response_time 差很多说明? → 时间耗在 Nginx 收发/网络;两者接近都大是后端慢。
- 大量 499 说明什么? → 客户端等不及主动断开,多伴随后端慢或客户端超时过短。
- 无法登录七步链? → 用户网络 → 入口(Nginx/证书) → 后端进程 → 后端日志 → 数据库 → Redis 会话 → 内部证书。
- "登录后反复掉线"查什么? → session 存储(Redis 淘汰策略)、负载均衡会话粘性、Cookie 域与 HTTPS。
- 前端刷新 404 解法? →
try_files $uri $uri/ /index.html;(history 路由兜底回 index.html)。 - proxy_pass 尾斜杠规则? → 带斜杠剥 location 前缀,不带则原样传递;配错现象是接口全 404。
- 证书过期怎么防? → openssl 远程探测有效期 + 30/7 天两级告警 + 巡检清单自动化。
- 证书 SAN 不匹配的教训? → 改访问入口地址必须同步更新 certSANs;openssl x509 -text 看 SAN。
- 静态文件 403 三层查? → 目录穿越 x 权限(namei -l)→ worker 运行用户 → SELinux avc。
- error_log "111 Connection refused" 怎么读? → 动作失败+错误码+阶段三段:连后端被拒,后端端口没人听。
- upstream 被动健康检查是什么? → max_fails/fail_timeout:转发失败计数到阈值在时间窗内摘除,开源版无主动探测。
- VIP 漂移验证四步? → ip addr 看主 → 停主服务 → 备机看 VIP → 客户端持续访问无感。