那天早上我像往常一样检查服务器日志,突然发现Nginx的error.log里出现了大量重复报错。最显眼的一条写着:"connect() failed (111: Connection refused) while connecting to upstream"。作为一个经历过多次线上故障的老运维,我立刻意识到这可不是普通的404错误,而是后端服务出现了严重问题。
这种错误通常发生在Nginx作为反向代理时,无法连接到配置的后端服务(upstream)。想象一下Nginx就像个尽职的前台接待,当它无法把客户请求转交给后台处理部门时,就会在日志里留下这样的"投诉记录"。具体到这条日志,我们可以看到几个关键信息:
这个错误看似简单,但背后可能隐藏着至少五种不同的故障原因。就像医生看诊需要结合多种检查报告一样,我们排查这个问题也需要系统性的方法。下面我就带大家完整走一遍我的排查过程,这套方法适用于绝大多数Nginx连接后端服务失败的场景。
先让我们把这条日志拆解得更加细致:
bash复制[error] 2334#2334: *253268 connect() failed (111: Connection refused) while connecting to upstream,
client: 172.12.23.44,
server: 212.65.12.29,
request: "OPTIONS /yun//sys/menu/nav?t=1583288052697 HTTP/1.1",
upstream: "http://127.0.0.1:8060/yun/sys/menu/nav?t=1583288052697",
host: "212.65.12.29:8002",
referrer: "http://39.107.238.105/yun-web/"
每个字段都有其特殊含义:
这里有个关键细节:upstream地址是127.0.0.1:8060,而server地址是212.65.12.29。这说明Nginx配置可能存在问题——当server是公网IP时,upstream通常不应该是本地回环地址。
面对这类问题,我通常会按照以下顺序排查:
网络连通性检查
服务健康状态
Nginx配置验证
系统资源检查
特殊场景考量
首先我用最基础的工具验证网络连通性:
bash复制# 检查端口是否开放
telnet 127.0.0.1 8060
# 使用更现代的替代方案
nc -zv 127.0.0.1 8060
# 检查本地端口监听情况
ss -tulnp | grep 8060
如果telnet/nc连接失败,说明要么服务没启动,要么防火墙阻止了连接。这时需要检查:
bash复制# 检查防火墙规则
sudo iptables -L -n
# 如果是firewalld
sudo firewall-cmd --list-all
# 检查SELinux状态
getenforce
在我的案例中,发现8060端口根本没有服务监听。这说明要么服务没启动,要么监听在错误端口。
接下来检查后端服务状态:
bash复制# 检查服务进程是否存在
ps aux | grep 服务名
# 查看服务日志
journalctl -u 服务名 --since "1 hour ago"
# 尝试手动启动服务
sudo systemctl start 服务名
如果服务运行正常但依然无法连接,可能需要检查服务绑定地址:
bash复制# 查看服务监听的IP地址
ss -tulnp | grep 服务名
有些服务默认只监听127.0.0.1,如果Nginx和服务不在同一主机,就会导致连接被拒。这时需要修改服务配置绑定到0.0.0.0。
现在来到最关键的Nginx配置检查。主要关注两个部分:
upstream配置(如果有):
nginx复制upstream backend {
server 192.168.1.10:8060;
server 192.168.1.11:8060;
}
server配置中的proxy_pass:
nginx复制location /yun/ {
proxy_pass http://backend;
proxy_set_header Host $host;
}
常见错误包括:
在我的案例中,问题正是配置写死了127.0.0.1,而实际后端已经迁移到独立服务器。
如果以上都正常,最后需要检查:
文件描述符限制:
bash复制# 查看当前限制
ulimit -n
# 查看Nginx进程实际使用的数量
cat /proc/$(pgrep nginx | head -1)/limits
连接数限制:
nginx复制# nginx.conf中的相关配置
worker_connections 1024;
内核参数:
bash复制sysctl -a | grep net.ipv4.ip_local_port_range
这是最常见的情况,解决方案很简单:
bash复制# 启动服务并设置开机自启
sudo systemctl start 服务名
sudo systemctl enable 服务名
# 验证服务状态
sudo systemctl status 服务名
修正Nginx配置的几种常见情况:
错误的上游地址:
nginx复制# 错误配置
location / {
proxy_pass http://127.0.0.1:8080;
}
# 正确配置(使用upstream)
upstream backend {
server 192.168.1.100:8080;
}
location / {
proxy_pass http://backend;
}
缺少结尾斜杠:
nginx复制# 错误配置(会追加URI)
location /api/ {
proxy_pass http://backend;
}
# 正确配置
location /api/ {
proxy_pass http://backend/;
}
开放防火墙端口的通用方法:
bash复制# iptables方案
sudo iptables -A INPUT -p tcp --dport 8060 -j ACCEPT
sudo service iptables save
# firewalld方案
sudo firewall-cmd --zone=public --add-port=8060/tcp --permanent
sudo firewall-cmd --reload
修改服务绑定地址的通用方法(以常见应用为例):
Spring Boot:
properties复制server.address=0.0.0.0
Node.js:
javascript复制app.listen(8060, '0.0.0.0')
Python Flask:
python复制app.run(host='0.0.0.0', port=8060)
当常规方法无法定位问题时,可以尝试抓包:
bash复制# 在Nginx服务器上抓取到后端的通信
sudo tcpdump -i any host 后端IP and port 8060 -w nginx_upstream.pcap
# 分析抓包文件(建议下载到本地用Wireshark分析)
tcpdump -r nginx_upstream.pcap -n
通过抓包可以清晰看到:
在Linux系统中,ECONNREFUSED(错误码111)表示:
可以通过以下命令获取更详细的错误信息:
bash复制# 查看系统错误代码定义
grep 111 /usr/include/asm-generic/errno*.h
# 使用strace跟踪Nginx系统调用
sudo strace -p $(pgrep nginx | head -1) -f -e trace=network
启用Nginx调试日志可以获得更详细的信息:
nginx复制error_log /var/log/nginx/error.log debug;
重启Nginx后,日志会记录:
注意:调试日志会产生大量数据,生产环境应谨慎使用。
nginx复制upstream backend {
server 192.168.1.100:8060 max_fails=3 fail_timeout=30s;
server 192.168.1.101:8060 backup;
keepalive 32;
keepalive_timeout 60s;
}
关键参数说明:
nginx复制location / {
proxy_pass http://backend;
# 重要头部传递
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 超时设置
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
# 错误处理
proxy_next_upstream error timeout invalid_header;
proxy_next_upstream_tries 3;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
}
对于关键业务,建议配置主动健康检查:
nginx复制upstream backend {
zone backend 64k;
server 192.168.1.100:8060;
server 192.168.1.101:8060;
}
server {
location / {
proxy_pass http://backend;
health_check uri=/health_check interval=5 fails=3 passes=2;
}
}
建议监控以下Nginx指标:
$upstream_response_time$upstream_status$upstream_cache_statusngx_http_stub_status_module配置日志分析工具自动捕获upstream错误:
bash复制# 使用awk实时监控错误日志
tail -f /var/log/nginx/error.log | awk '/connect\(\) failed/ {
print "[" strftime("%Y-%m-%d %H:%M:%S") "] Upstream error:", $0
}'
使用工具模拟流量,验证配置可靠性:
bash复制# 使用wrk进行压力测试
wrk -t4 -c100 -d30s http://localhost:8002/yun-web/
# 查看测试期间的错误率
grep 'connect() failed' /var/log/nginx/error.log | wc -l
去年我们遇到过一个典型案例:某次上线后,Nginx突然开始大量报upstream连接被拒。按照排查流程:
这个案例告诉我们:即使是最基础的连接问题,也可能有出人意料的根本原因。因此我现在的排查清单上又多了一项——系统时间同步状态。