ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux性能排查实战手册:CPU、内存、IO、网络四维故障定位指南

Linux性能排查实战手册:CPU、内存、IO、网络四维故障定位指南 Linux 服务器出问题的时候最怕的不是问题本身是不知道怎么下手。CPU 飙升、内存吃紧、磁盘 IO 卡成狗、网络连接一堆超时每一件都够运维喝一壶的。这些年我排查过不少生产环境的问题最大的体会是性能排查不是靠某一个神仙命令而是靠一套从现象到根因的思维方法。这篇东西就是围绕 CPU、内存、IO、网络四个维度把我平时实际在用的命令、判断逻辑和踩坑经验整理成一份能直接照着操作的手册。文章里不会讲太多纸上谈兵的理论重点放在“现场怎么查、数据怎么读、问题怎么定位”上。适合刚接手服务器运维的初级工程师也适合那些已经会敲几个命令但遇到复杂故障还是发怵的朋友。每一段我都会配上实际输出的解读和判断依据你完全可以把它当成工作台旁边的速查参考。1. 排查前的准备先理顺思路再敲命令很多人一上来就敲top看到 CPU 100% 就开始找进程找到进程就开始 kill结果问题反复出现。这不是命令的问题是思路的问题。性能排查首先要搞清楚三件事现象是什么、影响范围多大、期望的恢复手段是什么。1.1 四步走的排查流程现象、量化、定位、验证我习惯把整个排查过程拆成四个阶段顺序基本不能乱。第一步是观察现象。这一步只做记录不做任何变更。比如“应用响应变慢”“页面加载超时”“数据库连接池被打满”这些是现象描述注意不要在这个过程中加入主观猜测比如“可能被攻击了”“可能是慢查询”猜测会干扰后面的判断。第二步是量化问题。把模糊的“卡”“慢”“打不开”转成具体数字。CPU 使用率是多少、内存还剩多少、磁盘 util 是否跑满、网络重传率是多少。没有数字支撑的排障等于盲人摸象这也是我一直强调必须先做量化的原因。第三步是定位根因。根据量化的结果把排查范围一层层缩小。比如 CPU 高缩小到是用户态高还是内核态高用户态高再用pidstat或perf缩小到具体的进程和函数进程找到了再看它的调用栈和日志。这是一个漏斗结构每一层都有相应的命令和判断标准。第四步是验证恢复。做了调整之后重新观察第一步里的现象是否消失同时确认没有引入新问题。比如你清了 cache内存是释放了但如果应用的读写性能因此下降这就不是一个合格的变更。1.2 工具选型的两个原则全局优先先看系统再看进程Linux 下的排查工具非常多top、free、iostat、netstat、ss、tcpdump、perf、strace每一类都能讲一大篇。但真到现场我会遵循两个原则来选工具。原则一先看全局再看局部。不要一上来就盯进程先看整个系统的水位。top看整体负载vmstat看 CPU/内存/IO 的综合状况iostat看磁盘整体利用率sar看历史趋势。全局数据能帮你建立坐标系知道瓶颈到底在哪一层。原则二能看内核态别只看用户态。很多问题表面上是进程行为内核里可能完全是另一回事。比如进程卡住用户态毫无输出但/proc/pid/status里的状态是 D不可中断睡眠说明它在等 IO 完成这时候你去看进程日志永远查不出来。1.3 建立基线没有基线的排查没有意义基线这个词听着像大厂方法论其实特别实际。你得知道你系统正常情况下 CPU 负载是 1 还是 10内存占用是 30% 还是 80%磁盘 util 是 5% 还是 60%。同一台机器同样的指标在不同的业务场景下含义完全不同。我有一个习惯新机器上线后跑一周sar把各项核心指标记录下来存成文件。不用专门搭监控系统sar -o加 cron 就够了。后面排查时打开历史数据一看就能快速判断现在的异常是“突然升高”还是“长期缓慢爬升”这两个问题的方向完全不同。没有基线就永远只能凭感觉做判断这是排障中最容易翻车的一环。2. CPU 维度从 load average 到上下文切换CPU 排查是所有性能问题的重灾区。一方面 CPU 指标直观谁都会看另一方面CPU 的隐藏信息非常多同一个“CPU 高”背后可能有完全不同的故事。2.1 先分清 load average 和 CPU 使用率很多人把 load average 当成 CPU 使用率这是新手最常见的一个误解。load average 是运行队列中处于可运行状态和不可中断状态的进程平均数量它包含等待 CPU 的进程也包含等待 IO 的进程。而 CPU 使用率是 CPU 处于非空闲状态的时间比例两者并不完全对应。看一个实际例子uptime输出$ uptime 14:32:11 up 23 days, 4:21, 2 users, load average: 8.12, 6.54, 3.20load average 的三个数字分别对应 1 分钟、5 分钟、15 分钟的平均负载。如果 1 分钟的值显著高于 15 分钟说明是最近才突然升高的如果三个值差不多说明系统已经持续高负载一段时间了。但注意不能只看这个数字本身还要结合 CPU 核数来判断。8 核的机器 load 8 和 2 核的机器 load 8 完全是两个概念。判断 CPU 是否真的是瓶颈用vmstat看r列运行队列和b列阻塞进程数$ vmstat 1 5 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 6 0 0 812456 2048 3289476 0 0 0 26 2567 48900 34 12 54 0 0r持续大于 CPU 核数意味着 CPU 确实不够用了如果r不大但wa等待 IO很高那 CPU 空闲但进程在等磁盘问题在 IO 层加 CPU 核心数根本没有用。2.2 top、mpstat、pidstat 组合定位 CPU 飙升定位 CPU 飙升的进程top是最快的入口$ top -bn1 | head -20 top - 14:35:22 up 23 days, 4:24, 2 users, load average: 8.12, 6.54, 3.20 Tasks: 356 total, 2 running, 354 sleeping, 0 stopped, 0 zombie %Cpu(s): 34.2 us, 12.3 sy, 0.0 ni, 52.8 id, 0.7 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 16314344 total, 812456 free, 1234568 used, 14265320 buff/cache PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND 8301 work 20 0 12.456g 2.156g 14856 S 156.3 13.2 234:42.12 java 1024 root 20 0 321456 78564 2236 S 12.6 0.5 12:02.33 dockerd这里有一个判断要点%CPU超过 100 说明进程用了多核TIME是累计 CPU 时间。如果累计时间很高但当前 %CPU 不高说明它历史上消耗了大量 CPU如果当前 %CPU 高且 TIME 也在快速增长那就是现场问题。top是整机视角要确认某进程具体在哪些 CPU 核上运行、是不是存在 CPU 绑核失衡用mpstat -P ALL 1看每个核的独立使用率。生产环境经常会出现“整机 CPU 不高但某个核跑满”的情况比如网卡多队列中断绑定不均、某些线程密集调度到同一个核上这种情况只看整机数据根本发现不了。定位到具体进程后还有一层需要继续深挖这个进程到底在干什么。pidstat -p PID 1按进程输出 CPU 占用和时间片分布pidstat -p PID -t 1进一步细化到线程级。Java 应用线程打满了就要用jstack导线程栈C/C 应用可以直接用perf top -p PID看热点函数。2.3 上下文切换高一个容易被忽略的 CPU 杀手CPU 使用率不高但系统响应慢这种情况十次里有八次是上下文切换惹的祸。上下文切换包括进程切换、线程切换和中断处理每一次切换都有成本切换频率过高会把 CPU 时间消耗在“换人”而不是“干活”上。用vmstat的cs列context switch和in列interrupt来观察。我处理过一个实际案例某服务每隔几秒就出现一次明显卡顿top看 CPU 使用率不到 20%但vmstat里cs高达 30 万以上。进一步用pidstat -w 1查看到底是哪个进程在触发切换发现是一个使用 epoll 的事件驱动框架因为超时参数设置不合理导致大量短连接反复唤醒上下文切换被拉爆。修改超时策略后卡顿立即消失。查看每个进程的上下文切换量$ pidstat -w -p 8301 1 Linux 5.4.0-26-generic (hostname) 07/12/2025 _x86_64_ (8 CPU) 14:36:20 PID Cswch/s nvcswch/s Command 14:36:21 8301 125.00 1890.00 javaCswch/s是自愿切换比如等待 IO、锁nvcswch/s是非自愿切换时间片耗尽被抢占。非自愿切换占比高往往是线程数太多或线程频繁争抢 CPU自愿切换高可能是锁竞争或 IO 等待。两类问题处理方式完全不同锁竞争要看代码线程太多就要考虑协程化或者调线程池大小。2.4 高负载低 CPU 的一个排障实录有一年我们线上某个 Redis 集群节点出现诡异现象客户端超时频发但top显示 CPU 使用率只有 15%load average 却到了 20 多。我的第一反应不是 CPU 不够而是有进程卡在 IO 上了。用vmstat 1一看wa列确实不高但是b列也就是阻塞进程数持续有 5-8 个。再逐个排查进程状态发现有个备份脚本对 Redis 的数据目录做了全量tar把磁盘带宽占满了Redis 的持久化子进程在等磁盘写入导致主进程阻塞。CPU 完全闲着load average 却降不下来因为 load 统计了不可中断睡眠状态D 状态的进程。这个案例里有两条经验值得记住一是 load 高不一定是 CPU 问题二是看到 load 高先看一眼vmstat的b列和/proc/loadavg里的 running 与 blocked 状态。我在生产环境设过一个约定load 高时先跑vmstat 1 3r列高才是 CPU 问题b列高优先查磁盘和网络。3. 内存维度不是只有 free 那一行数字内存问题比 CPU 隐蔽得多。CPU 问题一般是“看得见”的跑满就是跑满内存问题经常是“温水煮青蛙”今天涨一点明天涨一点等告警响了进程已经被 OOM Killer 杀掉了。内存排查的关键是把每一块内存的用途搞清楚。3.1 free 输出全解读buff/cache 需要紧张吗看内存第一眼当然是free -h$ free -h total used free shared buff/cache available Mem: 15Gi 1.1Gi 12Gi 21Mi 1.9Gi 13Gi Swap: 2.0Gi 0B 2.0Gi这里最容易引起恐慌的就是 buff/cache 偏高很多新手看到内存被 cache 占了一大半就急着清。我在这里明确说一个原则cache 不是坏事而是 Linux 内核在用空闲内存做磁盘缓存目的是提升读写性能。判断内存是否真的吃紧要看available这一列它才是“在不触发 swap 的情况下还能分配给新进程的内存估算值”。如果available持续很低或者内存耗尽swap 被大量写入那就需要排查了。先看一眼 swap 的使用情况si、so两列持续有值说明系统正在频繁换页性能通常已经受损。Linux 下的 swap 和 Windows 下的虚拟内存不完全一样不等于废物机制但当它频繁活动时说明物理内存已经不够用了。3.2 连接状态超时在虚拟机里的实际表现我补充一个常见细节云服务器或者虚拟机里执行free时total通常比买来的规格少一些这是内核保留了一部分内存用于启动参数和硬件映射。不要拿这个“损失”去开工单属于正常现象。3.3 定位内存消耗top、smem、/proc 不能只看 REStop里的RES常驻内存是最常看的内存指标但它有一个陷阱它不包含共享内存里属于该进程的部分也不反映进程实际申请了多少内存。一个进程的 RES 可能只有 500M但加上共享库和共享内存后实际占用可能超过 1G。排查内存使用比较靠谱的两条路第一条是smem它会按 USS、PSS、RSS 三个维度输出内存占用。USS 是进程独占的内存PSS 是按进程数量均摊共享内存后的值。看谁是真正的内存大户用 PSS 排序比用 RES 更公平$ smem -t -k -s pss | head -20 PID User Command Swap USS PSS RSS 8301 work java 0B 1.456g 1.512g 2.156g第二条是直接查/proc。进程泄漏不泄漏盯smaps_rollup里的 Rss 变化趋势最直观它把整个进程内存映射汇总了$ cat /proc/8301/smaps_rollup Rss: 2211840 kB Pss: 1589248 kB Shared_Clean: 15234 kB Shared_Dirty: 652718 kB Private_Clean: 10248 kB Private_Dirty: 1545640 kB连续采样几次如果Private_Dirty和Rss只涨不降基本可以确认内存泄漏。再往细了挖可以看cat /proc/8301/smaps | grep -A 20 heap确认是否堆区增长或者pmap -x 8301看具体映射段。Java 应用还要结合jstat -gcutil PID 1000看 GC 后的堆占用确认是堆内泄漏还是堆外直接内存泄漏。3.4 内存回收、OOM 与 cgroup 限制的坑很多开发对 Linux 内存回收机制不了解一看到内存用得多就想赶紧清 cache$ sync echo 3 /proc/sys/vm/drop_caches这条命令在生产环境我基本不用。drop_caches 清的是 page cache如果系统正在跑大量文件读写清了 cache 不仅不能解决问题还会让后续读写直接落到磁盘上IO 性能反而恶化。更重要的是它是临时手段不解决任何根因。内存真正耗尽时内核会启动 OOM Killer。这时候第一件事不是骂内核而是看日志定位为什么耗尽了$ dmesg -T | grep -i oom日志里会记录被杀的进程、当时的进程列表、各进程占用的内存。如果你有特别重要的进程不想被杀可以调它的oom_score_adj比如 MySQL$ echo -500 /proc/$(pidof mysqld)/oom_score_adj但这里有个更隐蔽的坑现在的容器环境大多有 cgroup 内存限制进程看整机内存还有富余但 cgroup 内内存已经达到上限容器会被直接杀掉。排查这种问题不能只看整机的 free还要查 cgroup 的统计$ cat /sys/fs/cgroup/memory/memory.usage_in_bytes $ cat /sys/fs/cgroup/memory/memory.limit_in_bytes如果是 cgroup v2 路径对应文件是/sys/fs/cgroup/memory.current和/sys/fs/cgroup/memory.max。在容器里做内存排查第一步永远是先确认限制在哪里否则你的排查方向大概率是错的。3.5 内存排查经验swap 的罪与罚swap 配置这个事我在生产环境踩过很深的一次坑。当时一台机器物理内存 64Gswap 配了 8G某天应用突然开始剧烈抖动响应时间从 10ms 飙升到 2 秒。查下来发现 swappiness 被设成了 60内核在内存还剩 30% 的时候就开始积极换页。频繁的页换入换出把磁盘 IO 打满整机性能被拖垮。后续我把核心业务服务器的 swappiness 调低到 10同时把 swap 移到 SSD 上但这个场景本身说明了一点swap 不是越大越好也不是不用最好它承担的是“内存溢出时避免进程被杀”的兜底角色。在内存充裕且对性能敏感的应用上宁可让 swappiness 尽量低也不要让内核积极换页。如果你用的是云服务器一些厂商的默认镜像会把 swappiness 调成偏高建议部署后第一时间检查/proc/sys/vm/swappiness。4. IO 维度iowait 高不代表磁盘坏了IO 排查是四个维度里最容易被误判的。原因很简单IO 链路太长从应用程序到磁盘读写的完整路径里任何一环都能变成瓶颈。你以为的“磁盘慢”可能是文件系统锁问题可能是硬件故障也可能是磁盘其实很快但队列太长。4.1 学会看 iostat%util 的真正含义iostat是 IO 排查的核心工具$ iostat -x 1 5 Linux 5.4.0-26-generic (hostname) 07/12/2025 _x86_64_ (8 CPU) avg-cpu: %user %nice %system %iowait %steal %idle 5.23 0.00 1.02 42.34 0.00 51.41 Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz %util nvme0n1 112.4 185.2 3812.4 51234.5 0.0 18.2 0.00 8.94 1.25 2.48 0.56 33.9 276.8 61.80这里有几个指标非常容易误读%util被很多人当成“磁盘利用率”其实它的准确定义是采样周期内磁盘设备有请求未完成的时间百分比这个值高不代表磁盘“满”了。举个生活化的例子一条高速公路在某个时段源源不断有车通过通行能力并没有达到上限但基于“时间百分比”的算法会认为这条路一直忙。对于 SSD 和 NVMe只要队列不太深100% util 也未必是瓶颈机械硬盘反而要重视这个值。真正判断磁盘是否到瓶颈要看aqu-sz平均队列长度和r_await/w_await读写响应时间。如果 await 很低毫秒级util 高说明并发处理良好如果 await 高且队列深说明磁盘确实在排队。还有个细节经常被忽略rrqm/s和wrqm/s是磁盘调度器合并的请求数量。有时候你会发现r/s不高但wrqm/s很高说明 IO 已经被合并了这通常是好事但极端情况下合并频率太高会拉高 CPU 中断开销需要结合vmstat的in列判断。4.2 定位到具体进程iotop 和 pidstatiostat看到的是磁盘视角只知道整个磁盘的 IO 情况但不知道是哪个进程消耗的。这时候用iotop$ iotop -bk -d 1 -n 5 Total DISK READ : 0.00 B/s | Total DISK WRITE: 2.48 M/s Current DISK READ: 0.00 B/s | Current DISK WRITE: 1.23 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO COMMAND 5201 be/4 mysql 0.00 B/s 1.82 M/s 0.00 % 12.30 % mysqldIO列是进程在等待 IO 完成的时间百分比这个值越高说明进程越在等磁盘。注意iotop需要 root 权限而且在 IO 压力极大的机器上iotop本身的开销会比较大不建议常驻运行。如果iotop没有定位到明显的 IO 大户但磁盘 util 依然很高要怀疑是不是 writeback 内核线程在刷脏页。用pidstat -d 1看一下$ pidstat -d 1 Linux 5.4.0-26-generic (hostname) 07/12/2025 _x86_64_ (8 CPU) 14:40:32 PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command 14:40:33 245 0.00 36842.00 0.00 112 kworker/u8:3-flush-253:0kB_ccwr/s是取消写入的量iodelay是 IO 延迟这两个值一起看能判断内核 writeback 是不是在大量刷盘。如果出现这种情况通常是脏页比例阈值到了可以临时调高/proc/sys/vm/dirty_background_ratio但根因往往还是业务写入量太大。4.3 IO 慢的隐藏原因文件系统、锁、双写与硬件磁盘硬件本身没问题、iostat 数值也不高但应用还是慢这种情况有不少。我的经验里以下几个原因出现的频率最高。第一个原因是文件系统的元数据操作。比如 ext4 的小文件大量创建删除目录项dentry和 inode 的分配会成为瓶颈。用strace -c -p PID统计系统调用如果看到大量的openat、unlinkat、creat调用基本就是小文件场景的文件系统元数据开销。第二个原因是应用层的锁竞争。数据库场景里行锁、表锁、间隙锁在并发高时会表现成 IO 等待。看到 iostat 的 await 不高但iosdiag或者应用日志里充满了锁等待超时这不属于磁盘问题去查慢日志和锁监控。第三个原因是主从/lvm 层级的双写放大。比如一块盘通过 LVM2 mirror 做镜像或者某些云盘写策略导致一次写入在底层变成多次物理写iostat 里 r/s w/s 明明不高但物理盘已经热到烫手。这种情况下要对比业务层的 IO 量和设备层的 IO 量差距大就是有写放大。第四个原因是硬件层面的校验。很多企业用的磁盘阵列卡带有写缓存配置里如果关闭了 write-back 只开 write-through写入性能会腰斩。这种问题用iostat看不出端倪只能核对阵列卡配置和历史性能基线。4.4 一个 iowait 不高但卡死的实际案例之前帮朋友排查过一套 Kafka 集群的写入延迟问题。现象是生产者端持续报超时但iostat -x出来磁盘 util 只有 30%iowait 也不高。第一反应是网络问题但网络指标也正常。后来用blktrace去抓块设备层的事件$ blktrace -d /dev/nvme0n1 -w 10 $ blkparse -i nvme0n1.blktrace.0 | tail -100过程中发现大量的D型事件即请求被延迟处理解释出来是上层文件系统在等待日志提交。再往上层看Kafka 的 log segment 每次 fsync 都触发了底层小文件的大量元数据操作。进一步定位到是页缓存淘汰过快导致每次 fsync 都得等脏页刷完才能返回。把 dirty_ratio 和 dirty_expire_centisecs 调回合理范围并把 Kafka 的 flush 参数从 1 改成 100ms问题才彻底解决。这个案例教育我一件事磁盘性能下降了不能只盯着块设备的指标文件系统层和应用 fsync 策略对 IO 延迟的影响往往更大。4.5 inode 耗尽等其他“假 IO 故障”IO 故障里有一种相对少见但一旦遇到就很棘手的磁盘空间还有inode 却用完了。特别是大量小文件的场景比如消息队列积压、Java 应用日志未轮转都很容易把 inode 刷光。用df -i查看$ df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/vda1 6553600 6543289 10311 99% /IUse% 达到 100% 时即使磁盘有空余任何创建新文件的操作都会报错日志也可能只显示 “No space left on device”。排查时第一反应往往去查磁盘空间结果空间明明够用容易绕弯路。顺手练成习惯排查文件写入类问题先df -h和df -i一起跑。5. 网络维度抓包永远比看监控接近真相网络排查是四个维度里最“虚”的一个。CPU、内存、IO 都能在单机上看到网络问题往往牵扯两端中间还隔着一堆路由器和交换机。但也不是完全没有方法只要按照“容量 → 异常 - 数据包”的路径走大多数网络问题一两轮就能找到线索。5.1 先看流量水位sar、ss、iftop网络排查第一步看吞吐和连接数。sar -n DEV 1 5每秒输出每个网卡的收发包数和吞吐量$ sar -n DEV 1 5 12:00:01 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil 12:00:02 eth0 12520.00 13450.00 15240.00 16892.00 0.00 0.00 0.00 1.80关注带宽利用率和 PPS每秒包数。小包场景特别容易让 CPU 的中断处理成为瓶颈这时候网卡吞吐看着只有几百兆但 PPS 已经几十万了。如果单队列网卡没有开启 RPSReceive Packet Steering可以开启/proc/sys/net/core/rps_sock_flow_entries和多队列的rps_cpus来分散到多核但这是另一个话题。连接数用ss比netstat更高效特别是连接数多的时候netstat会明显卡顿$ ss -s Total: 1832 (kernel 2843) TCP: 542 (estab 189, closed 321, orphaned 0, synrecv 0, timewait 32), ports 0$ ss -ant | awk {print $6} | sort | uniq -c统计各状态的连接数重点关注 SYN_SENT、SYN_RECV、TIME_WAIT。如果 TIME_WAIT 特别多可以通过调 net.ipv4.tcp_tw_reuse 减少影响但不建议在生产环境盲目开 tcp_tw_recycle它在 NAT 环境下会造成大量连接被误杀。 iftop 适合看实时流量来源 bash $ iftop -i eth0 -n -B它能显示每个 IP 对之间的流量大小排查“谁在占带宽”非常直观。跟 iotop 一样iftop需要 root 且本身占用有一点不是必须常驻的工具。5.2 连接建立慢TCP 重传、握手超时、连接队列溢出连接建立慢的排查第一步看 TCP 握手状态。ss -tnlp | grep :8080看当前端口的连接状态如果出现大量 SYN_RECV通常是服务端 accept 队列满了也就是半连接队列溢出。可以用netstat -s | grep -i drop看是不是有 SYN cookie 或者丢包计数在涨。第二步查重传。TCP 重传意味着链路不稳或者接收端处理不过来。ss -ti能看到当前连接的重传次数$ ss -ti | head -5 State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 10.0.0.5:8080 10.0.0.8:39420 skmem:(r0,rb131070,t0,tb87040,f0,w0,o0,bl0,d0) cubic rto:204 rtt:1.229/0.718 ato:40 mss:1448 cwnd:20 ssthresh:14找到客户端口和服务端口。2. 清空宿主机的流量统计找个干净的统计起点。3. 执行正常请求如果观察统计中segments retransmited每秒都在涨说明链路确实存在丢包。4. 再配合两端主机的sar -n EDEV看是否有网卡错误计数。rtt是当前往返时延cwnd是拥塞窗口。如果cwnd很小而且持续小说明 TCP 拥塞控制一直在保守状态有可能经历了严重的重传或丢包后还没有恢复。rto是重传超时正常在小网络里应该是个位数毫秒级别如果看到几百甚至上千链路状况就不会太好。第三步如果觉得某个连接确实有问题直接tcpdump抓包看握手过程$ tcpdump -i eth0 tcp port 8080 -nn -c 10抓包重点看 SYN、SYN-ACK、ACK 三个包的往返时间。如果 SYN 发出去了ACK 始终不回来那就是中间链路或对端的问题如果 SYN 一直重传但无人应答检查防火墙或者安全组是不是把源 IP 拉黑了。5.3 TCP 重传与乱序的排查重传是网络问题里出现频率最高的关键词也是最容易被误诊的。碰到重传先把“丢包”和“乱序”分开。乱序会导致接收方认为丢包然后请求重传但其实数据都在路上只是到达顺序不对。判断标准用tcpdump抓包如果发现相同 TCP 序号出现两次且第二次到达时距离第一次非常短大概率是乱序而不是真实丢包。真实丢包的特征是等重传超时RTO到了才重传。翻开一根链路重传率高的时候我习惯性看两端 CPU 有没有软中断跑满、缓冲区有没有溢出。网络问题不一定真是网络问题有时候是接收端网卡队列溢出导致丢包。ethtool -S eth0 | grep drop能看到 rx_dropped、rx_missed这些指标是网卡层丢包的直接证据。5.4 网络排查手记一次连接超时排查的完整路径最后分享一个我印象深刻的现场。客户反馈我们的服务接口偶发超时每次持续几秒钟就恢复。整机 CPU、内存、IO 都没问题网络流量也不大但就是偶发超时。先用ping -f大包打对端没有明显丢包。再抓包发现有个明显规律超时的请求总是发生在 TCP 连接的初始握手阶段。用netstat -s对比各状态计数后发现listen queue overflow的次数在持续上涨。再查应用层服务端用的是 Java 的阻塞 IO 模型默认 back log 设置得比较低而在某个时间段因为下游数据库慢请求处理速度跟不上accept 队列瞬间被打满新连接只能放在半连接队列里排队排队超过超时时间就直接握手超时。这个案例的根因其实有两层一是应用处理线程池在必要时刻被数据库拖慢二是 TCP backlog 太小。处理方式是给应用层连接池和数据库连接池设置了合理的超时隔离同时把 listen backlog 从 50 调到 512。一套组合拳下来超时消失。经验就是网络问题的表象往往在 TCP 层面根因却在更上层的应用。抓包只能帮你定位到“握手超时”但为什么握手会超时要回到应用层找答案。6. 四维排障速查表与常用组合命令到这儿四个维度都过了一遍我整理一个速查表方便你现场用。表里面的工具和命令不是按“全不全”列的是按“现场够不够用”列的。每一条对应一个症状看完直接抄作业。维度典型症状第一梯队命令第二梯队命令关键判断指标CPU负载高、响应慢top、vmstatmpstat、pidstat、perf、jstackr列 vs 核数、cs列、%CPU超核数内存缓慢变慢、被 OOM 杀free、topsmem、smaps_rollup、jstat、dmesgavailable、si/so、cgroup 限额IO异步任务慢、数据库卡iostat -x、iotoppidstat -d、strace、blktrace、df -ir_await/w_await、aqu-sz、inode 使用率网络连接超时、传输慢ss、sar -n DEViftop、tcpdump、ethtool、netstat -sSYN_RECV 堆积、重传次数、rx_dropped 计数一个比较省事的组合排查流程我在应急时经常用# 一分钟内快速摸底四维状态 uptime free -h vmstat 1 3 iostat -x 1 3 ss -s dmesg -T | tail -50这一串命令跑下来CPU 负载、内存水位、磁盘吞吐、网络连接状态、内核报错全都有了足够支持下一轮的深入排查。如果你要临时持续监控用sar -o /tmp/sar_$(date %F).log 1 10把采样数据落盘后面可以用sar -f打开复盘这一招在事后分析“故障到底从什么时候开始”的时候非常好用。结尾我在实际排查中还有一个习惯也当作最后的小技巧分享给你处理任何性能问题都先把dmesg -T | tail -100过一遍再开始用各种工具。内核在发生 OOM、IO 错误、软锁死、CPU 异常时会往这里写日志很多时候答案其实就摆在第一屏只不过大家习惯往复杂的方向想。性能排查说到底就是一个不断缩小范围的过程从“整机水位高”到“某个进程异常”再到“某次调用超时”每一层都需要一个准确的判断标准。希望这份手册能让你在下次面对告警时少一点慌张多一点思路。毕竟系统不会骗人骗人的永远是没读懂的指标。
返回列表