← 返回面试专题

🚑 502 / 503:网关报错与线上排障

核心目标:先止血,再定位根因,最后固化治理

🧩 场景题题干(面试官常用表述)

用户反馈:页面一直报 502。 你是后端值班同学,如何快速排查并恢复服务? 如果恢复后还会再次出现,你会怎么做长期治理?
💡 一句话思路:网关 502 是“网关到上游失败”的结果。排查要从入口层上游逐跳推进:Nginx/网关 → 应用实例/端口 → 进程/线程池/连接池 → 下游(DB/Redis/MQ) → 最近变更。

📚 学习正文:如何系统排查 502 / 503?

建议把排障过程分成两段: 1) 先止血(控制影响面与错误率) 2) 再定位(用日志+指标+验证命令闭环)

1) 现象与状态码含义(先把“现象”说清)

502 Bad Gateway : 代理请求上游失败(连接失败/非法响应/协议问题) 503 Unavailable : 上游不可用(无可用实例/健康检查失败/被熔断) 504 Timeout : 等上游超时(排队/慢 SQL/下游超时)
⚠️ 重点:状态码是入口观察到的结果,不等于根因。必须用“证据链”说服自己与面试官。

2) 总体排查路线(从入口逐跳推进)

入口(Nginx/网关) ↓ 上游可达性(DNS/端口/TLS) ↓ 应用状态(进程/日志/线程池/连接池/GC) ↓ 下游依赖(DB/Redis/MQ/第三方) ↓ 最近变更(发布/配置/证书/流量)

3) 先止血:让系统先“可用”再深挖

  1. 确认影响范围:全量/部分?是否某个接口?是否集中在某些实例?
  2. 快速止血:摘除异常实例、回滚最近发布、开启降级/限流/熔断。
  3. 再定位:错误率下降后,用日志+指标做根因定位与复现验证。

4) 常见根因速查表(看到日志就能快速归类)

5) 定位方法:最常用的“命令 + 证据链”

💡 目标:不是“猜原因”,而是把问题收敛到:
哪一个接口? 哪一批请求? 哪一台 upstream 实例(IP:PORT)? 是连接失败、无实例、还是超时? 如果是超时:卡在应用哪一层(线程池/连接池/DB/Redis/MQ/第三方)?

5.1 先用 Nginx Access Log 定位到“具体接口 + 具体 upstream”

⚠️ 关键前提:你的 access log 必须带上 upstream 相关字段,否则无法精确定位到哪台上游实例。建议在 Nginx 加上(示例字段,按环境调整):
log_format main '$remote_addr $request $status '
                'rt=$request_time urt=$upstream_response_time uct=$upstream_connect_time '
                'uaddr=$upstream_addr ustatus=$upstream_status '
                'reqid=$request_id';
你要从 access log 里拿到 3 个关键信息: 1) 哪个 URI/接口在大量报错(定位到具体接口) 2) 报错对应的 upstream_addr 是哪些(定位到具体实例) 3) request_time / upstream_response_time 分布(判断是否超时/排队)
# 1) 快速看 502/503 是否集中在某些 URI(示例:按 $7 取 URI,实际按你的 log_format 调整)
grep ' 502 ' /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head

# 2) 看 502 是否集中在某些 upstream(需要 access log 有 uaddr 字段)
grep ' 502 ' /var/log/nginx/access.log | grep 'uaddr=' | sed -n 's/.*uaddr=\([^ ]*\).*/\1/p' | sort | uniq -c | sort -nr | head

# 3) 抽样一条 502 请求,看它打到哪个 upstream、耗时多少
grep ' 502 ' /var/log/nginx/access.log | tail -n 5

5.2 再用 Nginx Error Log 判断“属于哪类失败”

常见错误日志关键词 → 推断方向: - connect() failed (111: Connection refused) → 进程/端口/安全策略 - no live upstream / upstream server temporarily disabled → 无可用实例/健康检查/熔断 - upstream timed out (110: Connection timed out) → 上游慢/排队/下游慢 - upstream sent invalid header → 协议/响应头/代理缓冲区
# 1) 在网关或同网段机器:验证上游是否可达
curl -v http://UPSTREAM_IP:PORT/actuator/health

# 2) 看网关错误日志(示例路径,按环境调整)
tail -n 200 /var/log/nginx/error.log

# 3) 上游机器:确认端口监听
lsof -i :8080
netstat -anp | grep 8080

# 4) 上游机器:查看服务日志/是否频繁重启(systemd 示例)
systemctl status your-service
journalctl -u your-service -n 200 --no-pager

5.3 追到“具体上游实例”后,怎么定位到“具体问题点”?

你已经从 access log 拿到 upstream_addr(例如 10.0.0.12:8080),接下来要在那台机器/那个容器上回答: 它是挂了?卡死了?还是被下游拖慢了?
# 线程/CPU:找 Java PID & 热线程(Linux)
ps -ef | grep java
top -Hp <PID>
printf '%x\n' <TID>
jstack <PID> | grep -n "nid=0x..." -n

# 连接数/FD(典型:FD 打满导致各种连接失败)
ulimit -n
lsof -p <PID> | wc -l

