写在前面
干运维的,谁没被半夜的告警电话吵醒过?
"老板,网站打不开了!"
"连不上数据库了!"
"服务器ping不通了!"
网络故障是运维最常遇到的问题之一。问题本身不可怕,可怕的是没有排查思路,一通乱试。
今天就聊聊我平时排查网络故障的6步法,从最基础的ping到最后的tcpdump抓包,每一步解决什么问题、怎么用,全给你讲明白。
第一步:先看通不通,ping 和 telnet
ping 是最基础的网络连通性测试工具,发ICMP包看目标能不能响应。
ping -c 5 8.8.8.8
ping -c 5 baidu.com
-c 5 表示发5个包就停,不停在那里一直ping。如果通了但延迟很高(几百毫秒甚至上千),那是网络链路有问题。
但ping有一个坑:ICMP协议可能被防火墙拦截。有时候ping不通不代表业务端口不通,反之亦然。
telnet 用来测特定端口是否畅通:
telnet 192.168.1.100 3306
如果连上了会显示连接成功,连不上就卡住或者报"Connection refused"。
个人实操经验: 我排查问题的习惯是先ping看三层通不通,再telnet看四层端口开没开。这两步做完,一大半问题就能定位到方向了。
第二步:路由对不对,traceroute
ping通了但很慢,或者ping某些IP通但业务不通,可能是路由问题。
traceroute 可以看你到目标经过了哪些跳点,哪一跳慢了或者丢了:
traceroute -n 8.8.8.8
-n 表示不解析域名,省时间。输出每一行就是一个路由跳点,看到 * * * 表示那一跳没有回应(可能是路由器配置了不响应ICMP)。
个人实操经验: 有次客户说访问我们的服务很慢,我跑了traceroute,发现有个内网网关延迟飙到800ms,找网络同事一查,那台交换机CPU满载了。没有traceroute,你根本不知道问题出在哪一跳。
如果机器上没有traceroute,可以装一下:
apt install inetutils-traceroute
yum install traceroute
第三步:端口有没有在监听,ss
业务连不上,ping和路由都没问题,那就要看看服务本身有没有在监听了。
ss 是 netstat 的现代替代品,更快、信息更全:
ss -tlnp
ss -ulnp
ss -tanp
参数说明:
- -t: TCP
- -u: UDP
- -l: 只显示监听中的
- -n: 不解析服务名(显示端口号而不是mysql这种名字)
- -p: 显示进程信息
输出示例:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:3306 0.0.0.0:* users:(("mysqld",pid=1234,fd=16))
看到 0.0.0.0:3306 表示MySQL在所有IP上监听。如果看到 127.0.0.1:3306,那只能本机访问,外部连不上就是这个原因。
个人实操经验: 有次部署了一个Web服务,怎么都访问不了。telnet 80不通,ping没问题,ss一看,服务根本没在监听。启动脚本里没写 ExecStart,systemd启动后进程直接退出了。这种问题不查 ss/st 根本发现不了。
第四步:防火墙拦没拦,iptables / nftables / firewalld
服务在正常监听,但就是连不上?防火墙大概率在捣乱。
先看iptables策略:
iptables -L -n -v
iptables -t nat -L -n -v
如果云服务器或者发行版用的 nftables:
nft list ruleset
CentOS 7/8 的 firewalld:
firewall-cmd --get-active-zones
firewall-cmd --zone=public --list-ports
firewall-cmd --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --add-port=8080/tcp --permanent
⚠️ 安全提醒: 千万别图省事直接 systemctl stop firewalld 或者 iptables -F 清空所有规则。防火墙是你的第一道防线,正确的做法是只开放需要的端口,而不是关掉防火墙。生产环境因为关了防火墙被扫到漏洞的事故太多了。
第五步:DNS解没解析对,dig 和 nslookup
域名能解析到正确的IP吗?这一步很多人忽视,但DNS出问题的情况其实很常见。
dig 是最强大的DNS查询工具:
dig baidu.com
dig @8.8.8.8 baidu.com
dig +short baidu.com
dig +stats baidu.com
nslookup 更简单:
nslookup baidu.com
排查DNS缓存:
resolvectl statistics
cat /etc/resolv.conf
个人实操经验: 有次排查一个"网站时而能打开时而打不开"的问题,ping IP是通的,ping域名时通时不通。dig一看,每次请求返回的IP不一样,其中一个IP是旧的失效IP。原因是DNS记录之前变更过,TTL到期后还有部分DNS服务器缓存了旧记录。搞了半小时才定位到。
第六步:终极武器,tcpdump 抓包分析
前面5步都查不出问题?到这一步,就得看最原始的数据包了。
tcpdump 是Linux上最强大的网络抓包工具,没有之一。
tcpdump -i eth0
tcpdump -i eth0 port 3306
tcpdump -i eth0 host 192.168.1.100
tcpdump -i eth0 port 80 -A
tcpdump -i eth0 port 3306 -w db_traffic.pcap
几个常用场景:
场景1:看TCP三次握手有没有完成
tcpdump -i eth0 host 192.168.1.100 and port 80
场景2:看有没有丢包重传
tcpdump -i eth0 -t -n -q
场景3:看连接谁发起的
tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn) != 0'
个人实操经验: 有次线上MySQL突然变慢,业务日志报"Too many connections"。ss看到几千个TIME_WAIT,但理论不应该有这么多。tcpdump抓包一看,发现应用层有个bug:连接用完不放,还在疯狂创建新连接。最终定位到代码里少写了 db.Close()。如果没抓包,可能还在怀疑数据库性能问题。
安装提示: 很多最小化安装的机器没有tcpdump,需要装一下:
- Ubuntu: apt install tcpdump
- CentOS: yum install tcpdump
抓包需要root权限,记得加sudo。
真实案例串讲
说了半天,来看个完整案例。
现象: 线上Java服务连接RDS MySQL偶尔超时,重启后又好了,但过几小时又出现。
排查过程:
1. ping RDS地址 -- 正常,延迟不到1ms
2. telnet RDS 3306 -- 超时时连不上
3. ss -tlnp | grep 3306 -- 本地没有3306(正常,RDS是远程的)
4. 防火墙规则检查 -- iptables没有限制出站
5. dig @rds内网dns -- 解析正常,IP是对的
6. tcpdump抓包:
tcpdump -i eth0 host RDS_IP and port 3306 -w mysql.pcap
7. 用Wireshark打开pcap文件分析,发现TCP连接数飙到3000+后,新的SYN包发出去了但没有收到SYN-ACK。
根因: RDS实例的连接数上限是3000,业务连接池没有合理配置,加上有个定时任务没有正确关闭连接,导致连接泄露。连接数到上限后RDS拒绝新连接。
解决: 调整连接池最大连接数、修复连接泄露的bug、RDS升配增加最大连接数。
写在最后
网络排查其实没那么玄乎,核心就是分层排查:
1. 物理/网络层:ping、traceroute
2. 传输层:telnet、ss
3. 应用层:dig、curl
4. 实在不行:tcpdump抓包
记住一个原则:从简单到复杂,从外层到内层。不要一上来就抓包,也不要在ping不通的时候去查应用配置。
把这6个命令玩熟了,大部分网络故障半小时内能定位到根因。
⚠️ 安全提醒: 抓包文件(.pcap)会包含数据库密码、API密钥等敏感信息,排查完后记得及时删除。不要在公网传输pcap文件,或传输前先确认不包含敏感数据。另外生产环境抓包尽量在低峰期操作,高流量场景下tcpdump本身也会消耗CPU资源。
你还有什么网络排查的独门技巧?欢迎留言交流!