nginx “no live upstreams while connecting to upstream” 故障排查

nginx “no live upstreams while connecting to upstream” 故障排查

经验文章nimo972025-05-28 7:32:067A+A-

在维护基于nginx + zuul1.0 + springboot的微服务架构项目时,一场棘手的故障悄然降临。生产系统日志中频繁爆出"no live upstreams while connecting to upstream"错误,服务与上游的连接出现严重故障,业务几近瘫痪。面对庞大的微服务集群,数十个 Java 服务如同一座座迷雾笼罩的孤岛,逐个排查犹如大海捞针,收效甚微。

初步排查:在错误方向上反复试错

基于对系统架构的熟悉,第一反应是微服务响应请求超时。检查Nginx 设置了 60 秒读取超时,Zuul 网关读取响应超时为 30 秒,怀疑zuul网关等待后端响应时间过短,中断了springboot的响应,nginx从而判定服务不可用。随即对 Zuul 网关的超时配置动手,将
zuul.host.connect-timeout-millis

zuul.host.socket-timeout-millis
都调整为 60000 毫秒,满心期待能解决问题,然而故障依旧,业务还是在崩溃边缘挣扎。

无奈之下,将目光转向后端服务限流。zuul网关配置
zuul.semaphore.max-semaphores

zuul.host.max-per-route-connections

zuul.host.max-total-connections
等关键参数,试图通过限制流量来缓解压力。但这次尝试依旧以失败告终,故障如同顽固的钉子,死死卡在那里。

既然 Zuul 层面无法突破,便将注意力转移到 Nginx 配置上。设置max_fails=3 fail_timeout=1s,希望系统能在中断后迅速恢复。可现实却给了沉重一击,请求崩溃情况不仅没有改善,反而愈演愈烈,业务可用性进一步降低。

随后对微服务进行排查,隔离疑似超时的服务,仅配置部分 Zuul 路由,可无论怎么尝试,问题都没有得到丝毫缓解,整个排查陷入僵局。

转机出现:意外发现与灵感迸发

终于等到服务空闲时间,决定进行压力测试。先给存疑的微服务配置空接口,即接受请求后直接返回,不涉及任何业务逻辑。使用 Jmeter 进行压测,结果令人诧异:每秒吞吐量仅 2000,可 Springboot 服务却毫无压力。这一结果直指网关或 Nginx 存在问题。

为应对第二天的业务高峰,当机立断进行横向扩容,新增 Nginx 与 Zuul 网关。再次压测时,惊喜发现吞吐量提升至 7000(同样是空接口)。这意外之喜让人摸不着头脑,难道是新服务器性能卓越?复盘时注意到,扩容时为方便压测,Nginx 仅配置了一个 Zuul 网关,处于无负载均衡状态。抱着试试看的心态,将其他 Nginx 与 Zuul 进行一对一配对,验证后发现问题竟然得到解决。虽然业务恢复正常,但问题根源依旧成谜,只能先修改生产配置,确保业务稳定运行。

真相大白:Time_Wait 端口引发的连锁反应

就在百思不得其解时,突然灵光一闪,决定查看服务器端口状态。这一查,发现大量端口处于time_wait状态。凭借经验判断,这很可能就是问题的罪魁祸首 —— 端口被占用!为验证猜想,开始搜索解决方案,最终决定调整 Nginx 长连接参数。在upstream配置中,设置keepalive 1000控制与上游服务器的空闲连接数;keepalive_requests 10240限定长链接处理请求上限;keepalive_timeout 15s确定空闲连接断开时间。同时在server配置中,指定proxy_http_version 1.1并设置proxy_set_header Connection '',确保符合条件时保持长连接。

重新压测后,奇迹出现了!Jmeter 每秒吞吐量飙升至 20000,服务器也开始有了明显压力。问题终于解决,也借此机会深入学习了 Linux 系统中 HTTP 连接端口机制的相关知识。原来在 Linux 系统中,Nginx 每向后端服务发起一个请求,都会占用发起端的临时端口和服务端的端口。请求结束后,端口不会立即释放,而是进入time_wait状态,这主要是出于以下三个目的:

确保最后一个 ACK 能到达对端:保证 TCP 连接关闭过程的完整性,防止因 ACK 丢失导致对端一直处于半关闭状态。

让网络中旧的重复数据包过期:避免旧数据包干扰新连接,保证数据传输的准确性。

保证 TCP 全双工连接的可靠终止:确保双向数据传输都能正常结束,避免数据丢失或传输错误。

time_wait状态默认持续时间通常为 2 倍的 MSL(Maximum Segment Lifetime,最长报文段寿命),在 Linux 系统中默认是 60 秒。在高并发场景下,大量端口处于time_wait状态且未能及时释放,导致应用(如 Zuul)无法申请到临时端口,进而使得 Nginx 无法建立正常连接,最终引发了 “no live upstreams while connecting to upstream” 的故障。

点击这里复制本文地址 以上内容由nimo97整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

尼墨宝库 © All Rights Reserved.  蜀ICP备2024111239号-7