TCP/IP前四层网络排障:分层定位与抓包实战 网络问题这东西最气人的地方在于它经常看起来没问题。网页能打开、视频能播但一到传大文件就断断续续或者白天一切正常晚高峰就集体卡成幻灯片。很多人遇到这类情况的第一反应是重启设备、换个浏览器、问运营商一圈折腾下来问题还在。我在机房里待久了发现一个规律凡是能定位到具体层的问题解决起来都很快凡是定位不到层的基本都在瞎猜。TCP/IP五层模型就是那张帮我们把瞎猜变成定位的地图——物理层、数据链路层、网络层、传输层、应用层从下往上每一层都有自己的活儿和自己的故障特征。这篇文章只聊前四层也就是物理层到传输层因为绝大多数网不通网很慢时断时续的问题都埋在这四层里应用层反而是最后才有资格被怀疑的对象。内容会从每层的核心机制讲到实际排障动作带上参数计算、抓包命令和踩过的坑不管你是刚学网络的在校生还是天天跟设备打交道的一线运维都能从里面捞到能直接用的东西。1. 先把分层这件事想明白再谈每层的知识点五层模型背起来只需要五分钟但真正理解它为什么这么切需要一点工程直觉。分层不是学术上的洁癖而是为了让责任可划分、故障可隔离、演进可独立。你把这一条想通了后面每一层的知识点才不是零散的名词而是各自有位置的零件。1.1 分层本质上是在切一条责任链想象一次跨城的物流运输。货物要装进箱子应用层协议的数据格式箱子要贴上单号交给快递网点传输层负责端到端的可靠送达网点之间要靠干线卡车跑高速网络层负责选路和跨网段转发卡车跑的每一段公路有路基和路面物理层负责把承载物变成电信号或者光信号而在相邻两个站点之间的短途倒运靠的是站点内部的调度和叉车数据链路层负责同一段链路内的寻址和帧传输。任何一环出问题货都到不了但表现出的症状完全不同路面塌了是全线瘫痪调度失误是某一段反复打转单号丢了是不知道货在哪箱子破了是内容物损坏。网络排障的思路就是这套逻辑——先判断症状属于哪一种再顺着责任链往回找。这个类比里有个关键点值得强调每一层只关心自己那一段的交付质量不关心上下层的细节。网络层不需要知道底下跑的是铜线还是光纤传输层也不需要知道中间经过了几个路由器。这种不关心是刻意的设计它让无线网络、光纤网络、虚拟网络可以在同一套上层协议下共存。理解了这一点你就不会再问为什么换了无线之后IP地址还是一样的这种问题了。1.2 从下往上每层到底背了什么锅把责任分清楚排障才不会乱。我在下面用一张表把四层的核心职责、寻址方式、典型故障现象列出来这张表建议直接记在脑子里比背协议字段有用得多层级核心职责本层寻址数据单元典型故障现象物理层把比特变成可在介质上传输的信号无靠端口和介质标识比特链路down、CRC错误暴涨、频繁掉速、收光功率异常数据链路层在同一段链路内把帧送到相邻设备MAC地址帧同网段通、跨网段不通ARP表异常MAC地址漂移环路广播风暴网络层跨网段选路并端到端投递数据包IP地址数据包能ping通网关但ping不通外网路由环路TTL超时分片失败传输层进程到进程的通信提供可靠或尽力而为的交付端口号段TCP/数据报UDP端口不通但主机可ping连接建立失败传输慢、频繁重传连接堆积这张表最有价值的地方在于典型故障现象这一列。现实里判断问题在哪一层靠的不是逐个字段排查而是先用现象做初筛。比如能ping通但网页打不开主机可达性没问题说明下面三层大体是通的嫌疑立刻缩小到传输层和应用层再比如局域网内互传很快一跨网段就慢那基本锁死在网络层和链路层的边界上。1.3 分层思维最容易踩的三个认知坑第一个坑是把分层当成隔离。层与层之间是解耦的但不是互不影响的。物理层出现大量误码会让传输层疯狂重传最终表现为应用很卡。如果你只在应用层找原因永远找不到根上。真正的排障原则是下层的问题会向上传染但上层的问题不会向下传染。所以自下而上的排查顺序在多数场景下更稳妥。第二个坑是把模型当成实现。五层模型是为了教学和理解而抽象出来的真实协议栈里网卡做了一部分校验操作系统内核做了另一部分硬件卸载又把一些工作从CPU挪到了网卡上。所以你抓包看到的TCP重传可能根本不是链路问题而是本机接收窗口太小导致的。搞清楚软件和硬件的分工边界比背模型更重要。第三个坑是忽视时间维度。很多故障是间歇性的用一次ping测试得出的结论毫无价值。链路误码往往是累积到一定量才爆发队列拥塞只在高峰出现。所以排查工具要能长时间观察并输出统计量而不是只给一次快照。后面每个层级我都会给几个能持续采样、能看错误计数的手段这类工具才是真排障时的主力。2. 物理层所有玄学问题的最终归宿物理层是唯一一层你无法用抓包工具直接看到内容的层因为它传的是电平和光强不是数据。但恰恰是这一层制造了最多重启一下就好了的玄学。凡是那种时好时坏、重启就恢复、过几天又犯的问题八成要往物理层想。2.1 介质、接口和速率的对应关系常见的有线介质就三类双绞线、光纤、同轴新建设施里基本见不到了。双绞线靠的是差分信号抗共模干扰一对线走一正一反接收端相减干扰被抵消掉。这就解释了为什么网线必须用双绞结构也解释了为什么劣质网线在电磁环境复杂的地方特别容易出问题——屏蔽和绞距不达标抗干扰能力直接崩盘。速率和线材的对应关系是有硬性门槛的。百兆以太网用两对线1-2、3-6千兆必须四对全用上2.5G和5G对线材的标称等级和长度更敏感。工程上通常以100米作为双绞线信道的长度上限这个100米不是拍脑袋定的它是信号衰减和回波损耗两项指标在标准速率下同时满足要求的最长距离。超过100米衰减让信噪比下降误码率上升链路可能直接协商不上也可能勉强连上但在高负载下频繁出错。光纤这边要区分单模和多模。单模芯径小通常9微米只能传一个模式色散小适合长距离多模芯径大50或62.5微米多个模式同时传播存在模间色散距离受限。模块和光纤必须匹配单模模块配多模光纤或者反过来轻则距离大幅缩水重则完全不通。接口侧还要注意收发光功率是否在模块的接收灵敏度范围内收光太强会烧接收端太弱则误码。工程上一般留3dB左右的余量这个余量的意义是给连接器老化、灰尘污染、弯折损耗留出空间。2.2 编码与信号质量线长了为什么就掉速比特本身是抽象概念要在铜缆上传输必须映射成电平变化这个映射就是编码。早期以太网用曼彻斯特编码每个比特中间必有一次跳变接收端靠跳变沿恢复时钟好处是自带同步能力坏处是效率只有50%。千兆及以后普遍采用更高效的线路编码比如4D-PAM5、PAM4配合复杂的前向纠错效率提高了但对信号质量的要求也水涨船高。这就引出一个非常实用的判断同一条链路低速能通但高速不通基本可以判定是物理层质量问题。因为高速率对信噪比、回波损耗、串扰的要求更严。你在现场遇到千兆协商不上只能跑百兆不要急着怀疑设备端口先换一根确定合格的跳线再用另一台设备交叉验证如果换了设备还是百兆那这条链路的路由、模块、接头就都值得怀疑了。这类问题的根源往往是水晶头压接不良、线序错误、线缆被重物压过导致特性阻抗变化或者面板模块和线缆不是同一等级。另一个高频现象是双工不匹配。一端强制全双工、另一端自动协商成半双工或者一端是千兆固定、另一端因为线材问题退到百兆都会造成一侧认为链路空闲可以随时发另一侧却在检测冲突结果是大量碰撞、迟到冲突、帧校验错误。表现就是链路是up的也能通但速度只有预期的几分之一。这种坑特别隐蔽因为从指示灯上看一切正常。2.3 物理层现场排障的三个动作真到了现场别急着敲命令有三件事先做。第一件事是看错误计数这是判断物理层健康度最直接的指标。Linux下可以用两条命令# 看接口的收发统计重点看 errors、dropped、overrun ip -s link show eth0 # 看网卡驱动的细分统计重点看 crc_errors、rx_length_errors、collisions ethtool -S eth0判断标准很明确链路稳定运行时CRC类错误应该接近于零或者增长极其缓慢。如果每分钟成百上千地涨那就是物理层在丢帧上层所有的重传、超时、卡顿都是它的下游反应。这时候换线、换端口、换模块一次只换一个变量。第二件事是确认协商结果。ethtool eth0输出里的Speed、Duplex、Link detected三个字段要一起看。速度对不对、双工是不是Full、链路是否检测到任何一个不对都要继续查。尤其注意有些设备默认关闭了自动协商这种配置在混插不同厂商设备时极容易出问题。第三件事如果怀疑是MTU或者大包问题用不分片的ping去验证路径能承载的最大包长# 1472 8(ICMP头) 20(IP头) 1500正好等于标准以太网MTU ping -M do -s 1472 192.0.2.10 # 如果上面不通逐步减小找到能通的最大值 ping -M do -s 1400 192.0.2.10注意-M do是禁止分片这个参数的意义在于让路径上某一段MTU偏小这件事暴露成明确的失败而不是被中间设备静默分片掩盖掉。如果小包通、大包不通说明路径上存在MTU瓶颈往下就要看是不是隧道封装、PPPoE、或者某些链路层协议占了额外字节。3. 数据链路层同网段内谁把帧送到谁手上跨过物理层第一个有地址概念的层就是数据链路层。它解决的是一个非常具体的问题在同一个广播域内一台设备怎么把数据准确地交给另一台设备。注意同一个广播域这个限定它划定了链路层的能力边界也是同网段通、跨网段不通这类经典现象的理论根源。3.1 以太网帧结构里那些常被忽略的细节标准以太网帧从前往后依次是7字节前导码、1字节帧起始定界符、6字节目的MAC、6字节源MAC、2字节类型/长度、46到1500字节的载荷、4字节帧校验序列。前导码和定界符不计入帧长它们的作用是让接收端完成时钟同步告诉对方数据马上来了。这里有两个数字值得记住最小帧长64字节最大帧长1518字节不含前导码和帧间隙。最小帧长的由来和早期的共享介质冲突检测机制有关——为了让发送方在信号传到最远端的往返时间内仍能监听到冲突帧不能太短否则发送方已经发完了才检测到冲突就没法重传。这个时隙被定为512比特时间换算下来就是64字节。即使现在的交换网络基本都是全双工、不再有冲突这个最小帧长作为兼容性约束依然保留着。所以你会看到ARP这种载荷很小的帧ARP报文本身28字节在线上实际是60字节左右剩下的部分靠填充补足。最大帧长1518字节对应MTU 1500。这个1500是IP层的最大传输单元减去20字节IP头和20字节TCP头留给应用数据的最大长度就是1460字节也就是MSS。这个推导链条必须记牢因为后面所有关于大包不通分片MSS协商的问题都从这里出发。VLAN标签会插入4个字节把最大帧撑到1522字节这也是为什么抓包时经常看到帧比预期长了4字节的原因。有些老设备不支持超长帧遇到带标签的帧直接丢弃这类兼容性问题在混合组网时特别常见。3.2 MAC地址、ARP与交换机的转发逻辑MAC地址48位前24位是厂商标识后24位由厂商分配。它有两个特殊值必须认识全F的广播地址以及组播地址第一个字节最低位为1。交换机就是靠MAC地址工作的它的核心机制是源地址学习 目的地址转发具体逻辑可以这样归纳收到帧先把源MAC和入端口记入MAC地址表并刷新老化计时器。查目的MAC命中且不在入端口从对应端口转发命中且在入端口丢弃不需要自己转发给自己。没命中向除入端口外的所有端口泛洪如果是广播或未知组播同样泛洪。这套机制简单高效但会带来一个问题未知单播泛洪。如果MAC表项老化或被撑爆大量帧会被泛洪到所有端口占用带宽、暴露流量、增加终端负担。MAC表容量是交换机的隐藏规格低端设备可能只有几百条接入终端一多就容易溢出表现形式就是莫名其妙变慢而且往往无规律。ARP是链路层和网络层之间的黏合剂。它的作用是把IP地址解析成MAC地址流程是广播询问、单播应答。这里有几个非常实用的知识点ARP缓存是有老化时间的通常几分钟。老化期间如果对端换了网卡通信就会发往错误MAC直到缓存刷新。免费ARP用于地址冲突检测和缓存刷新设备上电时会发一个源和目的IP都是自己的ARP请求如果有人应答说明地址冲突了。ARP欺骗的防御靠的是端口安全、静态绑定、DHCP Snooping之类的机制本质是让谁对应哪个MAC这件事变得不可伪造。现场最常见的链路层故障就是IP冲突和ARP表异常。排查手段很直接# 查看ARP缓存注意同一个MAC对应多个IP或同一个IP频繁换MAC ip neigh show # 抓ARP包观察是否有异常的大量请求或应答 tcpdump -i eth0 -nn -e arp提示同一个MAC映射到多个IP通常是私接路由器或者代理ARP造成的同一个IP短时间内对应多个MAC基本可以确定是IP地址冲突。这两种情况在网络里都会造成间歇性断连而且用ping测的时候往往看着是通的极具迷惑性。3.3 VLAN、Trunk与二层环路VLAN解决的是广播域隔离问题。没有VLAN一个二层网络就是一个大广播域广播帧会送到每一个端口终端多了之后广播风暴能把网络拖死。VLAN把一个物理交换机切成多个逻辑交换机广播只在VLAN内传播。端口有两种典型角色Access口属于某个VLAN接终端收发的是不带标签的帧Trunk口承载多个VLAN帧带802.1Q标签用于交换机之间互联。这里最容易出错的地方是两端VLAN配置不一致一端Access VLAN 10另一端Trunk允许VLAN 20结果就是链路是up的但就是不通。这类问题排查起来很快看一眼两端配置就清楚了难的是新手容易在物理层反复折腾。二层环路是另一个经典灾难。交换机的转发逻辑里没有TTL这种防环机制一旦出现环路广播帧会在环里无限循环短时间内把带宽和CPU吃满整个广播域瘫痪。STP生成树协议就是为此设计的通过选举根桥、计算最短路径把冗余链路中的一部分端口阻塞掉形成无环的逻辑拓扑。根桥选举的规则是桥ID最小者胜桥ID由优先级默认32768加MAC地址组成。实际工程里通常会手动把核心交换机优先级调低确保它稳定当根桥。因为如果让一台接入层设备意外成为根桥整个网络的流量路径会变得极其别扭表现为明明是同机房的设备互访却要绕到另一栋楼。# 查看生成树状态不同厂商命令差异较大这里是通用思路 # 关注谁是根桥、各端口角色Root/Designated/Alternate、端口状态 show spanning-tree3.4 用抓包把二层看清楚链路层的排查抓包是最有说服力的手段。加上-e参数就能看到MAC地址# 抓20个ARP包显示链路层头部 tcpdump -i eth0 -nn -e -c 20 arp # 抓VLAN标签需要网卡支持并正确配置 tcpdump -i eth0 -nn -e vlan 10 # 抓特定源MAC的所有流量 tcpdump -i eth0 -nn -e ether src 00:11:22:33:44:55抓包时看三个东西源和目的MAC是否符合预期、类型字段是什么0x0800是IPv40x0806是ARP0x8100是带VLAN标签、帧长是否合理。如果看到大量重复的广播帧在同一个端口进出环路基本坐实如果看到ARP请求发出去了但没有应答问题可能在对端主机或者中间的二层隔离比如端口隔离、私有VLAN。我个人习惯是遇到局域网内互访异常先在两端各抓一小段包对比一下。如果A发出去了B没收到问题在中间链路如果B收到了但没回应问题在B的主机配置防火墙、ARP、路由表如果B回应了A没收到那就是回程路径的问题。这个三段对比法能把责任范围压缩到很小比盲目翻配置高效得多。4. 网络层选路、编址和那些绕不开的计算网络层是整个协议栈里知识密度最高的一层也是最容易考、最容易用错的一层。它的两件核心工作是编址和选路给每台设备一个逻辑地址然后决定数据包从哪条路走。4.1 IPv4报头里真正要盯的字段IPv4报头固定20字节最长60字节。字段不少但排障时真正高频使用的就那么几个字段长度排障价值总长度16位判断是否分片、单包大小是否异常标识16位同一数据报的所有分片共享此值用来重组标志位3位DF位决定是否允许分片MF位标记后面还有分片分片偏移13位以8字节为单位重组时的位置依据TTL8位每过一个路由器减1减到0丢弃并回ICMP超时是防环的核心协议号8位6TCP17UDP1ICMP用于交付给上层首部校验和16位只校验首部不校验数据TTL这个字段值得单独说。它的设计初衷是防止数据包在网络里无限打转每经过一台三层设备就减1减到0就丢弃并回一个ICMP超时消息。这个机制衍生出了两个极其实用的工具traceroute原理就是发送TTL递增的包让路径上每一跳依次返回超时消息从而探测出完整路径ping返回的TTL值则可以用来粗略判断对端操作系统和中间经过的跳数——初始TTL常见的是64、128、255收到时看到63基本可以推断中间过了一台设备且对端初始值是64。协议号是另一个关键点。它决定了IP层把载荷交给谁。看到协议号6就知道里面是TCP1就是ICMP。防火墙和ACL配置里经常需要指定协议号抓包时也能靠它快速筛出关心的流量。4.2 子网划分把计算过程彻底走一遍子网划分是网络层最实操的部分也是很多人看得懂但算不对的地方。核心只有一个公式块大小 256 - 掩码中关键的那一段十进制值。先看一个标准的等长划分。把192.168.10.0/24划分成4个子网需要借2位主机位掩码从 /24 变成 /26十进制是255.255.255.192。块大小 256 - 192 64。所以四个子网的起点依次是 .0、.64、.128、.192子网网络地址可用主机范围广播地址可用数量1192.168.10.0/26.1 - .62192.168.10.63622192.168.10.64/26.65 - .126192.168.10.127623192.168.10.128/26.129 - .190192.168.10.191624192.168.10.192/26.193 - .254192.168.10.25562可用数量是2的(32-26)次方减2也就是64减2等于62。减掉的这两个就是网络地址和广播地址它们不能分配给主机——这一点在给设备配地址时特别容易犯见过有人把网关配成 .255 然后在群里问为什么不通。再看一个反向题目从掩码快速判断容量/27的掩码是255.255.255.224块大小 256 - 224 32每个子网32个地址可用30个。/28是240块大小16可用14个。这个规律记住之后看到一个掩码能在三秒内说出它能装多少台设备比现场拿计算器靠谱。路由聚合是反向操作把多条明细路由合并成一条。比如有192.168.0.0/24到192.168.3.0/24这四条看第三段的二进制0是 000000001是 000000012是 000000103是 00000011。前6位完全相同所以可以聚合成192.168.0.0/22掩码255.255.252.0块大小4正好覆盖 .0 到 .3。聚合要满足必须是2的幂次且起始地址对齐这两个条件否则会多覆盖不属于自己的网段造成路由黑洞。注意规划地址时一定要预留。我见过太多项目把 /24 一刀切成 /26 全部分配出去半年后要加一个部门发现没有一个连续的块可用只能在别处重新起一段地址路由表越来越碎。实际做法是按业务类型分段、每段留出至少一倍的余量同类型的业务放在连续地址段里方便后续聚合。4.3 路由表和最长前缀匹配一台设备决定往哪发看的是路由表。表的每一条包含目的网络、掩码、下一跳和出接口。查表规则是最长前缀匹配在所有能匹配上目的地址的条目里选掩码最长的那条。举个例子路由表里有ip route show # 192.168.0.0/16 via 10.0.0.1 dev eth0 # 192.168.10.0/24 via 10.0.0.2 dev eth0 # 0.0.0.0/0 via 10.0.0.254 dev eth0目标地址是192.168.10.55三条都能匹配但 /24 最长所以走 10.0.0.2。目标地址是192.168.20.1/24 不匹配/16 匹配走 10.0.0.1。目标地址是203.0.113.5只有默认路由匹配走网关。这个规则解释了一个非常常见的现象明细路由永远优先于默认路由。所以你在做策略路由或者分流的时候加一条更长的前缀就能把特定流量引到指定出口不需要动默认路由。ip route get这个命令值得熟练使用它能直接告诉你去往某个地址系统实际选了哪条路由、从哪个接口出、源地址是什么ip route get 203.0.113.5排查为什么流量走了错误出口这类问题时这一条命令比翻整张路由表快得多。尤其在有多个默认路由、策略路由、多网卡的情况下路由表可能有几十条肉眼比对容易出错。4.4 分片、TTL与ICMP的实战用法分片这事理论上是网络层的合法行为实际上是个性能杀手。原因在于分片后的重组要消耗资源只要丢一个分片整个数据报就得重传而且很多防火墙对分片的处理策略不一致。所以现代网络普遍通过路径MTU发现机制来避免分片发送方把IP头的DF位置1中间设备如果发现包比自己的MTU大就回一个ICMP需要分片但DF已置位的消息发送方据此调小包长。这套机制的软肋在于它依赖ICMP。如果链路上有设备把ICMP全封了路径MTU发现就失效表现为小包正常、大包不通、连接建立后卡死。这类问题极难排查因为ping小包永远通。判断方法就是用前面提到的ping -M do -s逐步找最大可通包长如果 1472 不通但 1400 通说明路径上有设备MTU小于1500通常出现在隧道封装、PPPoE拨号、某些链路层协议开销较大的场景。ICMP本身也是排障利器但经常被误解。除了ping和traceroute用到的echo请求/应答和超时消息还有几个值得认识的类型ICMP类型含义排障用途3目的不可达细分码能区分是网络不可达、主机不可达还是端口不可达11超时TTL减到0时返回traceroute的基础5重定向提示主机存在更优网关出现频繁说明网关配置不当8/0回显请求/应答ping的底层实现其中端口不可达类型3码3特别有用它意味着包已经到达了目标主机只是目标主机上没有进程监听那个端口。所以如果ping不通但能收到端口不可达说明网络是通的问题在服务本身反过来如果连端口不可达都收不到那才需要怀疑网络层。5. 传输层端口、连接和那些决定速度的参数传输层是应用能直接感知到的最后一层。它把主机到主机的通信细化为进程到进程的通信靠端口号做区分。TCP提供可靠的有序字节流UDP提供简单的数据报服务两者的取舍贯穿了整个应用架构设计。5.1 端口和TCP报头的关键字段端口号16位范围0到65535。0到1023是知名端口需要特权才能绑定1024到49151是注册端口49152以上是动态端口客户端发起连接时由系统临时分配。这个划分有个实际影响一台服务器对外提供服务的端口是固定的但它的客户端连接会占用大量动态端口如果连接数极高可能把本地端口耗尽表现为连不上新连接但CPU和带宽都不高。TCP报头也是20字节固定部分几个字段必须吃透序号Sequence Number本段数据第一个字节在整个字节流里的位置。注意SYN和FIN虽然不携带数据但各消耗一个序号这个细节在做序列号推算时经常出错。确认号Acknowledgment Number期望收到的下一个字节的序号等于已收到的最后一个字节序号加1。数据偏移指出报头长度4位单位是4字节所以最大60字节说明选项部分最多40字节。标志位SYN、ACK、FIN、RST、PSH、URG。RST值得单独提它表示复位连接收到RST通常意味着对方没有监听这个端口或者中间设备主动干预了。窗口16位接收方告诉发送方自己还能接收多少字节。这个字段决定了吞吐量的上限。校验和覆盖伪首部、TCP头和数据比IP的校验更完整。5.2 三次握手和四次挥手的状态追踪三次握手的意义是双向确认收发能力和初始序列号。整个过程客户端发SYN携带自己的初始序列号x进入SYN_SENT。服务器回SYNACK携带自己的初始序列号y确认号x1进入SYN_RCVD。客户端回ACK序号x1确认号y1双方进入ESTABLISHED。为什么是三次不是两次因为两次只能确认客户端能发、服务器能收这一半服务器无法确认自己的发送能力被客户端接收到了也无法确认客户端收到了自己的初始序列号。第三次ACK补上了这一环。这个解释听起来像考试题但它有实际价值如果你在抓包里只看到SYN和SYNACK没有第三次ACK说明问题在客户端侧——可能是客户端收到SYNACK后崩溃了也可能是回程路径被防火墙拦了。四次挥手是因为TCP是全双工的两个方向要各自关闭主动关闭方发FIN进入FIN_WAIT_1。被动关闭方回ACK进入CLOSE_WAIT主动方进入FIN_WAIT_2。被动方处理完剩余数据后发FIN进入LAST_ACK。主动方回ACK进入TIME_WAIT等待2MSL后真正关闭。TIME_WAIT是最容易被误解的状态。它存在的理由是两条一是保证最后一个ACK能到达对端如果ACK丢了对端会重发FIN此时连接还在才能重发ACK二是让本次连接中延迟到达的报文在网络中消亡避免污染使用相同四元组的新连接。2MSL的等待时间在多数系统上是60秒这在高并发短连接场景下会造成大量端口占用。CLOSE_WAIT堆积则是另一类经典问题说明被动关闭方收到了FIN但没有调用close通常是应用代码里有连接泄漏忘了释放资源。看到某个进程的CLOSE_WAIT数量持续增长直接去查它的连接池和异常分支处理不用怀疑网络。# 统计各状态连接数CLOSE_WAIT和TIME_WAIT的数量变化最能说明问题 ss -tan | awk NR1 {print $1} | sort | uniq -c | sort -rn # 看整体概览 ss -s5.3 窗口、重传和拥塞控制速度到底由谁决定传输速度不是单纯由带宽决定的实际上是三个限制取最小值带宽、接收窗口、拥塞窗口。接收窗口是接收方通告的表示我缓冲区还能放多少。TCP头里窗口字段只有16位最大65535字节这个值在长肥管道上远远不够。所以引入了窗口缩放选项通过移位把窗口放大最大可放大到约1GB。这个选项只在握手时协商一旦协商失败窗口就固定在64KB链路再好也跑不快——这是能ping通但传文件极慢的常见原因之一。判断方法就是抓握手包看双方是否都带了窗口缩放选项。拥塞控制是发送方自己维护的它不知道网络到底有多堵只能靠丢包和延迟来试探。经典算法分四个阶段阶段触发条件行为慢启动连接建立或重传超时后拥塞窗口从初始值开始每收到一个ACK增加一个MSS等效每个RTT翻倍拥塞避免窗口达到慢启动阈值每个RTT只增加一个MSS线性增长快重传收到3个重复ACK不等待超时立即重传丢失的段快恢复快重传之后阈值减半窗口从新阈值开始线性增长不回到慢启动慢启动的初始窗口在现代实现里通常是10个MSS也就是约14.6KB。这个数字解释了一个现象短连接的首屏加载速度受初始窗口限制即使带宽充足前几个RTT能传的数据量也很有限。这也是为什么HTTP/2、HTTP/3要做连接复用——复用省掉的正是反复慢启动的开销。重传超时的时间RTO是根据RTT动态计算的大致公式是平滑RTT 4倍RTT偏差。RTT抖动越大RTO越保守重传等待越久用户体验越差。所以单纯的高延迟不可怕抖动才可怕。看TCP的重传统计Linux上有现成的工具# 查看TCP连接的详细统计包括重传段数 ss -tin # 系统级TCP统计重点看 retrans_segs 和 retransmit 相关计数 nstat -az | grep -i -E retrans|timeout重传率长期高于1%就值得查了可能是链路误码、可能是拥塞、也可能是对端接收窗口太小导致不必要的重传。区分方法是看RTT和重传的分布如果RTT平稳但重传集中在特定对端多半是对端问题如果整条链路都在抖回去看物理层。5.4 UDP的适用边界和常见误区UDP只做了端口复用和最基本的校验不保证顺序、不保证送达、不控制拥塞。这听起来像是缺陷但在特定场景下反而是优势没有握手延迟、没有重传等待、没有队头阻塞。适合UDP的场景有个共同特征——单个数据报的价值随时间快速衰减。实时音视频通话里一个已经延迟300毫秒的语音包重传回来也没用了不如丢掉。DNS查询也是一问一答用UDP省掉握手快得多。游戏同步、监控指标上报、日志采集都符合这个特征。但用UDP就快是个误解。UDP快是因为它不做那些TCP做的保障工作代价是应用层要自己承担。现代的做法往往是在UDP之上重新实现可靠性和拥塞控制把控制权拿到应用层典型的思路就是基于UDP的可靠传输协议。这类方案的核心优势在于可以按业务定制重传策略比如音视频可以只重传关键帧、可以优先保证时延而不是完整性。UDP还有个坑是数据报边界。UDP保留消息边界发一次收一次上层必须自己处理粘包问题。而且UDP不负责分片重组之外的任何事超过MTU的数据报在IP层分片任何一个分片丢失整个数据报就废了所以应用层通常会把单包控制在1200字节以内给隧道封装留出余量。6. 排查实录把四层的知识串成一套动作知识点的价值在于被调用。前面四层拆开讲了最后一节讲怎么把它们组织成一套排障流程以及几个反复出现的坑。6.1 自下而上还是自上而下这两种顺序没有绝对对错取决于你掌握的信息量。如果你完全不了解现场只知道网不通那就自下而上。先看链路是否up、看错误计数、看ARP、看网关能否ping通、看端口是否可达一层层往上排除。这个过程慢但不会漏。如果你已经知道别的服务都正常就这一个不行那就自上而下直接从应用和传输层入手因为下层大概率是好的。这时候从物理层开始查纯属浪费时间。还有一个更高效的做法是二分定位先ping目标IP。ping通说明网络层及以下基本没问题直接跳到传输层查端口ping不通就往上回退到网络层查路由和ARP。这一刀把四层砍成两半能省掉大量无效动作。用一句话概括判断依据现象首要怀疑层完全不通连网关都ping不到物理层 / 数据链路层同网段通跨网段不通网络层网关、路由、掩码能ping通端口连不上传输层监听、防火墙、ACL连接能建立传输极慢传输层窗口、重传、MSS或物理层误码时通时断无规律物理层链路质量、双工或链路层环路、地址冲突6.2 常见问题速查表现象最可能原因验证方法处理动作千兆口只能跑百兆线材等级不够、线序错误、水晶头压接不良ethtool看协商结果换合格跳线复测更换线缆或模块逐段排查链路up但速率极低双工不匹配、大量CRC错误ethtool -S看错误计数统一两端双工配置优先自动协商局域网内互访断续IP地址冲突、ARP表异常ip neigh看MAC与IP对应关系定位冲突设备做地址绑定网络突然全瘫、广播量大二层环路抓包看重复广播帧查STP状态断开冗余链路修正STP配置大包不通、小包正常路径MTU小于1500ping -M do -s逐步二分调小MSS检查隧道和封装开销能ping通但服务连不上端口未监听或被拦截ss -tlnp看监听tcpdump看是否收到SYN启动服务或调整策略传大文件速度上不去窗口未协商、重传率高抓握手包看窗口缩放ss -tin看重传调整缓冲区排查链路丢包大量CLOSE_WAIT堆积应用未正确关闭连接ss -tan统计状态分布排查代码资源释放逻辑大量TIME_WAIT堆积短连接过多同上启用连接复用调整相关参数6.3 几条踩出来的经验第一条先确认变了吗再确认哪里变了。网络突然出问题绝大多数时候是有人动过配置、换过设备、加过终端。先问清楚最近有什么变更比直接上工具高效十倍。我见过排查两小时最后发现是插了一根网线形成环路的案例也见过反复重启设备最后发现是DHCP地址池耗尽的案例共同点是变更没有记录。第二条不要迷信单次测试结果。ping通一下不代表链路稳定网页能打开不代表带宽够用。真要评估质量就得挂长时间采样看错误计数的增长趋势、看重传率、看延迟的分位数而不是平均值。平均值90毫秒但偶尔飙到3秒用户体感就是卡而平均值完全体现不出来。第三条一次只改一个变量。同时换线、换端口、改配置即使问题消失了你也不知道是哪个动作起的作用下次遇到同样问题还是不会。排障的价值不只在于解决当前问题更在于积累可复用的因果判断。第四条学会读错误计数的方向。接收方向的CRC错误说明信号在到达本机之前就坏了问题在链路上游发送方向的错误说明本机发出时就出了问题可能和驱动、硬件、协商有关。这个方向性判断能砍掉一半的排查范围但很多人只看有错误就结束了。第五条MSS钳制和MTU发现是跨网段问题的万能钥匙之一。凡是能连上但传数据就卡死的诡异现象先怀疑MTU。这个怀疑成本极低验证也快收益却很高。我个人在实际操作中的体会是五层模型最大的用处不是让你背出每一层的协议而是给你一个收敛怀疑范围的框架。真正的排障过程很少是线性的更像是在几个层之间来回跳但每一次跳跃都应该有依据——依据就是这一层该负责什么、不该负责什么。等你对每层的边界足够熟悉很多问题的答案会在几秒钟内浮现出来那种感觉就像看惯了地图之后不用导航也知道该往哪个方向走。至于工具命令会变、界面会变、厂商会换但这四层的分工几十年没变过把这块地基打牢学什么都快。