网络与IO问题排查实战:从现象到根因的完整指南
2026/9/16 7:15:59 网站建设 项目流程

写网络和IO问题排查这块,我一直觉得是整个运维和开发工作里最考验综合功底的环节。很多时候业务出问题,表面上是网络不通,实际上可能是IO卡死或者服务端处理不过来;反过来也成立。遇到这种场景,要是不分清楚问题的边界,上来就一顿抓瞎,很容易排查一整天毫无进展。所以我更愿意把这一章当作一套实战手册来讲,而不是堆概念。适合谁看呢?后端开发、运维工程师、嵌入式或硬件调试的同学,甚至自己电脑联网出点小毛病想弄明白原因的普通用户,都能从中找到可操作的思路。

1. 先想清楚:到底是网络问题,还是IO问题

1.1 两类问题的本质区别

网络问题,指的是数据在网络上传输时出了问题,比如连接建立不了、延迟高、丢包、对端突然断连等等。IO问题则更偏向本机或设备内部的处理能力,包括磁盘读写、内存换页、网卡收发包、文件系统等待等。两者最大的区别在于:网络问题是“两点之间”的问题,IO问题是“单点内部”的问题。

但实际排查过程中两者经常会交织在一起。比如某个服务查询很慢,你第一反应是网络慢,结果排查了一通,发现是磁盘IO接近瓶颈,所有请求都卡在等数据库返回数据,而数据库的慢是因为磁盘在读日志时排队。反过来,网络出现问题也可能诱发IO异常,比如大量无效重传会让网卡中断频繁,导致CPU软中断占用过高。所以动手之前,先确认问题究竟属于哪一类,能省掉大量无用功。

1.2 从现象倒推原因的通用思路

我个人的习惯是分三步走:

  1. 先复现或收集现象。包括报错信息、持续时间、影响范围、是否偶发等。
  2. 缩小范围。从客户端到服务端逐段确认,网络通不通、端口通不通、协议是否正确、应用层是否有响应。
  3. 抓关键数据。用抓包工具或监控命令抓取当时的真实流量和系统状态,结合日志定位根因。

不要一上来就怀疑代码、怀疑硬件、怀疑内核参数。先看数据,先看清楚现象,再去推导原因。很多时候排查浪费的时间,都是因为没搞清楚现象就开始猜了。

2. 工具箱:这些命令和工具到底在解决什么问题

2.1 网络层基础命令:从ping到tcpdump

网络排查常用的命令其实就那几类,关键是要知道每个命令适合什么场景:

  • ping:最基础的连通性测试,测试本机到目标IP的链路是否可达,同时初步判断延迟和丢包率。要注意的是ping通不代表应用就通,很多服务对ICMP包做了忽略,所以不要看到ping通就认为网络没问题。
  • traceroute / mtr:查看数据包经过的路径和每一跳的延迟变化。mtr比traceroute更适合排查,因为它会持续检测每一跳的丢包率,能更直观地判断丢包发生在哪一段。
  • telnet / nc:测试TCP端口是否可连接。telnet到目标IP指定端口,如果端口通,会显示连接到对方;如果不通,会超时或直接拒绝。nc(netcat)功能更强,可以测试UDP端口,也可以用来做简单的端口转发。
  • curl / wget:测试HTTP/HTTPS接口,可以指定请求头、POST数据、查看详细响应时间。curl的-w参数能输出连接时间、TLS握手时间、首字节时间等信息,对定位HTTP层问题非常有帮助。
  • tcpdump / Wireshark:抓包分析,看数据包的传输过程,包括三次握手、四次挥手、重传、RST等。Wireshark适合在本地分析pcap文件,tcpdump适合在服务器上抓包。

2.2 应用层与协议层工具

除了网络层,很多问题是出在应用层协议上的,比如HTTP请求超时、WebSocket连接中断、数据库连接池被占满等。这时候需要看应用日志,同时用抓包工具确认TCP或协议层面的交互。

  • ss / netstat:查看系统当前的网络连接状态,确认连接是ESTABLISHED还是TIME_WAIT,端口是否被监听。ss比netstat快很多,推荐优先使用。
  • lsof:查看某个端口由哪个进程占用,或者某个进程打开了哪些文件描述符和网络连接。
  • strace:跟踪进程的系统调用,能看到进程在读取网络数据、磁盘文件时的具体行为和耗时,是定位应用层和IO层问题的利器。
  • perf:系统级性能分析工具,可以分析CPU周期、缓存命中率、锁竞争等。虽然它不是专门的网络排查工具,但在定位软中断过高、锁等待导致IO毛刺时非常有用。

