排查一个常见 502 现象

现象

nginx 的日志中有两个关键错误

  1. no live upstreams while connecting to upstream
  2. upstream prematurely closed connection while reading response header from upstream

排查过程

  1. 压测 nginx > A ESB / nginx > B ESB,单点链路均无异常
  2. 压测 nginx > A+B ESB 稳定复现问题,结合 nginx 配置文档、中文博客分享,猜测为 keepalive 配置问题,导致 ‘upstream prematurely closed connection while reading response header from upstream’
  3. esb 服务实为 uwsgi ,同时观测后端服务的链接情况,发现 TIMEWAIT 数量多(20W+)
    1
    netstat -nat | grep :8002 | awk '{a[$6]++}END{for(i in a){print i,a[i]}}'
  4. 观察内核参数,keepalive 相关的参数均为默认值
  5. nginx http block 中 keepalive 为 60000,此时可以确认 TIMEWAIT 过多原因出现在此,keepalive * worker 就是最终连接数,设置 keepalive 为 65
  6. 重复压测 nginx > A+B ESB 链路仍稳定出现问题,“upstream prematurely …” 现象降低,但仍有较多 “no live …”,此处分析应为后端服务异常了
  7. 同时翻查 uwsgi 日志,观察到有热重启发生,伴随有模块加载异常的问题
  8. nginx upstream 配置 server ip1 max_fails=1 fail_timeout=30s,配合 7 的现象,确认为 upstream server 均不可用导致,临时将 max_fails 设置
    为 0,多次复测未复现,问题解决

分析

upstream prematurely closed connection while reading response header from upstream 分析

  1. nginx 发完请求后连接被”意外”关闭了, 导致读取响应失败,nginx 打印 upstream prematurely closed connection while reading response header from upstream 的日志,此处需要通过抓包确认,猜测某个 upstream 在数据传输等待响应 response 头部过程中主动 RST 了连接(后经排查可知,某个时刻 uwsgi 发生了热重启,可以匹配此行为)
  2. 分析后端 RST 连接的原因时发现 nginx 上有大量的 TIMEWAIT 连接,通过翻查源码和 nginx 文档后大概确认为配置问题。后端重启,server 收到 ACK 后应该 RST,但终止了连接,导致 TIMEWAIT

no live upstreams 分析

  1. nginx 中 upstream 默认是轮询的,upstream 中每个 server 组成链表去轮询,若 server1 连接失败后,服务将被移出链表,在 fail_timeout 超时后再次重新加入。
  2. 当两台 server 均被被移出后,因无 upstream 可用,nginx 打印 no live upstreams 日志,无响应返回 502
作者

Sony Dog

发布于

2023-01-13

更新于

2023-12-26

许可协议

CC BY-NC-SA 4.0