4. 服务端侧排查:端口、防火墙与连接队列
客户端抓包看完了,如果发现 SYN 包发出去石沉大海,或者反复重传,那问题大概率出在服务端。这时候,咱们就得把目光转向服务端了。
我个人习惯,排查服务端问题,会按一个固定的顺序来:先看端口在不在,再看防火墙拦没拦,最后看服务本身是不是扛不住了。这个顺序走下来,大部分连接超时问题都能定位到根因。
1. 端口监听状态 → 2. 防火墙/安全组规则 → 3. 服务负载与队列溢出
4.1 服务端口监听状态检查
这是第一步,也是最简单的一步。服务没起来,端口没监听,客户端连个鬼啊。
常用命令:
# Linux 系统
netstat -tlnp | grep :8080
ss -tlnp | grep :8080
# Windows 系统
netstat -ano | findstr :8080
这里我解释一下参数含义:
| 参数 | 含义 |
|---|---|
| -t | 只显示 TCP 连接 |
| -l | 只显示 LISTEN 状态的端口 |
| -n | 以数字形式显示地址和端口,不反解域名 |
| -p | 显示对应的进程 PID 和名称 |
输出结果应该是这样的:
tcp LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=12345))
看到 LISTEN 状态,说明端口在正常监听。如果什么都没输出,或者只看到 0.0.0.0:8080 但进程名不对,那问题就清楚了——服务没启动,或者启动失败了。
ss 而不是 netstat。ss 性能更好,输出也更清晰。特别是在高并发服务器上,netstat 可能会卡住,ss 基本秒出。
避坑指南: 我曾经遇到过一个案例,netstat 显示端口在监听,但客户端就是连不上。后来发现,服务监听的是 127.0.0.1:8080,而不是 0.0.0.0:8080。这意味着服务只接受本机回环地址的连接,外部客户端自然连不上。所以,检查的时候一定要看清楚监听地址是 0.0.0.0 还是 127.0.0.1,或者是某个具体的内网 IP。
4.2 服务端防火墙/安全组规则
端口在监听,但客户端还是超时?下一步,查防火墙。
云环境里叫安全组,物理机或虚拟机里叫 iptables/firewalld。说白了,都是包过滤规则。
检查 iptables 规则:
iptables -L -n -v | grep :8080
如果看到类似这样的规则:
DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
那恭喜你,找到问题了。这条规则把所有发往 8080 端口的 TCP 包都丢了。
检查 firewalld:
firewall-cmd --list-all | grep 8080
检查云安全组: 这个得去云厂商的控制台看。重点检查入方向规则,有没有放行客户端的源 IP 和端口。
我遇到过最坑的一次,是客户说端口明明放行了,但就是连不上。我让他把安全组规则截图发我,一看,入方向放行了 0.0.0.0/0 的 8080 端口,但出方向只放行了 80 和 443,没放行回包的端口。这就是无状态安全组的典型问题。
4.3 服务端负载与连接队列溢出
端口在监听,防火墙也放行了,但客户端还是超时?那问题可能出在服务端扛不住了。
这里有两个关键指标:半连接队列(SYN Queue) 和 全连接队列(Accept Queue)。
简单说下这两个队列是干嘛的:
- 半连接队列: 存放收到 SYN 包,但还没完成三次握手的连接。对应 TCP 状态中的
SYN_RECV。 - 全连接队列: 存放已经完成三次握手,但还没被应用程序
accept()的连接。对应 TCP 状态中的ESTABLISHED。
这两个队列满了,新的连接就会被直接丢弃,客户端就会看到连接超时。
怎么查队列溢出?
用 netstat -s 看统计信息:
netstat -s | grep -i "listen"
# 输出示例
12345 times the listen queue of a socket overflowed
6789 SYNs to LISTEN sockets dropped
如果 overflowed 和 dropped 的数字在持续增长,说明队列溢出了。
更精确的排查:
用 ss -lnt 查看当前队列深度:
ss -lnt | grep :8080
# 输出示例
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:*
第二个数字 128 就是全连接队列的最大长度。如果这个数字经常被占满,就需要调大它。
调优方法:
| 参数 | 作用 | 修改方式 |
|---|---|---|
net.core.somaxconn |
全连接队列最大长度(系统级) | sysctl -w net.core.somaxconn=1024 |
net.ipv4.tcp_max_syn_backlog |
半连接队列最大长度 | sysctl -w net.ipv4.tcp_max_syn_backlog=1024 |
| 应用程序 backlog 参数 | 全连接队列最大长度(应用级) | 修改代码中的 listen(fd, backlog) 参数 |
min(somaxconn, backlog)。也就是说,你应用里设置了 backlog=1024,但系统 somaxconn 只有 128,那实际队列大小还是 128。两个参数都得调。
我曾经处理过一个电商大促的案例,服务器配置很高,但一到流量高峰就大量连接超时。抓包发现服务端在收到 SYN 后直接回了 RST。查了 netstat -s,发现 listen queue overflowed 的数字飙升。最后把 somaxconn 从 128 调到 1024,应用 backlog 也调到 1024,问题解决。
说白了,队列溢出就是服务端处理不过来。要么调大队列,要么优化应用性能,要么加机器。没有银弹。
这张图把整个排查链路串起来了。从客户端发 SYN,经过防火墙,进入半连接队列,完成握手后进入全连接队列,最后被应用进程取走。任何一个环节出问题,都会导致连接超时。
嗯,服务端侧排查就这些。记住这个顺序:端口 → 防火墙 → 队列。按这个来,基本不会漏掉什么。