2.3 IO排查工具与关键指标

IO问题的排查相对复杂一点,因为IO不光是磁盘读写,还包括网络IO、内存换页、设备IO等。但大部分情况下我们遇到的IO问题都是磁盘IO或文件系统层面的。

  • iostat:查看磁盘的平均服务时间、等待时间、利用率。重点看%util、await、svctm这几个指标。%util超过80%就要警惕磁盘接近饱和,但也不能完全依赖这个数值,因为RAID或SSD的IO合并能力不同。
  • iotop:实时查看每个进程的磁盘读写速率和IO等待时间,非常适合定位“哪个进程在疯狂读写磁盘”这类问题。
  • df / du / lsof:排查磁盘空间不足、文件被删除但仍占用空间、以及打开文件数过多的情况。
  • dmesg:查看内核日志,能发现磁盘错误、文件系统错误、网络设备异常等。

2.4 别忘了系统基础状态

在排查网络和IO问题时,系统的基础状态往往能提供重要线索。

  • sar:系统活动报告,能看到CPU、内存、IO、网络的历史数据。如果在问题发生时没有实时抓取数据,sar的历史记录就是事后分析的关键。
  • vmstat:查看进程、内存、换页、IO的总体情况。如果wa过高,说明系统大量时间在等待磁盘IO。
  • /proc:Linux的虚拟文件系统,里面包含几乎所有内核运行时数据。比如/proc/net/dev可以看每块网卡的流量统计,/proc/diskstats可以看磁盘IO统计。

3. 网络问题排查:几个高频场景的完整过程

3.1 连接建立失败:先判断是网络不通还是端口不通

这个场景太经典了,以致于很多人一想到网络问题就上来反复ping。但如我前面所说,ping通不代表端口通。实际操作中,排查连接建立失败要按这个顺序来:

  1. 先确认目标IP是否可达。在客户端直接ping目标IP,如果完全丢包,可能是网络线路、防火墙、目标主机宕机等问题。
  2. 再确认目标端口是否有服务在监听。在目标主机上执行ss -lnt确认端口状态,如果端口没监听,就要去看服务进程是否启动、配置的监听地址是否正确。
  3. 如果端口在监听但客户端连不上,就在客户端用telnet测试。telnet不通时,用tcpdump同时抓客户端和服务端的网卡,看SYN包有没有发出、有没有收到SYN-ACK。SYN没发出,是本机防火墙或路由问题;SYN发出但没收到响应,说明包没到对端或被对端防火墙丢掉;收到SYN-ACK但客户端不回ACK,很可能是客户端本身的状态问题。

有一年我处理过一个跨地域的服务连不上的问题,现象是客户端偶发超时,服务端CPU和网络流量都不高。抓包后发现客户端发出了SYN,但对端迟迟不回SYN-ACK,过一会儿直接返回RST。最后定位到是中间防火墙因为连接数限制丢包,导致长时间没响应后自动发RST。这个问题如果不抓包,光靠看CPU和连接数,根本发现不了。

3.2 连接中途断开的真相:从WebSocket报错说起

在热词里有个很典型的报错:stream disconnected before completion: failed to send websocket request: io。这种报错的字面意思是:在发送WebSocket请求时,连接在完成之前就断开了。很多人看到这个报错会以为是代码里的异常处理逻辑有问题,但其实它背后藏着多种可能:

  • 对端主动关闭了连接。可能是服务端因为心跳超时、协议解析出错、空闲连接回收等原因主动断开。一般可以在服务端日志里看到“client closed connection”或“EOF”之类的记录。
  • 中间代理或网关主动断开。比如Nginx的proxy_read_timeout设置太短,客户端还没传输完,代理就认为超时了,然后主动断开TCP连接,客户端就会看到类似“peer closed connection”的错误。
  • 防火墙或负载均衡器因为空闲时间过长断开了连接。很多云环境的网络安全策略会清理长时间无流量的TCP连接,但客户端并不知道,还在等待数据,等到再发包时,对端已经关掉了。
  • 客户端自身IO阻塞导致发送超时。如果客户端的写缓冲满了、上行带宽拥堵,或者CPU被其他任务抢占,也会导致发送超时,表现为IO错误。

