news 2026/10/3 9:06:11

网络故障排查实战:从DNS解析到TCP连接的完整定位链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网络故障排查实战:从DNS解析到TCP连接的完整定位链路

先说一个几乎所有做过线上故障处理的人都会遇到的场面:业务监控大屏飘红,研发群里有人喊“调不通了”,紧接着就有人接一句“是不是DNS挂了”,另一个人说“不对,感觉是TCP连不上”。然后,争论的人各自打开工具乱按一通,最后靠重启大法解决问题——至于到底哪里出的问题,没人说得清。

我这些年被类似的“悬案”折磨过不少次,后来慢慢总结出一套固定套路:网络故障排查,永远应该沿着“DNS解析 → 网络连通 → TCP连接 → 连接质量”这条链路一步步往下走,每一层验证通过再进入下一层。这不是什么高深理论,而是一条能大幅缩短排障时间、减少同事之间互相甩锅的实战路径。这篇文章我就把自己常用的这条排查链路完整梳理一遍,把命令、原理、典型坑位都摆出来,希望能帮你把乱七八糟的“网络不通”变成一张清晰的定位清单。适合正在自己排查服务的开发、运维、网工,也适合刚入门想建立体系化排查思路的人。

1. 为什么排障要按“DNS → TCP”的顺序来:先画一张协议栈地图

1.1 绝大多数“网络不通”的真相:故障是分层的

先把一个关键认知说清楚:你遇到的每一个“网络不通”,从来都不是一个孤立的错误,而是某一层协议栈没有按预期工作。用户访问一个网站,背后经过的链路大致是这样:浏览器先做DNS解析拿到IP,然后发起TCP连接,连接建立后才是HTTP请求的发送和响应。哪怕只是“页面打不开”这五个字,可能的原因就能列出一长串:域名解析失败、解析到了错误IP、IP不可达、路由黑洞、防火墙拦截SYN包、连接超时、建立连接后经常断、数据包丢失严重导致请求永远发不完……

如果不分层,排障就像在暗室里找一只不存在的猫。你ping了一下域名发现不通,立刻怀疑服务器宕机,结果其实是你本地DNS缓存了解析,压根没连到正确的服务器。反过来,你用IP访问发现服务明明是好的,但又说不清为什么域名访问偶尔超时。这些情况的本质,都是没有把“哪一层出的问题”先框定住。

所以我的习惯是:不管用户报什么网络故障,第一件事永远是把链路拆成三层来看——域名解析层、IP连通层、TCP传输层。每一层都有对应的验证工具和典型症状,先定位到某一层,再往细节里钻。

1.2 为什么必须先从 DNS 开始,而不是先抓 TCP 包

有人会问:既然TCP才是最基础的连接,为什么不先去抓包看握手?这里有个很实际的逻辑:TCP连接的前提是拿到目标IP和端口,而绝大多数业务场景里,你要连接的服务器是用域名表示的。如果DNS解析这一关就错了——解析超时、解析到旧IP、缓存了错误结果——你后续再怎么抓TCP包都是浪费时间,因为你可能在跟一个根本不对的地址较劲。

另外从排查成本上看,DNS解析的检查也最便宜。一条nslookup或dig命令几秒钟就能出结果,而抓包分析TCP握手少说要花几分钟,还要带着过滤器去判断SYN、SYN-ACK这些标志位。先做成本最低的验证,再进入成本更高的环节,这是排障效率的基本原则。

排障顺序也对应着依赖关系:TCP建立在IP之上,IP建立在DNS解析出的目标地址之上。自顶向下逐层验证,每过一层就排除一批可能性,剩下的范围自然越来越小。等到你确认DNS没问题、IP能通,再开始查TCP握手状态,这时候抓包看到的东西才有意义。

1.3 开工前先备好这几把“扳手”

在开始讲具体排查之前,我先把平时最常用的一套工具列出来。这套工具在Linux和Windows下基本都有对应版本,不用装什么重型软件,系统自带的能力已经够排查九成问题:

