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 和端口。

注意: 云安全组规则是有状态的。如果你放行了入方向的 TCP 80 端口,出方向的回包会自动放行,不需要额外配置。但如果你配置了无状态的安全组,那就得同时配置入方向和出方向规则,很容易漏配。

我遇到过最坑的一次,是客户说端口明明放行了,但就是连不上。我让他把安全组规则截图发我,一看,入方向放行了 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 Queue 全连接队列 Accept Queue 应用进程 排查步骤: 1. 检查端口监听状态:netstat -tlnp | grep :8080 2. 检查防火墙/安全组规则:iptables -L -n -v | grep :8080 3. 检查队列溢出:netstat -s | grep -i "listen"

这张图把整个排查链路串起来了。从客户端发 SYN,经过防火墙,进入半连接队列,完成握手后进入全连接队列,最后被应用进程取走。任何一个环节出问题,都会导致连接超时。

嗯,服务端侧排查就这些。记住这个顺序:端口 → 防火墙 → 队列。按这个来,基本不会漏掉什么。