排查这个问题的思路是:客户端抓包看发送流程,服务端抓包看接收和断开的过程,定位是哪个方向先发的FIN或RST。如果能看到先发FIN,再对应查找服务端日志中关闭连接的原因;如果看到的是RST,就要看是否有防火墙或系统参数在干预。有次我遇到一个WebSocket每隔几分钟就自动断开,抓包显示的确实是服务端先发了FIN,而服务端日志里没有异常。最后发现是云平台的SLB设置了空闲连接超时,5分钟没有消息就默认断开,需要开启长连接保活或在应用层做心跳。

3.3 延迟高与丢包:用mtr逐跳定位

网络延迟高的排查要区分是物理距离导致的固有延迟,还是路径上的设备故障或拥塞导致的附加延迟。用ping测试只能得到最终结果,很难知道延迟出在哪一跳。这时候用mtr就能看到每一跳的情况。

mtr的输出格式里,每一行代表经过的一个路由节点,可以看到该节点的丢包率和平均延迟。如果某个节点丢包率很高,而同一条路径上它后面的节点反而正常,那通常不是这个节点本身丢包,而是这个节点的ICMP限制策略,不一定是故障。但如果丢包持续存在,并且后面所有节点都跟着丢包,那这个节点很可能就是瓶颈所在。

另外,用mtr排查时要注意,运营商的路由设备优先级一般较低,即使对ping包限速,也不一定代表用户流量会丢包。所以判断要谨慎,不能一看到某个节点丢包就觉得是它的问题,要看它之后的节点表现。还有一个经验:如果只是延迟高但没有丢包,可能是链路拥塞、带宽跑满或者MTU设置不合理导致的分片与重组开销增大。可以尝试调整MTU或检查带宽使用率。

3.4 传输速度上不去:结合网络测速与TCP参数

网络测速大家都不陌生,无论是网页端还是App端测速,原理基本一致:建立多个TCP连接分别下载数据,统计一段时间内的下载量,计算传输速度。如果你在自建服务或服务器上遇到传输速度上不去,除了考虑带宽限制,还需要关注TCP层的因素。

TCP传输速度跟拥塞窗口、接收缓冲、发送缓冲、延迟息息相关。最典型的问题是“带宽时延积”概念:在长肥网络中,如果接收窗口太小,传输速率会被限制在窗口大小除以RTT的数值附近。举个例子,RTT是100ms,接收窗口默认是64KB,那么最大吞吐大约就是64KB/100ms ≈ 6.4Mbps。这显然达不到百兆甚至千兆带宽。解决办法是调整系统的TCP窗口参数,比如Linux下将net.core.rmem_max、net.core.wmem_max调大,并且让TCP自动窗口缩放生效。

另一个常见问题是网卡队列和中断绑定。如果网卡多队列没有开启,或者中断全部集中在一个CPU核上,高流量时会触发软中断瓶颈,表现为CPU使用率不高但网络吞吐上不去。可以用ethtool看网卡队列配置,开启多队列,并把中断irqbalance打开,缓解单核压力。

3.5 网络协议分析:别小看抓包这一步

抓包看起来简单,实际上有不少门道。首次抓包前,建议先确定几个问题:抓哪个网卡、抓多长时间、是否足够大的缓冲区、需要过滤哪些流量。我的习惯是先抓主机的所有流量,用临时文件保存,等复现后停止抓包,再用Wireshark过滤分析,这样最稳妥,避免漏掉关键包。

分析时先关注TCP三次握手、TLS握手、应用层协议交互这几个阶段。如果握手本身就花了很长时间,那问题大概率在网络层或对端处理能力;如果握手很快但应用层响应慢,那问题在应用逻辑或数据库、第三方接口调用上。抓包还可以看到重传、乱序、窗口缩小等现象,这些是网络质量问题的重要信号。

4. IO问题排查:深入到每一个等待

4.1 磁盘IO瓶颈:从iostat看懂读写的真实情况