工具作用典型排查场景
nslookup/digDNS解析查询域名解析不到、解析结果异常
ping测ICMP连通性目标机器是否在线、IP是否可达
traceroute/tracert路由路径追踪中间路由丢包、链路绕路
telnet/nc测试端口连通性TCP端口是否对外开放
curl -vHTTP访问并输出详细过程整体访问链路哪里卡住
ss/netstat查看本地连接状态连接卡在SYN_SENT还是ESTABLISHED
tcpdump抓包分析定位握手失败、重传、丢包问题

这套工具不用一次性全上,而是按“DNS → IP → TCP”的顺序逐层启用。每验证完一层,记录一下结果,确认没问题再动下一层。不然工具开了一大堆,信息反而是噪音。

2. DNS 解析异常:最隐蔽也最容易误判的坑

2.1 一次域名解析要经过哪几关

域名解析看似是个一步操作,实际是一条完整的查询链。我在排障时习惯把它拆成四段:浏览器/系统缓存 → 本机hosts文件 → 系统配置的DNS服务器 → 根服务器与权威服务器。

第一段是缓存。你的浏览器、操作系统甚至路由器都会缓存DNS结果,缓存有效期由域名解析结果里的TTL值决定。很多“为什么我改完域名解析了还是不生效”的问题,根子就在缓存。Chrome输入chrome://net-internals/#dns可以查看并清空DNS缓存,Windows下用ipconfig /flushdns,Linux下根据systemd-resolved或nscd的不同缓存机制处理。

第二段是hosts文件。Windows在C:\Windows\System32\drivers\etc\hosts,Linux在/etc/hosts。某些内网环境会利用hosts做域名映射,如果里面写了一个过期的IP,即使DNS服务器上的解析是对的,实际访问还是会走hosts的旧地址。

第三段才是真正意义上的DNS查询。系统把解析请求发给配置的DNS服务器,这台服务器要么自己知道答案,要么代表你去问根域名服务器和权威服务器。第四段就是整个递归和迭代过程,通常不会出问题,一旦权威服务器响应慢,就会变成“解析时好时坏”的诡异现场。

2.2 症状识别:到底是“解析失败”还是“解析错误”

很多初学者把DNS问题的症状搞混。我举几个最常见的:

  • 浏览器直接报“无法找到 DNS 地址”或“找不到服务器IP地址”。这个最直接,多半是当前用的DNS服务器根本没给出答案。
  • 命令行里ping example.com报unknown host,说明系统层解析就失败了,和浏览器报的其实是同一件事。
  • curl访问域名报Could not resolve host,同样是解析环节出了问题。
  • 更隐蔽的是“解析成功但结果不对”。比如你用nslookup能看到A记录,返回IP却是别人家的旧地址,或者解析到内网IP但实际服务在另一个网段。这种情况不只是“有没有解析到”,还要看“解析到的对不对”。

遇到“解析失败”,优先查三个地方:本机hosts有没有写错、当前配置的DNS服务器是否可用、这台DNS服务器是不是被运营商污染或者部分域名解析不了。遇到“解析错误”,就需要对比多家DNS服务器的解析结果,看看是不是只有你用的那台有问题。

2.3 定位 DNS 问题三步法

我一般按下面三个步骤做,基本不会漏:

第一步,用系统默认DNS解析一次,看结果。nslookup example.com(Windows和Linux通用),dig example.com(Linux更推荐,输出带TTL和查询耗时)。先确认默认配置下能不能解析出来。

第二步,换一个知名公共DNS再解析一次。比如nslookup example.com 114.114.114.114或dig @223.5.5.5 example.com,看是不是换了服务器就能解析。如果默认服务器解析失败、公共DNS能成功,那问题就锁定在你当前配置的那台DNS服务器上,要么是它本身故障,要么是它到权威链路的路径有问题。

第三步,对同一域名查出来的多个结果做对比。分别查询几组不同的DNS服务器,把所有A记录列出来对比。如果公共DNS之间结果一致,但你公司内网DNS给出的结果不一样,多半是内网DNS有特殊配置或缓存过期。我遇到过不止一次,内网DNS把某域名缓存在一台已经退役的服务器上,导致业务偶发超时。

2.4 Linux 下改 DNS 的经典坑:配置总是“还原”

