nginx “no live upstreams while connecting to upstream” 故障排查
在维护基于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” 的故障。
相关文章
- Serverless时代,Java如何放下身段拥抱轻量化,实现毫秒级唤醒?
- Java学习123——方法的重载(Overloading)和重写(Overriding)
- SpringBoot + Apache tika 轻松实现各种文档内容解析
- 紧急修复XML漏洞,WordPress 3.9.2 下载
- 安全研究员曝光FireEye核心产品0day漏洞
- Linux并发IO详解(上)
- Nginx核心参数 try_files使用及原理
- Nginx性能调优与优化指南
- 深入对比Nginx、LVS和HAProxy,选择最合适负载均衡方案!
- Nginx的http块sendfile,keepalive_timeout的配置指令说明,