磁盘IO问题最常见的表现是服务响应变慢,CPU的wa指标升高。但CPU高wa并不一定就是磁盘坏了,也可能是文件系统、RAID重组、或某个进程在刷大量日志。

iostat -x 1的输出里,有几个指标要重点看:

  • %util:设备忙碌的百分比。传统机械盘接近100%说明确实忙不过来,但SSD因为有内部缓冲和高并发能力,%util高也不一定代表性能就到顶,要结合await判断。
  • await:IO请求在队列中等待和服务时间的平均值。如果await很高,说明IO请求排队时间很长,大概率是磁盘或后端存储池满载。
  • svctm(或新版本里的r_await、w_await):设备实际处理一个请求的平均时间。如果svctm很低但await很高,说明不是磁盘本身慢,而是排队太严重。

有一个场景我记得很清楚:某服务每天晚上定时做全量备份,磁盘IO直接在iostat里看到%util接近100%,application日志的写入也跟着变慢,进而导致大批请求超时。这时候的解决思路不一定是要换更快的磁盘,而是考虑错峰备份、限流io、或者把备份目录放到另一个磁盘,避免和业务IO争抢。

4.2 jbd2 IO过高:底层文件系统日志进程的干扰

热词里有一个“jbd2 io过高”,这个是Linux下ext4文件系统的日志守护进程,负责维护文件系统的日志(journal)。正常运行中jbd2的IO占比较低,如果它异常升高,通常意味着文件系统层有大量元数据更新操作,比如大量的小文件创建删除、目录操作、日志模式的配置不当等。

有一个实际的案例:服务器运行docker容器,每天的日志文件很多都在小文件之间频繁创建,导致jbd2持续写入journal,IO负载长期偏高。后来调整了文件系统挂载参数,将data=ordered改成data=writeback,减少日志同步次数,问题缓解了不少。但要注意,这个调整牺牲了一定的崩溃一致性,建议只在能接受该风险的场景使用,并且在修改前一定要备份和评估。

另外,如果你遇到jbd2写IO异常高,还要检查是否频繁出现文件系统错误或磁盘坏道,因为jbd2会在写入数据时触发多次重试,导致IO异常升高。dmesg或journalctl里一般能看到端倪。

4.3 应用层IO阻塞:用strace看清每次系统调用

磁盘和文件系统层面的问题排查完了,如果发现系统层面IO压力不大,但业务还是慢,那问题可能出在应用自身。这时候strace是最直接的武器。

strace -cp 可以汇总进程的系统调用时间和次数,看到哪个系统调用耗时最长。如果想跟踪某个具体的文件操作,可以strace -e trace=file -p 。有一次压缩一个超大目录性能很差,strace发现进程几乎都在调用getdents(遍历目录项),也就是说文件数量巨大导致遍历本身就耗时巨大,而不是压缩算法慢。后来做了目录结构优化,减少单层目录的文件数,问题就明显改善了。

网络IO阻塞也一样。用strace跟踪一个HTTP服务的读写,如果发现read或write调用经常是阻塞很久才返回,说明对端或网络有延迟,也可能是socket的send缓冲满了,需要检测网络连接状态和流量情况。strace本身有开销,生产环境使用要谨慎,有条件的话先在测试环境复现。

4.4 网络IO与异步模型:从BIO到NIO再到io_uring

网络相关的IO问题,很多时候也牵涉到编程模型。传统的BIO(阻塞IO)模式下,每个连接分配一个线程,大量连接时线程上下文切换成了瓶颈。后来又有了NIO(非阻塞IO),配合多路复用器(select、poll、epoll)获得更高的并发能力。Java生态里的Netty、Java NIO,都是基于这套模型。

排查这类问题时,如果发现服务线程数量很多、CPU上下文切换频繁,可以考虑线程模型是不是有问题。可以用perf或者pidstat查看上下文切换次数,如果cswch/s特别高,说明线程调度频繁,很可能是阻塞IO模型扛不住高并发。

在Linux 5.1之后出现的io_uring,把IO性能和异步处理又往前推了一大步。它用共享内存的机制规避了系统调用的开销,特别适合高IOPS场景。在实际项目里,如果遇到传统epoll+read/write模型的性能瓶颈,可以尝试用io_uring等新异步模型做优化。不过io_uring的使用门槛较高,对内核版本也有要求,建议先从代价较小的参数调优和代码逻辑优化做起。