# 应用健康检查(建议接入 actuator/health)
curl -s http://127.0.0.1:8080/actuator/health

5.4 进一步下钻:判断是不是“下游把上游拖慢”

如果 Nginx 侧看到的是 timeout/RT 飙升,往往不是网关问题,而是: 应用线程在等 DB/Redis/MQ/第三方,或在等锁/等连接池。
💡 面试官喜欢的“闭环一句话”:“我先用 access log 精确定位到报错的 URI 与 upstream_addr,再用 error log 判断失败类型,然后到对应实例上用日志/指标/线程栈把根因收敛到线程池/连接池/下游慢点,最后用修复+治理把问题永久解决。”
⚠️ 面试官最想听到的:
我看到的日志是什么? 我做了什么验证? 验证结果是什么? 它如何支持“根因结论”?

6) 解决策略:短期修复与长期治理

短期:摘流异常实例 / 回滚变更 / 限流降级 / 关停高危接口 / 必要时扩容 长期:SLO 与告警 / 灰度与自动回滚 / 超时&重试治理 / 线程池隔离 / 容量评估 / 复盘机制

🎯 面试题(建议学完上面正文再做)

1. 502 / 503 / 504 的区别是什么?简单
  • 502 Bad Gateway:网关作为反向代理,向上游请求失败(连接被拒绝、上游返回非法响应、TLS/协议问题等)。
  • 503 Service Unavailable:上游明确不可用/被熔断/无可用实例(也可能是网关侧限流/熔断)。
  • 504 Gateway Timeout:网关等上游超时(上游卡住、慢 SQL、线程池耗尽、下游超时)。
⚠️ 面试加分点:强调“状态码只是现象”,一定要结合网关 error log、upstream 状态、RT、错误率定位根因。
2. 线上出现大量 502,你第一时间做什么(止血优先)?简单
  1. 确认影响范围:是否全量?是否某一条链路/接口?是否仅某地域/某机房?
  2. 确认是否持续:是瞬时抖动还是持续 5+ 分钟?
  3. 快速止血
    • 回滚最近发布(若和变更强相关)。
    • 从 LB 摘除异常实例、重启异常实例(如果明显挂了)。
    • 开启降级/限流/熔断,保证核心链路可用。
💡 面试表达:我会先让错误率下降、服务可用,再去做深入定位,避免“边查边炸”。
3. 你如何快速判断:问题在 Nginx/网关,还是在后端应用?中等
  1. 看网关错误日志:出现的是 connect refused、no live upstream、upstream timed out,还是 upstream sent invalid header。
  2. 直连上游:在网关机器上 curl 上游实例/端口(或从同网段跳板机 curl)。
  3. 对比实例维度:是否集中在某几台实例?如果是,通常是应用实例问题/资源问题。
# 在网关/同网段机器上:直连验证上游是否可达
curl -v http://UPSTREAM_IP:PORT/actuator/health

# 看网关 error log(示例路径)
tail -n 200 /var/log/nginx/error.log
4. 网关日志出现 connect() failed (111: Connection refused),你怎么排?中等
  • 端口是否监听:应用进程是否还在?端口是否在 LISTEN?
  • 是否被防火墙/安全组拦截:近期是否变更了安全策略?
  • 是否误发布到错误端口:应用配置端口与网关 upstream 配置不一致。
# 在上游机器上查看端口
lsof -i :8080
netstat -anp | grep 8080

# systemd 服务状态(如使用 systemd)
systemctl status your-service
journalctl -u your-service -n 200 --no-pager
5. 网关日志出现 upstream timed out,你如何判断是应用慢还是下游慢?困难
  1. 先看应用 RT 分布:P50/P95/P99 是否飙升;是否仅某接口。
  2. 看线程池/连接池:Tomcat/Netty 线程、DB 连接池、HTTP client pool 是否耗尽。
  3. 看下游耗时:DB 慢查询、Redis 阻塞、MQ 堆积、第三方接口超时。
  4. 用链路追踪/日志埋点:把总耗时拆成 DB、RPC、业务计算等分段耗时。
⚠️ 常见坑:应用看起来没报错,但线程池排队导致整体超时,网关会表现为 504/timeout。
6. 如果是“部分实例”持续 502,你会重点看哪些差异?中等
  • 版本差异:是否灰度导致版本不一致?
  • 配置差异:环境变量、配置中心、JVM 参数、连接串、DNS 解析结果。
  • 资源差异:CPU/内存/磁盘、FD 上限、是否发生 OOM 重启。
  • 网络差异:是否跨可用区,是否有丢包/ACL。
7. 给出一个“完美回答结构”(面试 2 分钟版本)困难
  1. 澄清现象:502 是否全量、持续多久、影响哪些接口、是否最近发布。
  2. 快速止血:摘除异常实例/回滚/限流降级,让错误率下降。
  3. 分层定位:网关日志 → 上游可达性(curl/端口)→ 应用状态(线程/GC/连接池)→ 下游(DB/Redis/MQ)。
  4. 根因与修复:例如连接池耗尽/慢 SQL/配置错误/证书过期。
  5. 长期治理:SLO/告警、灰度发布、容量评估、熔断降级、复盘机制。