资讯动态

Linux性能排查进阶:从top命令到x86/ARM芯片架构底层原理

发布时间:2026/10/17 8:10:45 来源:尧图企业网站定制
这几年带过不少转行的朋友也接过不少“帮我看下这台机器怎么这么卡”的求助。大多数人的第一步是打开终端敲 top看一眼 CPU 占用率然后得出结论“有个进程把 CPU 跑满了”。这个结论不能算错但它基本没有排查价值CPU 高是结果不是原因。top 那一堆数字背后还藏着系统调用、中断、缓存一致性、超线程和 NUMA 这些芯片层面的问题只停在“看占用率”这一层问题根本定位不到根上。如果你正从“背了几十条 Linux 命令”走向“出了问题能定位到内核和芯片层面”这篇内容就是把这件两件事连起来写的。不打算罗列命令手册而是挑高频的 top、vmstat、mpstat、perf、strace 这些命令讲清楚它们输出的字段与 x86、ARM 芯片执行指令的方式有什么对应关系再拆一套完整的性能排查流程给你看。适合有一定基础、想让技能往上走一步的同学。1. 先搞懂命令在“替谁打工”从指令到系统调用1.1 一条命令从终端到 CPU 要走多少步你敲入ls、回车这个过程绝不是“shell 把字符串发给系统”这么简单。第一步是 shell 解析命令行找到可执行文件然后调用execve这个系统调用把当前进程替换成新的程序。这里关键的字眼是系统调用用户态程序想要让内核干活必须通过它。在 x86_64 上用户进程发起系统调用靠的是syscall指令在 ARM64 上则是svc #0。这两条指令会把 CPU 从用户态切换到内核态内核再根据系统调用号去执行对应的处理函数。所有命令最终都会变成一组系统调用然后才有真正的 IO、进程切换、内存分配发生。用strace能看到这个过程strace -c /bin/ls输出的最后一列是 syscall 名称比如execve、openat、read、write、mmap、brk。mmap负责分配内存映射read和write负责读写文件这里面任何一环变慢命令都会变慢但 top 几乎不会告诉你到底是哪一环慢了。这个环节也是“命令”和“芯片”的第一个交叉点。系统调用意味着用户态/内核态切换而切换是有代价的要保存现场、跳转特权级、执行内核代码、再切回用户态。一次、两次无所谓如果进程每秒发起几十万次系统调用sy列就会飙升整台机器的性能肉眼可见地下降。很多新手只盯着us列是因为不知道sy高同样能卡住业务。所以我在带人排查问题时第一件事不是讲命令参数而是先让他们接受一个观点每条命令的输出都是内核基于硬件状态整理出来的“体检报告”。不会看底层的话报告就只是一堆数字。1.2 top 的 CPU 百分比到底读的什么文件top、free、ps这些命令看起来是不同工具其实很大一部分数据源是同一个/proc虚拟文件系统。内核把运行状态以文本形式暴露在这里命令只是做了格式化展示。top第一行的 CPU 使用率核心数据来自/proc/stat第一行cpu开头的记录cat /proc/stat | head -n 1看到的是cpu user nice system idle iowait irq softirq steal guest guest_nice这些字段的累计值。top显示的百分比是两次采样之间这些字段的差值再除以总间隔时间。这也是为什么很多老运维习惯运行top -d 3强制 top 每隔 3 秒刷新一次来采样而不是只看一次瞬时输出。注意top -b -n1一次性输出里看到的 CPU 百分比是自开机以来的平均值不是当前瞬时值。排查突发性能问题必须看两次采样之间的差值。vmstat 1 5、mpstat -P ALL 1 5之所以强制指定采样间隔就是基于这个原理。1.3 三种进程状态决定系统“忙不忙”ps -eo state,pid,cmd的 STATE 列看着是几个字母却是判断负载的关键R可运行状态正排队等待 CPU。S可中断睡眠等事件比如等 IO 完成、等锁。D不可中断睡眠通常卡在内核驱动里等硬件 IO。D 状态是判断“load 高但 CPU 不高”的关键。load average 衡量的是“可运行线程 不可中断线程”的加权平均D 状态的进程也算进去。所以我遇到uptime显示高负载但top里 CPU 空闲时第一条命令就是ps -eo state,uid,pid,cmd | awk $1 ~ /D/ {print $0}如果有大量 D 状态进程重点去查磁盘、网络挂载和内核 IO 路径而不是加 CPU。这个话题留到第 5 部分继续展开这里先留个印象。2. 高频指令实战性能排障三板斧2.1 负载曲线先分清“正在忙”还是“已经忙很久了”uptime输出的三个 load average很多人只记住了“超过核数就不行”实际信息量更大。1 分钟、5 分钟、15 分钟三条曲线描述了负载随时间变化的趋势。曲线关系含义应该做什么load1 远大于 load15负载刚刚冲上来找最近启动的进程、定时任务load1 小于 load15高峰期已过正在回落结合监控确认持续时间与根因三个值都比较高持续过载扩容、限流、优化代码不是临时任务尤其要记住load average 不等于 CPU 使用率。一个进程在等磁盘时状态通常是 D 或 S也会被计入负载。所以你可能会看到“8 核机器 load 到了 16但 CPU 才 20%”的情况这时候定位方向立刻转向 IO。top是一个更好的入口但要有固定读取顺序第一行看负载第三行看 CPU 分布第五行看内存之后再进进程列表排序。很多人一打开就是看进程列表把第一行忽略了顺序一乱思路就容易偏。2.2 内存free 显示“已用”不等于内存紧俏free -h的输出里buff/cache那一列经常被误读为“内存不够用”。其实这是内核把空闲内存拿去做页缓存page cache和文件系统缓存了本质上是可以回收的。遇到内存压力时内核会自己回收到MemAvailable能满足新分配请求为止。所以判断内存够不够看的是available这一列不是free列也不是简单的 total - used。MemAvailable是内核按当前可回收情况估算出的数字更贴近真实可用性。内存压力变大时用vmstat 1 5看si和so两列si每秒从 swap 换入内存的数据量。so每秒从内存换出到 swap 的数据量。只要si、so高频出现非零值说明内存真的吃紧有进程在被频繁换页。更精确的判断可以看/proc/pressure/memory内核需支持 PSI 特性里面some值代表过去一段时间内有进程因等待内存而停滞的时长占比cat /proc/pressure/memory这个文件能直接告诉你“是不是因为内存而在排队”。OOM 场景则通过dmesg -T | grep -i oom查看内核杀掉了哪个进程。这里想提醒一个现象很多系统长期开着大量业务进程内存的used一直在 90% 以上但业务很稳。因为内核页缓存本来就会占满只要available足够就不是问题。真正的内存泄漏往往表现为available持续下降、si频繁出现而不是used高。2.3 CPUuser/sys/wa/irq 分别代表什么top第三行是 CPU 状态的核心缩写不同但原理一致us用户态、sy内核态、waIO 等待、hi硬中断、si软中断、st被宿主机偷走的时间。下面这套判断逻辑要刻在脑子里现象倾向性结论继续看什么us高业务代码在消耗 CPUperf top 看热点函数sy高系统调用、中断、锁频繁strace、pidstat -wwa高IO 子系统成为瓶颈iostat -x、D 状态进程si高软中断处理过多网络场景常见/proc/net/softnet_stat、irqbalancest高虚拟机被宿主机抢占宿主机负载、调整实例规格看 CPU 时别忘了按1键展开每个核。多核环境里整体 30% 使用率可能是“每个核均匀 30%”也可能是“8 个核里 2 个 100%、6 个 0%”。后者往往才是问题的体现中断亲缘性、锁竞争、单线程热点都会让某些核过载而其他核闲着。mpstat -P ALL 1 5把每个核的状态打到屏幕上比 top 更适合做一段时间内的观察mpstat -P ALL 1 5如果某个核的%soft持续很高就去查/proc/softirqs和网卡网络收发路径上软中断只在一个核上处理是很常见的性能杀手。3. 芯片架构视角看命令输出x86 与 ARM 背后的差异3.1 指令级差异同一份代码在不同芯片上执行路径完全不同到这一节才是标题里“芯片架构底层逻辑”的重点。很多人觉得Linux 命令在 x86 和 ARM 上结果不是一样的吗用户可见输出确实一样但perf统计数据背后的执行路径完全不同。x86 是 CISC 风格指令长度不固定从单字节到十几字节都可能出现。现代 x86 处理器为了兼顾兼容性和高性能会把每一条 x86 指令在内部翻译成若干条小的微操作uops再交给乱序执行引擎处理。这个译码前端是 x86 CPU 很关键的瓶颈之一尤其在高 IPC 的密集计算场景。ARM64 的 AArch64 指令集中普通指令固定 4 字节译码比 x86 简单直接因此同等功耗下有更好的能效比这也是它在服务器、嵌入式、移动端大范围铺开的原因。固定长度的代价是指令密度不如可变长指令代码段体积通常比 x86 略大指令 Cache 的压力也不同。对命令输出的直接影响是如果用perf stat比较同一个程序在 x86 和 ARM 机器上的instructions总数两个数大概率差很多。这不能直接说明谁快谁慢。指令数量、Cache Miss 率、分支预测命中率必须和时钟频率、功耗、并行度放在一起看。以 IPC 为例它比单纯的指令数更有对比意义IPC 高说明每个时钟周期完成的有效工作多IPC 低且 cache miss 高说明瓶颈在访存而不是算力。理解了这一点再看perf stat sleep 1的输出就不会只盯着第一行了。3.2 Cache 层级为什么 L1 命中不到 1nsL3 却可能几十 nsCPU 和内存之间隔着多级 Cache。典型的现代处理器结构是核心私有 L1分成指令 L1i 和数据 L1d和 L2然后是多核共享的 L3最后一级缓存。访问延迟上L1 命中大约 1 纳秒量级L2 几纳秒L3 十几到几十纳秒主内存则是几十到上百纳秒。用一个生活化类比L1 是厨师灶台上的调料瓶L2 是厨房柜子里的备用调料L3 是隔壁储物间主内存是 1 公里外的超市。每降一级成本都是数量级的增加。lscpu可以快速查看缓存大小lscpu | grep -E CPU\(s\)|Thread|Core|Socket|L1|L2|L3|NUMAL1d cache、L2 cache、L3 cache就是你评估数据结构是否合适的依据。Cache 的计量单位是 cache linex86 和主流 ARM 都是 64 字节。这意味着即使只修改一个 8 字节变量硬件也需要把整条 64 字节加载到缓存并在被替换时回写。如果多个线程频繁修改落在同一条 cache line 上即使操作的是不同变量也会互相使对方的缓存行失效然后不断从主存重新加载这就是“伪共享”。现象是 CPU 的 us 不高但 perf 里的 cache-misses 很高程序扩展性很差。定位这类问题perf是核心工具。先以固定频率采样perf record -F 99 -g -p pid -- sleep 10 perf report --stdio-F 99是每秒采样 99 次-g记录调用栈报告中能看到热点函数和调用路径。如果热点函数内部 Cache Miss 很高再用事件统计进一步确认perf stat -e task-clock,context-switches,cache-misses,instructions ./your_benchmarkcache-misses与instructions的比值比单一指标更接近“到底是不是 Cache 问题”的答案。3.3 NUMA 和超线程为什么加核不积极甚至加了更慢多路服务器和大型 CPU 普遍采用 NUMA 架构。本质是每个 CPU 自己有内存控制器访问“本地内存”比访问“其他 CPU 的内存”要快。系统用 NUMA node 表达这种距离关系numactl --hardware能看到节点分布numactl --hardware numastatNUMA 场景最典型的坑是程序被调度到 node 0 的核内存却优先分配在 node 1。每一个跨节点访问都要走 CPU 间互联通道延迟明显上升带宽也受限。表现为业务的响应时间抖动大但单看 CPU 占用率并不高。对策是使用亲和性工具把进程和内存绑在同一个节点numactl --cpunodebind0 --membind0 ./your_application或者用taskset把进程固定在指定 CPUtaskset -c 0-3 ./your_application这里要特别说下超线程。一个物理核具备两个逻辑 CPU它们共享 L1/L2 和执行端口。lscpu里能看到Thread(s) per core如果它是 2说明开了超线程。操作系统视角是两个“CPU”芯片物理视角是一个完整核心。超线程的价值在于填满流水线空闲期比如一个线程在等待 Cache Miss 时另一个线程可以用上执行单元。但如果两个逻辑核都在跑密集计算它们会互相争抢执行资源总吞吐并不是单核的两倍。用top看到两个逻辑核都 100%不代表两个物理核都满负荷。容量规划时以物理核数而不是逻辑核数作为起点是经验之谈。3.4 中断处理硬中断、软中断与 CPU 亲缘性排障中另一个容易被忽略的底层因素是中断。网卡收到数据包、磁盘完成 IO、时钟周期到达硬件都要打断 CPU让它停下来处理。中断有硬中断和内核延后执行的软中断softirq之分后者专门处理网络收包、块设备层、定时器等重活。/proc/interrupts能把每个中断号在每个 CPU 上的发生次数列出来watch -n 1 -d cat /proc/interrupts如果大量中断集中在一个 CPU 上比如 CPU0 上堆了几十万次网卡中断这个核就既忙业务又忙中断出现严重的单核瓶颈。软中断分布可以看cat /proc/softirqs看到NET_RX在某几个核上特别高说明网络包处理正在反复打扰这几个核。标准解法是启用irqbalance服务让它按负载自动分散中断如果实时性要求高也可以手动调整/proc/irq/中断号/smp_affinity把网卡中断绑定到空闲核。注意一个细节中断和业务进程如果抢到同一个物理核的超线程性能反而会掉不要让中断和业务共享同一个物理核心。4. 从观测到定位一套可复用的排查组合拳4.1 一次实战风格的排查流程复盘用一个小案例串一遍。假设某内部模拟项目 X 的系统在预发布环境偶发卡顿页面加载有时两秒有时十秒。先登录机器执行uptime看到 16 核机器 load 到了 22且 1 分钟、15 分钟都高排除瞬时抖动。然后top按 CPU 排序确实有几个业务进程高但更刺眼的是有 4 个进程处于 D 状态。这个信号把方向从“CPU 不够”转向“IO 有问题”。继续mpstat -P ALL 1 5发现核与核之间负载极不均衡CPU2、CPU3 接近 100%其他核只有 20%。存在两种可能单线程热点或者中断全部堆在这两个核上。接着查/proc/interrupts确认网卡中断几乎都集中在 CPU2、CPU3。顺手看进程亲和性发现一个忙线程正好跑在 CPU2。最后用strace -f -tt -c -p pid看系统调用耗时同时配合perf top -p pid看热点函数发现热点全部落在内核网络收包路径。调整方案分两块用irqbalance接管中断分配把网卡中断分散到多个核再用taskset把业务线程固定到其他性能核上。改完后 load 回落到正常范围十秒级的卡顿消失。整个排查顺序是uptime→top→mpstat→/proc/interrupts→strace→perf每一层都在收窄范围每一层都对应一个芯片或内核层面的机制。4.2 高频命令的定位能力速查表经常有人问“到底该用哪条命令”我按“症状 → 观测工具 → 判断依据”整理了一张表症状首选工具关键判断系统慢但不清楚方向uptime、topload 趋势 进程/线程汇总CPU 高mpstat -P ALL、perf top分核状态、热点函数内存受限free -h、vmstatMemAvailable、si/so磁盘慢iostat -x%util、aqu-sz、读写延迟网络收包慢sar -n DEV、/proc/net/softnet_stat吞吐、丢包、backlog多线程竞争pidstat -t -w、perf recordcswch/s、锁热点硬件拓扑lscpu、numactl核数、缓存、NUMA 节点这张表的价值在于顺序先判断负载性质再拆到 CPU、内存、IO 各子系统最后用代码级或系统调用级工具收口。新手容易一上来就perf结果被海量输出淹没反而不如在mpstat这一步多停一会儿。4.3 上下文切换最隐蔽的“系统时间”上下文切换是 Linux 上最经典也最容易被忽略的指标。vmstat 1 5的cs列是每秒上下文切换次数数字大到一定量级比如每秒几十万即使 CPU 看起来不忙业务也会明显卡顿因为进程在被频繁换进换出。pidstat -w可以按进程拆解pidstat -w 1 5其中cswch/s是被动切换时间片耗尽、等待 IOnvcswch/s是主动切换线程主动让出 CPU、等待锁。主动切换比例太高往往暗示锁竞争或线程池调度太激进用perf record -g直接看内核调用栈里的mutex_lock、schedule相关热点很快能定位到锁代码。切换代价的本质在于每次切换都要保存当前线程的寄存器、PC、栈指针恢复下一个线程的现场还要经历 TLB 失效和 Cache 污染。Cache 是芯片里的稀缺资源频繁切换等于不断把“灶台上的调料”换掉性能损耗远高于表面那几个百分点的 CPU。5. 常见问题与避坑经验实录5.1 top 里 CPU 能超过 100%这是新手第一课。top整机 CPU 使用率不会超过 100%但进程列表的%CPU可以超过 100%因为一个多线程进程可以占满多个核。某个进程显示 200%说明它平均用了两个逻辑核的 CPU。看线程级别的真实占用需要top -H或ps -eLo pid,tid,pcpu,cmd --sort-pcpu | head。注意多线程进程显示的总 CPU 是各线程之和不代表单线程能跑 200%。5.2 load 高而 CPU 空闲大概率是 IO 排队回到第一部分说的 D 状态。常见故障场景是某块盘的 IO 卡死比如挂载盘掉线、网络文件系统处于重试状态。进程进入不可中断睡眠load被撑高CPU 却没事可做。排查思路上面写过先ps -eo state,pid,cmd | awk $1D再iostat -x 1 3看磁盘队列长度和 utilization。注意%util达到 100% 并不总是等于“硬盘到了极限”NVMe SSD 这种高队列深度的设备util 100% 也可能只是请求过密要结合aqu-sz和 IO 延迟综合判断。5.3 swap 被使用但不代表内存一定不足free看到 Swap 有占用很多人就慌了。其实内核在内存富余时也可能因为某些原因把很少用的页面换出比如vm.swappiness配置偏大。先看配置sysctl vm.swappiness如果值在 60 上下且available还大、si/so没有持续波动swap 占用通常只是历史遗留不值得紧张。真正危险的是si持续非零那说明系统真的在持续把数据从交换分区往内存搬性能抖动会非常明显。5.4 perf 没权限先调两个内核开关非 root 执行perf常报 permission denied常见原因是两个参数收紧kernel.perf_event_paranoid太高需要降到 1 或 0kernel.kptr_restrict限制了内核符号可见性会影响perf report里的内核函数名。临时调整sudo sysctl -w kernel.perf_event_paranoid1 sudo sysctl -w kernel.kptr_restrict0线上环境改内核实参要谨慎并走变更流程。真没权限时先用top、vmstat、mpstat做粗筛等有权限的窗口再上perf。这也是我前面强调“先粗筛后细查”的另一个原因。5.5 x86 和 ARM 数据不能直接横向比跨架构对比性能是另一个常见误区。某程序在 x86 机器上instructions是 1 亿在 ARM64 机器上是 8000 万这不代表 ARM 更快也可能只是指令密度和编码不同。跨架构对比应该使用归一化指标IPC、Cache Miss Rate、每请求耗时、功耗等。只看原始计数器很容易得出错误结论。另外perf 里的branch-misses等指标在两种架构上的统计口径也有细微差别比较前先确认工具版本和内核版本一致环境变量的差异也要尽量对齐。“命令能跑通”和“数据可比”是两回事。5.6 整机视图与进程视图要分开不少人习惯在top里盯着某一列翻来翻去。我的建议是整机状态用uptime、mpstat、vmstat、free、iostat的组合进程细节用ps、pidstat、strace、perf。视图不分开就会陷入“某个进程 CPU 很高但整机不慢”的假象里。一个具体场景数据库复制进程在某一瞬占用 CPU 很高但业务请求量不大整机负载也很低。这时优先看进程自己的状态、IO 和线程切换而不是整机统计。先整机后进程是我排查任何问题都遵守的顺序。写到这里我想起自己最初学 Linux 时走过的弯路那时候能背几十条命令遇到问题却只会用top来回刷新折腾半天得不出结论。后来认真啃了一部分处理器相关资料再回头敲这些命令很多以前需要硬记的字段突然就通了。命令是表面的话术芯片架构和内核才是背后的语法同样的输出在不同架构、不同负载模型下含义完全不同。“CPU 高”从来不是一个答案而是一个问题。拿到一个现象先问自己四句是哪个核在忙是哪类 CPU 时间us/sy/wa/si是哪个进程甚至哪个线程热点对应哪条路径用户代码、系统调用、中断这四个问题问完排查方向基本不会错。最后再分享一个我用来检验自己有没有真懂的技巧不看man手册只读/proc下的原始文件试着手动推断 top 里的数值会怎么变化。能推出来说明你确实理解了命令背后的逻辑推不出来说明还停留在背命令的阶段需要回去补一点架构课。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