第32章 排错决策树:502 / 504 / 握手失败 / 环路 / 泄漏

学习目标

  • 掌握代理排错的总方法论:沿生命周期分段二分定位
  • 备齐排错工具箱,知道每个工具看什么层
  • 用一棵决策树,从症状快速定位到根因
  • 把全书各章的故障场景收口成可操作的排查路径

前置知识


原理

总方法论:分段二分

代理把一条连接拆成两段(第01章):客户端→代理 和 代理→源站。排错第一步永远是确定故障在哪一段:

  客户端 ──①── 代理 ──②── 源站

  在代理上直接 curl 源站:
    通 → 问题在 ① 段(客户端到代理)
    不通 → 问题在 ② 段(代理到源站)

然后沿 第03章 的生命周期阶段(DNS→连接→认证→连源站→转发→回写)逐段二分,用 curl -w 的分段计时锁定是哪一步慢/断。

工具箱:每个工具看哪一层

工具看什么用于
curl -v -w分段计时、请求/响应头定位慢在哪段(第03章)
tcpdump/tshark字节流、TLS 握手、SNI连不连得通、握手对不对(第01章/第02章)
mitmproxy应用层明文请求内容对不对(第18章)
ss/netstat连接状态/数量CLOSE_WAIT、TIME_WAIT、连接泄漏
dig/nslookupDNS 解析DNS 错/泄漏(第03章)
openssl s_client证书链、ALPN、SNITLS 握手失败、MITM(第05章)
代理日志错误码、上游状态代理视角的真相

排错决策树(从症状出发)

症状?
├─ 502 Bad Gateway ──────────▶ 代理→源站这一跳"坏了"
│   ├─ 代理上 curl 源站不通? → 源站宕/端口错/网络(②段,第03章)
│   ├─ DNS 解析失败?        → 代理侧 DNS/内网域名(第03/08章)
│   └─ 源站返回非法响应?     → 协议不匹配(如 h2 后端配成 h1,第07章)
│
├─ 504 Gateway Timeout ──────▶ 代理→源站"超时"
│   └─ 源站慢/负载高,或 read timeout 太短(第31章)
│
├─ 503 Service Unavailable ──▶ 无健康后端 或 限流
│   ├─ Envoy "UH"?          → 无健康 upstream(第15章)
│   └─ 触发了限流/熔断?      → stick table/ratelimit(第14/31章)
│
├─ 407 / 401 ────────────────▶ 认证
│   ├─ 407? → 代理认证缺 Proxy-Authorization(第04章)
│   └─ 401? → 源站认证(与代理无关)
│
├─ Connection refused ───────▶ 代理没起/端口错/防火墙(①段)
│
├─ TLS 握手失败 ─────────────▶ 证书/SNI/版本/MITM
│   ├─ "unable to get local issuer"? → 被 MITM 或缺 CA(第05章)
│   ├─ SNI 不匹配/拿不到?     → 证书选错/ECH(第02/05章)
│   └─ 版本/算法不兼容?       → TLS 版本协商
│
├─ CONNECT 403/405 ──────────▶ 端口白名单(Safe_ports,第04/17章)
│
├─ CPU 100% / 无限循环 ───────▶ 透明代理没放过自己(环路,第11章)
│
├─ CLOSE_WAIT 大量堆积 ───────▶ 半关闭处理不当/连接泄漏(第21章)
│
├─ 慢 / 尾延迟高 ─────────────▶ 连接池小/缓冲/后端/协调遗漏(第31章)
│
├─ DNS 泄漏(被看到访问谁)────▶ 本地 vs 远端解析(第03章 socks5 vs socks5h)
│
└─ 间歇性"串味"/响应错配 ─────▶ 请求走私(hop-by-hop 头,第04/33章)

️ 实现 / 命令

实验一:502 分段二分实战

# 第1步:在代理机上,绕过代理直接连源站——区分是哪一段坏的
curl -v http://源站IP:端口/ --resolve 源站域名:端口:源站IP
#   通 → 问题在"客户端→代理"段或代理配置;不通 → "代理→源站"段(源站/网络)

# 第2步:看代理日志的上游错误
tail -f /var/log/nginx/error.log     # connect() failed / no live upstreams / SSL handshake...

# 第3步:DNS?在代理机上解析源站域名
dig +short 源站域名                   # 解析不出 → 代理侧 DNS 问题(第03章)

实验二:用分段计时定位"慢"

curl -w "DNS:%{time_namelookup} 连接:%{time_connect} TLS:%{time_appconnect} 首字节:%{time_starttransfer} 总:%{time_total}\n" \
     -s -o /dev/null -x http://proxy:3128 https://源站/
# 哪段数值大,瓶颈就在哪(第03章):
#   TLS 大 → 握手/会话复用(第31章);首字节-TLS 大 → 源站处理慢(504 前兆)

实验三:连接状态体检

ss -tanp | awk '{print $1}' | sort | uniq -c     # 各状态连接数
# 大量 CLOSE_WAIT → 应用没关连接(第21章半关闭)
# 大量 TIME_WAIT  → 短连接太多(第31章,连接池/tw_reuse)

实验四:TLS 握手失败定位

openssl s_client -connect 源站:443 -servername 源站域名 </dev/null 2>&1 | head -20
# Verify return code 非 0 → 证书链问题
# issuer 是 mitmproxy/企业 CA → 被 MITM(第05章)
# no peer certificate / alert → SNI 不匹配或版本不兼容

排错速查(症状→首查项)

症状第一步查相关章
502代理上直连源站 + 代理 error 日志03/04
504源站响应时间、read timeout31
503upstream 健康、限流配置15/14
握手失败openssl s_client 看证书/SNI05
环路/CPU 满透明代理 uid 排除规则11
CLOSE_WAIT 堆积半关闭/连接关闭逻辑21
慢/尾延迟curl -w 分段 + wrk231
DNS 泄漏socks5 vs socks5h03
内部调用全超时NO_PROXY 是否含集群内08/25

系统化的网络排错决策树参见 网络手册 · 故障排查方法论。


本章小结

  • 排错第一性原理:先分段二分(代理上直连源站,判断故障在客户端→代理还是代理→源站),再沿生命周期定位阶段。
  • 工具按层分工:curl -w 看分段时间、tcpdump 看握手字节、openssl s_client 看证书、ss 看连接状态、mitmproxy 看明文。
  • 记住核心因果:502=代理→源站坏、504=超时、503=无后端/限流、环路=没放过自己、CLOSE_WAIT=半关闭。

最后一章 第33章 代理安全,看代理作为攻击面的全部风险:开放代理、SSRF、请求走私、凭证泄漏,及加固清单——全书收尾。