资讯详情

DHCP到网卡丢包:网络故障排查全链路解析

📅 2026/10/18 15:36:27 | 华诺云谱 👁 阅读
DHCP到网卡丢包:网络故障排查全链路解析
不知道你有没有半夜被叫起来处理网络时好时坏的经历。明明服务没重启、密码没改、机房也没断电但客户就是反馈卡顿、超时、掉线。这类问题我处理过太多次了到最后你会发现一个残酷的事实几乎所有网络故障本质都是某个数据包没有被正确送达或者送到后没被正确处理。而要搞清楚这个问题你必须把一条链路彻底弄明白——从设备怎么拿到IPDHCP到拿到的是公网还是私网地址再到这个数据包如何被封装、路由、转发最后到达网卡之后是怎么被收进来的以及为什么会被无声无息地丢掉。这篇文章我就围绕这条主线把DHCP的工作原理、公网与私网IP的区别、一次网络请求的数据包完整流程、网卡内部的工作机制以及最让人头疼的网卡丢包问题完整串一遍。适合刚入行的运维、网络工程师也适合那些想系统搞懂数据包到底怎么走的开发者和学生。内容偏原理但每一段我都会结合实际排障经验讲不是那种看完就忘的理论书。1. DHCP的四个阶段从无人理睬到拿到地址的完整握手1.1 为什么需要DHCP它到底分配了什么先说一个最基础的场景你把一台崭新的电脑插到办公室网口上没做任何配置几十秒后就能上网了。这中间发生了什么答案是DHCP动态主机配置协议替你完成了IP配置。如果回到二十年前那时候管理员是手工给每台机器填IP地址的。你想想那画面300台电脑一台台记IP、填子网掩码、填网关如果哪天改了一次网段切换就得重新跑一圈。这还不算最恐怖的最恐怖的是有人乱填把别人的IP占用了冲突的机器直接断网。DHCP解决的问题就是把这套繁琐的动态配置过程自动化。它分配的远不止一个IP地址还包括IP地址子网掩码默认网关DNS服务器地址租期Lease Time以及一些可选参数比如域后缀、NTP服务器等从协议栈的位置来看DHCP属于应用层协议它基于UDP客户端用68端口服务器用67端口。但有意思的是在客户端还没有IP地址的情况下它是怎么和服务器通信的呢靠的就是广播。1.2 Discover、Offer、Request、Ack四步还不够加上Release才完整DHCP最经典的交互过程是四步握手抓包经常能看到以下几个包第一步DHCP Discover。客户端在拿到IP之前源地址只能是0.0.0.0目标地址是255.255.255.255也就是广播地址。它向整个广播域喊了一嗓子有没有DHCP服务器我需要一个IP地址。注意这里它连子网掩码都还不知道呢所以只能拿全网络的广播地址来喊。第二步DHCP Offer。服务器收到Discover后会从地址池里挑一个IP通过广播或者单播取决于客户端在Discover里的标志位设置回复一个Offer包我这里有这个IP带上掩码、网关、租期你要不要第三步DHCP Request。客户端收到Offer后会广播一个Request包。这里有个关键点为什么客户端的接受回复要用广播而不直接单播给那个服务器因为可能同一网段有多台DHCP服务器都回了Offer客户端选择了其中一台但需要告诉其他服务器我不用你们的IP了请释放。如果单播只告诉被选中的服务器那些落选的服务器还会傻乎乎等着客户端来续租造成地址浪费。第四步DHCP Ack。被选中的服务器收到Request后确认这个IP正式分配给客户端发一个Ack。客户端拿到Ack就完成了配置。除了这四步还有一个包值得注意Release。当客户端主动释放IP比如你拔网线、dhclient -r命令时会发送。另外如果客户端后来发现IP被占用了比如自己ping不通网关或者有人手工配了相同IP客户端会发一个DHCP Decline告诉服务器这个IP我不要了。1.3 租期续租机制和两个要命的阈值拿到IP只是开始这个IP不是永久归你的它有一个租期。默认情况下很多路由器里的租期是12小时或者24小时。客户端会在两个时间点尝试续租T1一般是租期的50%。到点后客户端直接单播给当时分配IP的那台DHCP服务器说IP我还用着续一下。如果成功了就继续安静上网。如果T1没续上等到T2租期的87.5%客户端会重新回到广播方式发送Discover请求任意一台可用的服务器来分配IP。这里有个常见的坑如果你改了DHCP地址池的网段配置然后重新启动DHCP服务而客户端还在旧租期内它会继续用旧IP直到T1时间点你可能发现机器半小时上不了网。我处理过好几次改完路由器配置后有些手机连不上Wi-Fi的问题最后发现就是这个租期没到期的原因。所以现在我在改地址池时会顺手把租期临时调成两分钟等设备全部重新拿到新地址后再调回来。跨网段的时候DHCP请求就没法靠广播转发了需要在三层设备上配置DHCP中继IP Helper。它的原理很简单把客户端的广播包转成单播发给指定的DHCP服务器服务器回复后再由中继单播返给客户端。很多人在配置跨网段DHCP时发现客户端一直拿不到IP十有八九就是忘了在中继设备上配置接口地址和服务器地址。2. 公网IP和私网IPNAT背后的地址分配逻辑与运营商级陷阱2.1 只有43亿个IPv4地址为什么你家几十个设备都能上网拿到IP之后紧接着就要搞清楚一个概念这个IP到底是公网的还是私网的。IPv4的地址总量是2的32次方大约43亿个。全球几十亿人人手一个都不够更别提一个人还有电脑、手机、平板、智能家电、服务器一台设备就需要一个IP。所以大家想了一个办法把IP地址划分成公网可路由的地址和私网内部使用的地址。私网地址段是RFC 1918规定的说白了就是三块预留的自留地网段范围典型用途10.0.0.0/810.0.0.0 ~ 10.255.255.255大型企业内部网络172.16.0.0/12172.16.0.0 ~ 172.31.255.255中型网络云计算VPC常使用192.168.0.0/16192.168.0.0 ~ 192.168.255.255家用路由器和中小公司最常用这三段地址有个共同特点它们在公网上不会被路由。也就是说你拿着一个192.168.1.100的源IP去访问公网服务器到了运营商核心网就会被丢掉因为公网路由表里根本没有这些网段的路由条目。那家里几十个设备怎么上网答案是NAT网络地址转换。所有私网设备把数据包发给家用路由器路由器把源IP统一改写成自己唯一的公网IP再加上端口号来区分是哪个内部设备发起的会话。这种多对一的转换也叫NAPT网络地址端口转换。过程可以简单理解为内网一台设备用192.168.1.100:50000的源发送请求路由器收到后把它改成203.0.113.10:65000发出。服务器回包给203.0.113.10:65000路由器查自己的转换表知道这个端口对应内网192.168.1.100:50000于是把包改回去扔给内网设备。这里就衍生出一个所有运维都耳熟能详的结论公网服务器没法主动连接内网设备。原因不是技术上行不通而是NAT转换表里没有对应的映射。外部的包到了路由器路由器根本不知道该转给谁。所以那些想在公司内网暴露服务到外网的人要么做端口映射手动添加转换规则要么用一些隧道类工具打洞原理都是让内网主动建立一条会话再复用这条会话做反向数据传递。2.2 家用宽带背后的运营商级NAT你踩过的坑现在不少家庭宽带光猫的WAN口地址既不是公网IP也不是我们熟悉的192.168这类私网IP而是100.64.0.0/10这个范围内的地址。这段地址是RFC 6598规定的运营商级NAT专用地址CGNAT。为什么运营商要搞这么一出因为公网IPv4地址早就枯竭了运营商手里的公网地址不够给每个宽带用户分配一个。他们把大量用户塞在同一台运营商NAT设备后面让所有用户共享少量公网IP出口。这台设备造成的实际影响做过网络的人应该深有体会你在家里部署的服务无论怎么设置路由器端口映射都访问不了因为运营商那层NAT把你的公网流量又转了一道映射关系根本不归你控制。P2P下载、视频通话、远程桌面直连经常失败因为打洞打不过运营商那层NAT。排查方法特别简单登录光猫看WAN口IP如果在100.64.0.0/10范围基本就是中了CGNAT的招。打电话找运营商申请公网IPv4大部分地区都能申请下来只有极少数地区会拒绝。IPv6曾经被视为解决地址短缺问题的终极方案公网IPv6地址数量大到浪费也没事每台设备都能分到独立公网地址。但这么多年过去了很多应用和运维体系还是对IPv6适配不够上心NAT这套IPv4时代的老办法依旧统治着日常网络。这个现实短期内不会改变。3. 一次网页请求的数据包之旅封装、路由与逐跳改写的全过程3.1 从浏览器地址栏到服务器网卡数据包经历了什么地址问题搞清楚了现在来看一个完整的数据包是怎么从你浏览器出发跨过互联网到达服务器的。假设你在浏览器输入了一个域名整个过程分这么几层第一DNS解析。浏览器先要知道这个域名对应的IP地址。它会向配置好的DNS服务器发起查询拿到IP。DNS查询本身也是一个完整的UDP数据包流程这里先不展开。第二TCP三次握手。浏览器拿到的IP和目的服务器的80或443端口建立起TCP连接。SYN、SYN-ACK、ACK三次交互后连接建立。第三HTTP请求发送。浏览器把HTTP请求封装成TCP数据段加上源端口随机高端口和目的端口80或443。第四IP封装。操作系统把这个TCP段交给IP层加上源IP你的内网IP和目的IP服务器IP为它找到一条出去的路径。第五以太网封装。在真正发出网卡之前还要加上源MAC地址和目的MAC地址。注意这里其实涉及一个关键判断目的IP和你在不在同一个网段如果在同一网段直接ARP查找目的IP的MAC地址。如果不在同一网段数据包必须先发给网关处理此时目的MAC地址是网关的MAC而不是最终服务器的MAC。很多人刚开始抓包时会困惑我明明在访问一台远程服务器为什么以太网帧里的目的MAC是我家路由器的答案就在这里——MAC地址是逐跳变化的但IP地址在到目标之前保持不变。3.2 中间每一跳的路由器到底做了什么数据包从家用路由器出去后会一路经过多台运营商路由器每一跳做的事高度一致从物理端口收到以太网帧。剥掉链路层的帧头和帧尾取出IP包。查路由表依据目的IP做最长前缀匹配决定下一跳IP和出接口。重新封装一个新的以太网帧目的MAC改成下一跳设备的MAC源MAC改成自己出接口的MAC从出接口发出去。这个过程的本质就是源IP和目的IP全程不变但每一段的MAC地址都在改写。我在给新人讲这个的时候喜欢用快递做类比IP地址是写在快递单上的收件人地址从发货到收货全程不变但每个中转站贴的转运条码每次都换成下一站的信息不同中转站之间的交接凭证不一样。整个过程中还有一个容易被忽略的机制TTLTime To Live。IPv4包里有一个TTL字段每经过一个路由器就减1减到0就丢弃并给发送方回一个ICMP超时消息。这个机制有两个用途一是防止数据包在环路上无限打转二是被traceroute命令利用来探测路径上的每一跳设备。关于MTU最大传输单元也值得说几句。大部分以太网链路MTU是1500字节如果你的IP包总长度超过这个值且包头的DF禁止分片标志没有设置路由器就会把它拆成多个小片继续发。但很多安全设备、隧道设备会设置DF位导致大包直接发不出去。这类问题排查的时候用ping命令加大包体并设置DF位来测就能快速定位能通则通大包不通的MTU故障。3.3 数据包从入口到应用进程的最后几步到了目标服务器数据包也不是直接被应用拿到的中间还有好几道关卡。先是服务器的网卡根据目的MAC地址把帧收进来剥掉以太网帧头把IP包交给IP层。IP层检查目的IP是不是本机是的话交给TCP/UDP层。TCP层通过目的端口号找到正在监听这个端口的socket把数据放到接收缓冲区。应用进程调用read()把它读走。这个过程看着简单但每一步都藏着几个经典丢包点。TCP层有个半连接队列和全连接队列分别对应握手未完成和已完成但未被应用accept的连接。如果应用处理太慢全连接队列满了服务器就会直接丢弃新来的SYN包。你在客户端看到的症状是TCP连接超时但在服务器上抓包却看不到明显的错误因为包在协议栈里被静默丢掉了。在排查这类问题时我常用的一个思路是先确定故障在哪一层再用排除法逐步定位。而排除法的基础是对这条完整链路的每一步心中有数。4. 网卡内部是怎么工作的环形队列、中断与卸载特性的底层逻辑4.1 网卡绝不只是一个插网线的口说到数据包到服务器的最后一米就绕不开网卡。我接触过不少运维对网卡的理解还停留在一个RJ45接口。实际上网卡本身就是一个微型计算机它承担了大量与CPU的协同工作。网卡的核心职责可以拆成几条物理层收发把电缆或光纤上的模拟电流/光信号解码成二进制的数据帧。帧校验每个以太网帧末尾都带一个FCS帧校验序列网卡用CRC算法校验如果发现FCS错误直接丢弃这个帧因为数据已经不完整了。地址过滤网卡检查帧头里的目的MAC如果不是本机MAC、不是广播MAC、也不是组播MAC在开启组播过滤的情况下直接丢弃不惊动CPU。DMA传输数据帧校验通过后网卡通过DMA直接内存访问把数据写到内存中的环形缓冲区不用CPU逐拷。为什么网卡要支持DMA想象一下如果每个收到的包都要CPU亲自从网卡寄存器里一个一个搬进内存高速网络下CPU会直接被中断和拷贝操作打满根本没有余力处理应用逻辑。DMA本质上是让硬件设备直接访问内存只在完成一批传输后打断CPU。4.2 环形队列和中断机制数据进内存前的最后一道门刚才提到的环形缓冲区Ring Buffer是理解和排查网卡丢包的关键。它的工作原理像一条环形传送带网卡把收到的帧放到Ring Buffer里然后给CPU发一个中断信号告诉它有数据来了快来处理。CPU收到中断后从Ring Buffer里取出数据交给网络协议栈。Ring Buffer是有容量的默认在256或512个描述符左右具体看网卡驱动。如果CPU处理速度跟不上数据包到达的速度Ring Buffer会被填满。满了之后会发生什么新到的数据帧无处安放直接被网卡丢弃。这个丢弃行为会在网卡统计计数器里留下痕迹。这也是下一章要重点展开的问题。还有个概念叫中断合并Interrupt Coalescing和NAPI。早期网卡是收到一个包就中断一次CPU高并发下CPU会陷入中断风暴干不了正事。现代驱动普遍使用NAPI机制数据包大量到达时网卡的中断响应转为轮询模式CPU持续从Ring Buffer里批量取包而不是被打断几千次。中断合并则是让网卡攒一批包再统一通知CPU牺牲少量延迟换取高吞吐。在延迟敏感场景下反而需要调低合并阈值。4.3 卸载特性为什么抓包看到的MTU超过了1500现在的高性能网卡还有各种硬件卸载特性比如校验和卸载和分段卸载。Checksum Offload的意思是TCP/UDP包的校验和计算交给网卡硬件完成CPU不用算了。TSOTCP Segmentation Offload更狠应用和驱动可以把一个几MB大小的TCP段直接交给网卡网卡硬件自己按照MTU把它切成一个个符合标准的以太网帧再发出去。这带来一个抓包时的常见迷惑现象在服务器上用tcpdump抓包经常看到超过MTU的超大包。这不是出了bug而是抓包点位于驱动层之上或者在硬件队列中看到的是TSO切分前的大段数据。排查真实MTU问题时如果开着TSO抓包结果很容易误导你这时候要先用ethtool把TSO/GRO/GSO临时关掉再测试。多队列RSSReceive Side Scaling也是现代网卡的标配。网卡内部有多个Queue每个Queue可以绑定不同的CPU核通过哈希算法把不同连接的数据流分散到不同队列实现多核并行处理收包。如果没有多队列或者驱动没正确启用所有收到的包都会压到一个CPU核上那个核的softirq软中断使用率直接飙到100%而其他核闲着。这是很多高流量服务器性能上不去的隐形原因。5. 实测网卡丢包排查计数器里的真相与一次断流问题复盘5.1 一次网络时好时坏的完整复盘前四年份的铺垫都是为了这一刻真刀真枪地排查一次网卡丢包。我这里说的丢包是真正意义上的沉默故障网络层的ping可能正常但应用层就是时快时慢。之前帮某客户处理过一次特别典型的问题。现象是服务器上跑着一个接口服务客户端反馈时好时坏高峰期延迟从正常的5ms飙到300ms偶尔直接超时。服务器CPU、内存、磁盘都很健康完全没有高负载迹象。我的排查链路是这样的第一步ping测试。从客户端ping服务器发现平均延迟还行但max值比平时高了一个量级。再ping网关延迟稳定说明物理链路没大问题问题大概率出在服务器收包后的某个环节。第二步检查网卡统计计数器。这是最关键的一步。ethtool -S 输出里有个叫做rx_missed_errors的参数一直在持续增长。这说明网卡内部FIFO或者Ring Buffer发生过溢出有数据包在还没进入协议栈之前就被硬件丢弃了。第三步确认Ring Buffer大小。ethtool -g 显示当前RX Ring大小是256而当时这台机器上的业务流量峰值已经把队列冲爆了。CPU把包从Ring Buffer取走的速度赶不上网卡把包塞进来的速度。第四步调整Ring Buffer。ethtool -G 把RX Ring从256调到4096。为什么调大有效因为Ring Buffer实际上是一块网卡和驱动共享的内存描述符队列调大之后相当于给网卡到CPU之间加了更长的缓冲带短时间的流量尖峰不会被直接丢包。第五步观察效果。调整后rx_missed_errors基本恒定延迟恢复正常。当然我不建议一上来就无脑调大Ring Buffer。如果CPU处理能力本身就不足调大Ring只是把包堆积延后并且消耗更多内存根本问题并没有解决。5.2 两类被隐瞒的丢包如果你只盯着ifconfig就错了网卡丢包问题最坑人的地方不是丢包本身而是丢包了你看不出来。很多人排查丢包第一反应是看ifconfig。输入命令后看到RX dropped为0就觉得网卡没问题。但你要知道ifconfig和netstat -i里的dropped计数统计的是协议栈层面的丢弃——比如IP层发现目的地址不是本机、ARP处理失败、内存分配失败的包。而网卡硬件层面因为Ring满了丢掉的包很多网卡驱动并不会同步到这个计数里给你看到的只是ethtool -S里那些带missed、over、fifo字眼的计数器。所以我的经验是不要只用ifconfig判断网卡是否丢包必须结合ethtool -S的数据。下面这张表可以帮你快速定位丢包方向计数器或现象可能原因优先排查方向rx_crc_errors / rx_fcs_errors 增大物理链路问题电缆或光模块故障换线、换光模块、检查协商速率rx_missed_errors / rx_no_buffer 增大网卡Ring Buffer过小或溢出调大ethtool -G的rx参数RX-DRP增高netstat -i协议栈处理缓慢或畸形包检查内核dmesg、防火墙规则、nf_conntrack表tx_dropped增高发送队列拥堵或流量控制检查Ring Buffer的TX方向、流量整形配置单核softirq占用100%多队列/中断绑定未生效ethtool -L启用多队列绑定中断到多个CPUdmesg出现nf_conntrack: table full连接跟踪表满新连接被丢弃调大nf_conntrack_max或者清理无效连接5.3 用两端抓包稳住问题的证据链计数器的证据能缩小范围但要最终确认丢包到底发生在哪一段我强烈建议在两端同时抓包。具体操作是这样的假设客户端访问服务器超时。在服务器的网卡上抓包同时也在客户端出口抓包。如果客户端的TCP栈已经发出了SYN包但服务器端抓不到这个SYN说明包在中间链路丢了或者被中间设备过滤了。如果服务器抓到了SYN但在服务器上却从未发出SYN-ACK说明问题出在服务器的协议栈处理上可能性包括半连接队列满了、防火墙drop规则拦截了入站连接、应用进程根本没有listen。另一种常见情况服务器把SYN-ACK发出去了但客户端收不到。这时候要在客户端抓包判断是不是客户端防火墙把回包拦了或者是NAT映射异常导致回包被转给了错误的内网主机。可以说一次完整的网络排障本质上是沿着数据包的足迹逐层验证。从DHCP拿到的地址是不是正确到路由路径对不对再到网卡收包有没有损耗每走一步都是在用证据接近真相。我在实际工作时有个习惯拿到一台新服务器第一件事就是把网卡的基准计数器、Ring Buffer大小、多队列配置、关键内核网络参数记录下来。这样等出问题时我可以第一时间对比哪些指标偏离了基线而无须现查历史。这个习惯帮我省了很多半夜排查的时间。也建议你从今天开始做个网络基线台账哪怕只是一张表格出问题时你真的会感谢当时的自己。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