4.5 硬件IO与嵌入式:从高速计数器到FPGA口模式

网络与IO问题不只在服务器和软件层,嵌入式开发中也有大量IO排查需求。热词里的“h5u 高速计数器”还有“FPGA的IO有没有类似ARM的模式”,都属于这个范畴。

PLC领域里的高速计数器(HSC)用于处理高频脉冲信号,如果IO输入频率超出硬件能力,就会出现计数丢步。排查时除了确认输入信号的电压阈值和频率是否在规格范围内,还要关注布线长度和干扰,高频信号走线过长或靠近动力线都会引入噪声。

FPGA的IO可配置模式比ARM MCU更灵活一些,常见的有推挽输出、开漏输出、上拉/下拉输入、差分信号等。在FPGA里,IO模式一般由综合工具或约束文件配置,和ARM在寄存器层面配置的模式类似,但FPGA的优势是IO数量多且时序可编程。如果FPGA驱动外部设备出错,先检查引脚约束是否正确、输出类型是否匹配负载需求、IO电平标准是否一致。开漏输出要特别注意是否加上拉电阻,否则高阻态时信号状态不确定,这种问题在示波器上看起来就是电平漂移,很难直接发现故障点。

5. 常见问题速查与排查经验总结

5.1 问题、症状、排查路径一览

为了查阅方便,我把日常最常遇到的问题整理成一个速查表,给各位当参考:

症状可能原因首选排查命令/工具解决思路
ping通但应用连不上端口未监听、防火墙拦截、服务绑定错误telnet、ss、nc确认端口监听地址,检查防火墙规则
连接建立很慢SYN重传、握手超时、负载高tcpdump抓包、sar分段确认SYN-ACK响应时间,抓包找重传
连接断断续续代理超时、空闲连接过期、防火墙回收mtr、tcpdump、服务端日志调整代理超时,应用层增加心跳保活
传输速率上不去TCP窗口太小、网卡队列不足、带宽限制iperf、ethtool、ss -i调大TCP缓冲,开启网卡多队列
CPU iowait高磁盘排队、日志刷写频繁、备份任务iostat、iotop、pidstat定位高IO进程,错峰或限流
jbd2高频写IO小文件元数据操作频繁、日志模式不合适iostat、strace、dmesg优化文件目录结构,调整日志写模式
应用读文件慢大目录遍历、缓存命中低strace、perf、vmstat优化目录结构,加大缓存

5.2 我踩过的坑和总结的避坑经验

多数网络和IO问题排查到最后,总结下来都是小问题,但耗时的点往往在于方向错。我把自己在这方面的几条经验写出来:

第一条,抓包前务必校准时间。服务器和客户端的时间偏差过大,抓包分析时很容易误判请求顺序和超时逻辑。我的习惯是统一使用NTP同步,抓包时保留时间戳,分析时结合应用日志时间线。

第二条,不要盲目调整内核参数。网上有很多“性能优化建议”,动不动就让你改TCP重传次数、增大socket缓冲区。但这些参数往往是牵一发动全身,改小了可能导致连接不稳定,改大了内存占用又上去了。改之前要弄清楚当前状态的瓶颈在哪个环节,改之后还要用压力测试验证效果。

第三条,IO高不代表磁盘要换。很多磁盘IO升高其实是代码或配置造成的,比如日志框架在每次请求都写一条同步日志、数据库批量更新没有走事务合并、文件系统没有启用合适的缓存策略。换磁盘是最简单的方案,但往往是性价比最低的方案。

第四条,硬件IO问题优先检查接线和电气参数,其次才是程序。在高频脉冲、开漏输出这些场景里,信号质量问题比代码逻辑问题更容易被忽略。示波器量和程序review两个动作要同时做,不要只在代码里查。

5.3 再分享一个建议

如果你在排查网络或IO问题时卡住了,不妨换个角度:把关注点从“哪里出故障”换成“数据流经了哪些环节,每个环节的表现如何”。网络数据从客户端发出,经过网卡、协议栈、内核缓冲、应用层、磁盘等等,一步一个脚印地查,总能找到卡住的那个点。这套思路和动手能力,比记住任何一份命令清单都管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询