热搜词里有一条特别真实:“linux修改dns后重启网络+还原”。这个问题我在Ubuntu、CentOS上都踩过,根因在于不同发行版的DNS配置管理体系不一样。

很多老教程让你直接编辑/etc/resolv.conf,这在某些系统上确实立竿见影,但一到重启网络服务或者重启机器就全没了——因为你的配置被NetworkManager或systemd-resolved覆盖了。Ubuntu 22.04这类新版系统,/etc/resolv.conf通常是个软链接,指向systemd-resolved生成的文件,你改了等于白改。

正确的做法是先确认系统用哪套网络管理机制。如果是NetworkManager,用nmcli con mod改对应连接的ipv4.dns和ipv4.ignore-auto-dns;如果是netplan(Ubuntu 22.04默认用这个),就在/etc/netplan/*.yaml里修改nameservers配置,然后sudo netplan apply;如果只是临时测试,可以用resolvectl dns命令直接临时设置。

改完别忘验证:resolvectl status看当前生效的DNS,再用systemd-resolve --status(部分版本)或直接ping一个域名测试。这里还有个容易骗过自己的细节:systemd-resolved默认有缓存和DNS stub,就算你配置已经变了,也可能要等缓存失效或手动重启systemd-resolved服务才生效。

2.5 公共 DNS 怎么选:延迟、可用性、内网域名的平衡

很多人在选DNS服务器时只看“名气大”,其实这里面的取舍挺多的。国内常见的公共DNS大概有这些:

DNS服务器地址特点
114 DNS114.114.114.114老牌,用户基数大
阿里DNS223.5.5.5 / 223.6.6.6阿里云维护,解析速度稳定
百度DNS180.76.76.76国内节点覆盖不错
电信/联通运营商DNS各省不同延迟最低,但可能在部分域名上解析结果不理想
1.2.4.81.2.4.8国家下一代互联网示范工程,部分环境有奇效

我的选择原则是:办公室内网环境优先用内网DNS,因为它能解析内部域名,还能做内网流量的智能调度,公网DNS再好也替代不了这一点。如果内网DNS抽风,临时切换到公网DNS做验证是没问题的,但不要长期混用,否则内部服务名都解析不出来了。

测DNS延迟有个简单办法:dig @服务器地址 example.com,看返回里的Query time。多对比几台,延迟低且解析结果稳定的就是适合作默认配置的。另外,如果你是在云上建了自己的DNS服务器,把“转发器”指向一个稳定可靠的上游也很重要,不然自己搭建的DNS会在递归查询时频频超时。

3. DNS 通过之后:IP 层连通性才是“中间那段看不见的路”

3.1 ping 不通不代表服务一定不可用

确认域名解析没问题后,下一步就是验证目标IP是否可达。很多人习惯性先ping一下,但对ping不通的结果过度解读,反而会带偏方向。

ping使用的是ICMP协议,它测试的是“主机是否在线并且允许响应ICMP请求”。现实情况是:很多生产环境出于安全考虑会禁掉ICMP响应,比如云服务器、负载均衡器的安全组默认就不放行ping,但这完全不影响TCP和HTTP服务正常访问。所以,ping不通的时候,不要急着下“服务器挂了”的结论,先换用TCP层面的端口探测工具验证。

ping真正有价值的地方在于:第一,能快速判断当前IP在网络里有没有路由可达;第二,连续ping一段时间看延迟和丢包率,可以判断链路质量。比如你ping 1.1.1.1延迟只有几毫秒,但ping 某云服务器延迟超过两百毫秒还伴随大量丢包,那基本可以断定中间链路或路由策略有问题,TCP连接自然也不会顺畅。

3.2 traceroute 的用法:找到“黑洞”在哪一段

如果你怀疑中间链路有问题,traceroute(Windows上叫tracert)是下一步的核心工具。它会记录数据包从你本机经过的每一个路由节点,并且打印每一跳的延迟。

我遇到过一个典型场景:客户端访问某个API,有时候通有时候超时,ping目标IP能看到少量丢包。用traceroute一查,发现从本机出去的第三跳开始延迟飙升到300ms,再往后几跳干脆全部* * *超时。这基本说明问题出在中间的运营商链路上,而不是目标服务器本身。

需要注意一条经验:traceroute中间某几跳超时,千万不要直接判定故障。很多运营商路由器为了性能和安全,会限制ICMP的响应,导致显示超时,但数据包仍然正常转发。判断的标准是看最终那一跳能不能到,以及整体延迟是否异常。只有最终跳也超时、或者连续多跳都丢包,才说明路由真的断了。

3.3 用 telnet/nc 验证“端口是否真的开放”

从IP连通再往前一步,就是端口可达性。这一步是最接近TCP排查的入口,也是很多人容易跳过的一步。

telnet 目标IP 端口是个老而实用的工具。如果端口开放,你会看到Connected to或者直接进入一个黑屏光标;如果端口不通,会一直卡住直到超时,然后报Connection refused或者Unable to connect。nc -vz 目标IP 端口在Linux下更适合脚本化检测,还能一次测多个端口。

这里要特别区分两种报错的含义:Connection refused说明IP是通的,目标机器在线,但那个端口上没有服务在监听,或者有防火墙主动回了RST;Connection timed out说明SYN包根本没人应答,大概率是被防火墙安全组静默丢弃了,或者中间链路丢包导致握手包过不去。这两种现象对应的排查方向完全不一样,前者去看服务进程有没有起来,后者去看安全组、iptables规则和网络链路。

3.4 云上环境最容易漏的检查点:安全组

如果是上云的环境,IP层和端口层的“隐形防火墙”一定要优先排除。云服务器的安全组规则、负载均衡器的监听规则、以及VPC内部的网络ACL,任何一层Drop了流量,你在服务器里面抓到包往往什么都看不到,因为包根本没到达网卡。

我处理过几次“服务明明在监听,客户端就是连不上”的案例,最后都是安全组规则只放行了一部分来源IP,或者忘了放行对应端口。碰上这种情况,先别急着在服务器里抓包,去云控制台把安全组、网络ACL、负载均衡监听配置全过一遍,确认源IP、目的端口都放行了再继续看TCP层。

4. TCP 三次握手:连接建不起来时到底卡在哪一步

4.1 握手的本质:三次状态转换

TCP连接建立靠的是三次握手:客户端发送SYN包,服务端收到后回复SYN-ACK包,客户端再回一个ACK包,双方进入ESTABLISHED状态。虽然这是老生常谈,但排障时必须把这三步和本机的连接状态对应起来,才能真正定位问题。

客户端视角:发出SYN后,连接状态是SYN_SENT;收到服务端SYN-ACK,状态会变成ESTABLISHED。如果你在客户端用ss -tn看到大量连接停留在SYN_SENT,说明SYN包发出去了但一直没等到应答。原因可能是对方防火墙拦截、中间链路丢包、或者服务端的接收队列已经满了。

服务端视角:收到SYN后会进入SYN_RECV,表示已经收到连接请求但还没完成握手。如果服务端ss -tn里堆积了大量SYN_RECV,说明对方发来的SYN-ACK应答一直没收到,典型原因是半连接队列溢出,或者客户端回应的ACK丢了。

4.2 用 curl -v 和 ss 判断“卡在握手哪一段”

我最常用的组合拳是curl -v加ss -tn。curl -v会打印连接过程,比如Connected to example.com port 443说明TCP已经建好了,接下来卡住的话就是TLS或HTTP层的问题;如果一直报Connection timed out,说明还在等TCP握手,这时候切到ss -tn看连接状态就非常直观。

举个例子:你访问某个服务超时,ss -tn显示一堆SYN_SENT连接,那就先把目标IP和端口拿出来,在另一个网络环境(比如云服务器本机)试试能不能连。如果本机可以通、你这边不行,多半是本地到目标之间的防火墙或路由问题;如果本机也不行,就是服务端的问题,继续看服务端半连接队列和监听进程。

4.3 半连接队列溢出:一个让连接“时好时坏”的元凶

在TCP握手阶段,服务端维护着两个队列:半连接队列(存放SYN_RECV状态的连接)和全连接队列(存放已完成握手等待应用accept的连接)。这两个队列都有上限,一旦打满,新的连接请求就会被直接丢弃。

这就是为什么有些服务会出现“偶尔连得上、偶尔连不上”的现象:连接量一上来,队列满了,新连接全部卡死,但已有连接还在正常工作,从外部看就是一部不可靠的服务。

排查方法很简单:ss -tn state syn-recv看半连接队列堆积数,ss -lnt里看Send-Q和Recv-Q能反映全连接队列大小和当前积压。如果是Java应用报accept失败或者Nginx报504,配合这两个命令基本能确认队列问题。应急措施是调大net.core.somaxconn、net.ipv4.tcp_max_syn_backlog,以及应用监听接口的backlog参数;治本的办法是看业务流量是否暴涨、后端处理是否过慢,全连接队列堆积通常意味着应用accept速度跟不上连接建立速度。

4.4 防火墙和安全组的“静默丢包”:抓包才能看到真相

很多防火墙配置是“静默丢弃”,也就是直接扔掉你发来的SYN包,不回RST也不回任何东西。客户端这边的表现就是连接一直卡在SYN_SENT直到超时。

要确认这一点,最有效的办法是抓包。Linux下tcpdump -nn -i eth0 tcp port 目标端口可以看到SYN包到底有没有从本机网卡发出去。如果本机已经发出SYN,但一直看不到对端回任何包,那问题几乎肯定在中间某个环节被丢弃了,接下来就该顺着链路往上查防火墙和安全组。

抓包有个容易被忽略的细节:如果在云服务器上用tcpdump抓包,看到SYN进来了但服务端没有回SYN-ACK,这时候先看iptables规则。iptables -L -n -v能看到每条规则的匹配计数,如果某个DROP规则计数在增长,说明是本地防火墙干的。如果计数没增长,再考虑是不是服务进程没有监听这个端口。

4.5 TIME_WAIT 与“端口已在使用”:经典 Java 客户端重连报错

握手建立之后的资源释放阶段,同样有一堆坑,其中最经典的就是java tcp客户端重连时报地址已在使用。这背后是TIME_WAIT状态在作怪。

TCP连接关闭时,主动关闭方会进入TIME_WAIT,默认等待2个MSL(最大分段生存期)后才会释放端口。如果应用在短时间内频繁创建、关闭连接,而每次都用同一个本地端口,就会在重连时报Address already in use。这个问题的根源不在于程序逻辑,而在于TCP协议为了保证旧连接的迟到数据包不会干扰新连接,强制让端口在TIME_WAIT期间不可复用。

我见过好几个用Java或C#写TCP客户端的项目踩这个坑,尤其是配合心跳重连机制时特别容易触发。缓解方式有几个:一是让操作系统允许TIME_WAIT端口尽快复用,net.ipv4.tcp_tw_reuse配合tcp_timestamps启用;二是客户端在重连时不要固定本地端口,让系统随机分配;三是在设计层面控制连接频率,用长连接而不是每次都新建连接。我个人更推荐后两者,因为tcp_tw_reuse虽然能解决端口问题,但它改变的语义需要你对内核参数有充分理解,生产环境不要贸然开启。

5. 连接建立成功之后:握手只是开始,重传和粘包才是真正的暗坑

5.1 DUP ACK、重传与丢包:连接“能用但很慢”的真凶

TCP连接建立成功后,很多人就以为万事大吉了,其实TCP的可靠性机制在这一阶段才开始真正工作。握手只代表双方愿意建立连接,不代表后续数据能稳定送达。最常见的两个问题是重传和重复确认(DUP ACK)。

什么是DUP ACK?简单来说,接收方发现某个数据包丢了或者乱序,就会针对“最后一个按序收到的数据包”重复发送ACK,催促发送方赶紧补发。发送方连续收到几个DUP ACK,就会触发快速重传。如果丢包严重,发送方会走超时重传路线,这时候TCP吞吐量会断崖式下跌。

排查手段有三个层面:第一,ss -tin可以看每个TCP连接的重传次数和发送队列里有没有堆积;第二,ping目标看丢包率和延迟波动,作为链路的粗参考;第三,tcpdump抓包统计重传包和DUP ACK的数量,确定是特定链路段还是全局性问题。我在实际项目中见过不少“接口时快时慢”的案例,最终抓包发现全是重传,链路本身丢包率夸张,TCP层的可靠机制变成了一把双刃剑——它保证了数据无损,但也把延迟放大了几十倍。

5.2 粘包和半包:TCP 是“流”不是“消息”

TCP是字节流协议,它不保证你发送的每一条消息都完整、独立地到达对端。应用层发两次write,底层可能合并成一个包发出去;反过来,一次大消息可能被拆成多个TCP段。这就是粘包和半包问题的根源。

在排查这类问题时,我见过太多程序员怀疑网络设备,结果锅全在应用层。比如C#和Java的TCP客户端互相通信,或者用Modbus TCP协议做设备通讯时,如果双方没有设计明确的消息边界,收方很容易把两条消息读成一条。网上的热搜词里“c# modbus tcp客户端”和“esp01s发送tcp消息手机”都是这个问题的重灾区。

正确的处理方式是应用层约定消息格式,常见有四种:用\n换行分隔、用固定长度、用长度前缀、用特殊终结符。Modbus TCP本身就规定了MBAP头部里有长度字段,但很多单片机实现时不严格按协议组包,也会出现半包问题。我的经验是:先抓包确认底层收到的字节流是什么样,再检查解析逻辑是不是按“完整消息”来读取,而不是按“一次read就是一条消息”来写代码。

5.3 半开连接与 KeepAlive:对方“失踪”了,连接还挂着

TCP还有一种很折磨人的现象:连接看似还活着,实际上对端已经消失了(断电、断网、崩溃),这就是半开连接。TCP协议本身没有内置检测对端是否活跃的机制,除非你主动发包。

客户端和服务端都可能在半开连接上干等。客户端等不到响应,服务端这边看到的就是一堆“假连接”,占用着文件描述符和内存。解决思路有两个层面:应用层主动做心跳,定时发探活消息,超时几次就主动断开重建;内核层面开启TCP KeepAlive,调整net.ipv4.tcp_keepalive_time、tcp_keepalive_intvl、tcp_keepalive_probes三个参数,让内核周期性地发送探测包。

实际项目中,我倾向于应用层心跳为主、内核KeepAlive兜底。原因很简单:内核KeepAlive的探测间隔默认是2小时,对于大部分业务来说太慢了;而且它只能确认“对端IP栈是否活着”,不能确认“对端业务进程是否正常”。真正想做健康检测,还得靠自己设计的心跳协议。

5.4 Nagle 算法与延迟确认:小包业务的延迟杀手

如果你调用的服务是小包高频交互(比如物联网设备的心跳、游戏的实时状态上报),那延迟不稳定多半和Nagle算法与TCP延迟确认的“打架”有关。

Nagle算法会把多个小包合并发送,减少网络上小包数量,但代价是可能增加几十毫秒的延迟。TCP延迟确认机制则是收包后不立刻回ACK,而是等一小段时间,期待能和数据一起捎带回去。这两个机制叠加在一起时,会出现一种经典的“确认死锁”:发送方等着合并更多数据,接收方等着捎带ACK,两边都在等,延迟就肉眼可见地恶化了。

Java和C#里设置TCP_NODELAY(setTcpNoDelay(true))就是关闭Nagle算法,让每个小包立即发送。但这不等于无脑开启,如果你的业务本来就是大块数据传输,Nagle算法反而能提升链路利用率。这个参数是典型的“场景决定论”,不要照搬网上的配置。排查时可以先在抓包里看“两组小包之间的间隔是否异常”,比如明明应该10ms一个包,实际却等到了40ms,那就要怀疑这两个机制在做怪了。

5.5 MTU 与 MSS:为什么小包能通,大包就断

还有一个比较进阶但容易被忽略的坑:MTU(最大传输单元)导致的数据传输失败。症状很怪:TCP握手没问题,小包数据没问题,但只要一传大文件或者大响应体,连接就卡住甚至重置。

原因在于网络链路中某一跳的MTU比你的包小,而你又禁用了路径MTU发现,导致大包被中间设备直接丢弃。排查方法是ping -M do -s 1472 目标IP,测试不同大小的包能不能顺利到达。如果大包不通、小包通,基本就锁定了MTU问题。

解决思路包括调低本机网卡的MTU、调整TCP MSS值(ip link set dev eth0 mtu 1400这种做法),或者确保路径MTU发现正常工作。这个坑在跨运营商、跨国际链路时出现概率特别高,国内访问海外服务时尤其常见。之前处理过一个“从国内服务器访问海外API,小请求正常、大响应超时”的案例,就是典型的MTU问题,把接口响应体压缩到阈值以下立刻恢复正常。

6. 一次完整链路排障复盘:从页面打不开到 TCP 半连接队列溢出

光讲理论容易散,我用一个真实复盘把前面所有步骤串起来。这个案例非常有代表性:某天业务方反馈,官网页面“偶尔打不开”,刷新几次又好了,但过一阵又报超时。用户用的浏览器是Chrome,报的是“无法找到DNS地址”和“连接超时”两种错误交替出现。

当时第一反应当然是先调查DNS。我在用户侧机器上nslookup了一下公司域名,发现默认的内网DNS服务器响应极其不稳定,有时候要等两三秒才返回结果,偶尔直接超时。换个公共DNS一测,解析秒回,结果也正确。到这一步,按常规套路应该把用户机器的DNS改成公共DNS就能解决问题。但奇怪的是,改完后“找不到DNS地址”确实是没了,新问题浮出水面:连接还是间歇性超时。

这说明问题不止一层,DNS只是第一个暴露的故障,后续的TCP层还有问题。于是继续往下查:curl -v访问官网,发现卡在Trying ...之后,紧接着ss -tn看到连接停留在SYN_SENT状态。SYN发出去了,没人应答。这时候就到了“链路连通性”的检查环节。ping目标IP延迟正常、无丢包,telnet 目标IP 443同样超时。那么问题基本锁定在服务端或中间的防火墙。

登录到服务端一看,ss -lnt显示监听端口的Recv-Q积压很大,SYN_RECV状态的连接数量远超正常水位。再查应用进程日志,发现后端业务线程在高峰期处理太慢,全连接队列被占满,内核只能把新进来的SYN包丢弃。结合前面DNS的问题,实际上点有两个:内网DNS因为配置问题导致部分机器解析走了一条慢路径,后续又因为官网流量突增导致TCP半连接队列打满。

最后处理方案是两层同时做:先把内网DNS的转发配置和上游链路重新调整,再把后端服务的accept backlog调大,同时对峰值流量做扩容。这个案例很典型,它说明一个“页面打不开”的现象,背后可能是DNS和TCP两层问题叠加。如果你只处理了DNS,那TCP的坑迟早会让故障换个面目再出现;反之,只调TCP参数也搞不定DNS解析的间歇性失败。这就是为什么“从DNS到TCP一步步定位”这种方式,本质上是在帮你把问题切开,一个接一个解决,而不是靠运气撞上答案。

7. 排障命令速查与沉淀下来的几条经验

7.1 命令速查表:按场景直接找工具

把前面涉及到的常用命令整理成一张速查表,排查时对照着用就行。

排查目标命令关键观察点
域名解析是否正常nslookup example.com/dig example.com返回的A记录、查询耗时
指定DNS服务器解析nslookup example.com 114.114.114.114对比结果是否一致
清空系统DNS缓存Windows:ipconfig /flushdns执行后提示“已成功刷新DNS解析缓存”
查看hosts文件Windows:C:\Windows\System32\drivers\etc\hosts是否有过期的域名映射
IP连通性ping -c 5 目标IP丢包率、延迟波动
路由路径traceroute 目标IP中间跳延迟是否异常
端口开放检查telnet 目标IP 端口/nc -vz 目标IP 端口Connection refused还是超时
查看TCP连接状态ss -tn/ss -tn state syn-sentSYN_SENT堆积、ESTABLISHED数量
查看监听队列ss -lntRecv-Q和Send-Q是否积压
抓包分析tcpdump -nn -i eth0 tcp port 443SYN、SYN-ACK、重传包
查看TCP重传ss -tinretrans计数是否持续增长
防火墙规则计数iptables -L -n -v被DROP规则的计数是否增长

7.2 这些年排障,我总结的几条“心法”

最后分享几条我自己沉淀下来的习惯,不一定写在什么教科书里,但实战中非常有用。

第一,一次只改一个变量。很多故障排查到最后,发现问题是过去两三个小时里别人顺手改过配置导致的。你如果同时改了三处配置,烧香式地重启服务,问题就算消失了你也不知道是哪个改动起的作用。规范操作是先记录当前状态,做一次改动就验证一次,验证通过再动下一个。

第二,抓包要趁早,不要等“实在没办法了再抓”。抓包不是最后手段,而是最有力的证据。tcpdump在问题发生时打开,哪怕只看几十秒,都能帮你把“理论上的问题”变成“证据确凿的问题”。我经常看到有人花一两个小时猜防火墙、猜路由,最后抓包三分钟就定位了。

第三,现象和时间线一定要记录。什么时候开始报错、当时有没有发版、有没有改配置、是不是周期性出现,这些信息比任何命令都值钱。很多神秘故障的答案就藏在“报错时间点”和“变更时间点”的重合里。

网络故障排查这件事,本质上拼的是耐心和条理。技术命令背得再多,没有一套清晰的定位思路,遇到复杂场景还是容易原地打转。按照“DNS → IP连通 → TCP连接 → 连接质量”这条链路一层层验证下去,大多数看起来玄乎的网络问题,最后都会落在某个具体的可修复点上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 9:05:51

手脚冰凉别硬扛:激活人体产热机制的科学方案

1. 为什么你总是手脚冰凉——先把人体产热机制弄清楚每年一到冬天,办公室里总有那么几个同事裹着羽绒服、抱着暖水袋,手指头还是冰得能戳出凉气。我身边很多人把原因归结为“体质虚”,其实事情没那么玄乎,身体觉得冷,本…

作者头像 李华
网站建设 2026/10/3 9:05:15

瑞利衰落与莱斯衰落信道模型:从公式到可运行代码的仿真实现

简介:这份资源聚焦无线通信中的瑞利衰落与莱斯衰落信道建模,面向通信工程专业学生、科研人员及算法工程师,用于理解多径传播环境下信号强度的随机变化规律。压缩包共4个文件,以3个m脚本文件和1张jpg示意图为主,脚本分别…

作者头像 李华
网站建设 2026/10/3 9:04:20

基于Spring Boot的流浪动物救助站系统:从需求到部署的完整实战

前段时间接了个活儿,给本地一家流浪动物救助站梳理日常管理流程。去了现场才知道,情况比我预想的糟糕得多:动物登记靠纸质表格,领养申请全靠微信群里一条条聊天记录,物资出入库是用Excel记的,经常对不上账。…

作者头像 李华
网站建设 2026/10/3 9:03:58

Claude Code 从安装到实战:终端编程代理配置与踩坑全记录

最近一段时间,我把 Claude Code 从安装、配置到实战完整过了一遍,从命令行工具、VS Code 插件到桌面版,再到切换第三方模型、本地模型、嵌入式项目,过程挺有意思,坑也没少踩。这篇学习记录不是官方文档的复读&#xff…

作者头像 李华
网站建设 2026/10/3 9:03:51

用Django打造电脑配置推荐系统:从规则建模到部署实战

这台电脑怎么配?——这几乎是每个装机群每天都会出现的问题,也是不少计算机专业学生毕业设计题目里反复出现的一道经典题。我把这个题目用 Django 完整实现过一版,从需求分析到推荐引擎再到部署上线,一路踩了不少坑。这篇文章把完…

作者头像 李华
网站建设 2026/10/3 9:03:40

电商评论情感分析实战:从清洗到Streamlit看板的工程落地

简介:这是一套基于Python实现的电商评论情感分析系统,面向数据分析初学者、课程设计学生及毕业设计开发者,聚焦真实电商场景下的文本情感判别与产品口碑挖掘。资源包含1380个文件,主体为478个Python脚本(含Streamlit可…

作者头像 李华