ARTICLE DETAIL

资讯详情

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

Linux性能排查必备:perf常用命令速查手册

Linux性能排查必备:perf常用命令速查手册 写这份perf常用命令速查手册是因为团队里每次有人问“CPU飙高了怎么办”“接口为什么偶发抖动”我都要把同样的命令从历史记录里翻出来久而久之干脆整理成了一份能直接查的文档贴在工位旁边。perf是Linux内核自带的性能剖析工具基于内核的perf_event子系统几乎任何发行版都能用采样开销可控线上应急非常合适。它能回答一个其他工具很难回答的问题程序的时间到底消耗在哪些函数、哪些指令上。不管你是运维、后端开发还是SRE只要日常需要排查Linux性能问题这份手册都值得收藏起来遇到情况时按图索骥。很多人一遇到性能瓶颈习惯打开top看一眼就慌了神然后凭感觉加机器、调参数折腾半天没效果。其实只要冷静下来用perf采集几十秒现场问题往往就浮出水面了。接下来我会从工具原理讲到每个高频命令的实际用法再结合真实案例和常见问题把一份能直接落地的速查手册给你理清楚。1. perf能帮我们解决什么问题1.1 什么场景下该拿起perf用的是同一台机器偶尔会出现这样几类让人头疼的问题而perf就是为这些场景准备的。第一类是CPU占用异常高但不知道是谁在烧CPU。top能看到进程占用300%但看不到进程内部哪一段代码在发热。尤其是用Go、Java、C写的大型服务源码几十万行没有调用链信息基本无从下手。perf可以精确到函数、甚至到某一条汇编指令。第二类是延迟抖动。监控面板上接口P99偶尔飙到几百毫秒但平均耗时没什么变化这种抖动大多和CPU调度、锁竞争、缓存局部性有关。perf sched和perf lock专门干这个能把调度延迟和锁等待时间直接量化。第三类是优化完代码觉得“应该变快了”但说不清快在哪。这类情况我会用perf stat对比优化前后的指标看IPC、cache-misses、分支预测失败率是否真的下降。数据摆在面前比拍脑袋靠谱得多。1.2 实用工具那么多为什么要先学perfLinux下的问题定位工具不少但各有各的局限。top只能看到进程级别的CPU、内存占用属于“系统体检”根本进不去进程内部。strace只能追踪系统调用计算密集型的CPU热点它完全看不见而且ptrace机制会让目标进程慢好几倍。gdb是调试器适合解决逻辑bug但性能问题上你用gdb打断点就相当于让一个跑马拉松的人每跑一步停下来绑一次鞋带完全扭曲了现场。perf的优势在于它走的是内核的硬件性能计数器采用采样的方式记录运行现场而不是一条一条插桩。打个比方你不需要给每一辆过路车都装GPS记录仪只需要随机抽几百辆车就知道了这条路大致通向哪里。采样开销小不影响真实运行采样结束还能生成调用链直接定位热点函数。这也是perf被称为“Linux性能排查第一工具”的原因。它不像gprof那样依赖编译期插桩也不像一些商业工具那样需要额外部署agent装上内核配套的perf命令就能用干净利落。2. 上手第一步安装与权限准备2.1 不同发行版安装perfperf不是独立软件它跟着内核源码的工具目录发布不同发行版的命名习惯不一样。Debian和Ubuntu上先安装通用包再安装对应内核版本的工具包apt-get install -y linux-tools-common linux-tools-generic apt-get install -y linux-tools-$(uname -r)RHEL、CentOS和Rocky Linux上直接装perf包yum install -y perf如果包管理器里找不到对应内核版本的工具包可以直接到内核官网下载同版本源码单独编译tools/perf目录依赖很少耗时也能接受make -C tools/perf装完之后第一步不是急着跑命令而是检查perf版本和当前内核是否匹配否则很可能出现某些事件不支持或指标解读错误的情况perf --version uname -r2.2 权限、内核参数与符号问题很多人第一次跑perf看到“Operation not permitted”就懵了。这通常和内核参数kernel.perf_event_paranoid有关。这个参数限制的就是普通用户能不能使用性能计数器常见的取值和含义如下参数值含义2只允许用户态自进程测量多数发行版默认值1允许CPU事件用户态采样不允许内核态采样0允许内核态采样-1完全放开无限制临时放行可以执行sysctl -w kernel.perf_event_paranoid-1如果希望永久生效写入配置文件echo kernel.perf_event_paranoid-1 /etc/sysctl.conf sysctl -p这里要郑重提醒一句线上环境改权限前先和运维确认安全策略别为了一次排查把生产机长期置于完全放开状态排查完记得改回来。容器环境里用perf还要看capabilities通常需要--privileged或者至少添加CAP_PERFMON。另外检查一下kptr_restrict参数它会影响内核符号的读取非root用户经常在此处栽跟头。符号解析是另一个高频坑。perf top里如果看到一堆unknown或者符号地址无法映射到函数名要分三步排查。第一步确认编译时加了调试信息和栈帧指针C/C程序建议用gcc -g -fno-omit-frame-pointer -O2 app.c -o app第二步确认系统有没有安装对应内核的debuginfo包。Ubuntu可以通过ddeb仓库安装linux-image-$(uname -r)-dbgsymRHEL系可以用debuginfo-install kernel-$(uname -r)。第三步如果线上二进制为了减小体积做了strip也没有关系perf会记录build-id之后可以用perf buildid-cache --add把带符号的文件关联回去。2.3 采样原理与频率怎么定perf这个工具最核心的机制是性能计数器溢出采样。CPU内部有一组硬件计数器可以统计cycles、instructions、cache-misses这些硬件事件。perf设置一个采样周期当计数器达到阈值时触发一次中断内核在中断处理程序里记录下当前进程ID、CPU编号、指令指针和调用栈。就这样每隔一段固定时间“咔嚓”拍一张照片最后把成千上万张照片聚合成热点分布图。软件事件如task-clock、context-switches走的也是类似机制只是计数源变成了内核软件时钟。这里有个采样频率的选择经验很多人没弄明白。perf record默认的采样频率是4000Hz也就是每秒拍4000张照片。频率越高细节越丰富但采样本身也有CPU开销尤其配合-g采集调用栈时每秒几千次栈回溯并不轻松。生产环境我一般建议用-F 99也就是每秒采样99次。为什么是99而不是100因为100和系统时钟的节律、程序运行周期容易形成整数倍关系采样间隔若和热点函数的执行周期共振我可能每次都拍到同一个小阶段导致结果失真。99是质数与大多数周期没有公约数采样位置会更均匀地散落在整个时间线上。这也是火焰图作者Brendan Gregg到处推荐-F 99的原因。短时间任务、测试环境可以适当提高频率线上长期采集则应控制在49到99之间。3. 四个最常用的perf命令3.1 perf stat先看整体指标任何性能问题的排查我建议先跑一遍perf stat它能在不深入采样的情况下告诉你程序整体健康状况。最简单的用法是跟踪一个正在运行的进程10秒perf stat -p PID sleep 10或者直接运行一条命令做整体统计perf stat -e cycles,instructions,cache-misses,branch-misses ./app输出通常长这样Performance counter stats for sleep 5: 0.34 msec task-clock # 0.000 CPUs utilized 1 context-switches # 2.941 K/sec 0 cpu-migrations # 0.000 K/sec 61 page-faults # 179.412 K/sec 306,891 cycles # 0.903 GHz 315,724 instructions # 1.03 insn per cycle 65,722 branches # 193.300 M/sec 8,249 branch-misses # 12.55% of all branches几个关键指标我按重要程度排个序。instructions per cycleIPC是衡量CPU流水线利用效率的核心指标。现代x86处理器理想情况下IPC能到2到4实际应用能稳定在1以上就算健康。如果IPC长期低于0.5说明CPU大部分时间在等待内存、等待分支预测结果而不是在真正算数。实战中我用IPC判断优化方向百试不爽IPC低就往访存和分支优化IPC已经很高但仍不够快就要考虑并行化。context-switches代表进程被切换出去的次数。每秒几百上千次正常如果上万多半是锁竞争激烈或线程数量设置失衡。cpu-migrations表示进程在不同CPU核心之间搬家的次数核心频繁迁移会污染L1/L2缓存性能损耗明显。page-faults里重点看major faults它意味着磁盘IO参与是真正的性能杀手。3.2 perf top实时代码热力图perf top相当于把top的进程维度换成函数维度实时刷新CPU热点分布。它是最快的定位方式适合排查线上正在发生的CPU飙升问题。直接运行perf top -p PID -F 99界面会显示类似这样的数据Samples: 25K of event cpu-clock, 4000 Hz Overhead Shared Object Symbol 12.40% libc-2.31.so [.] __memmove_avx_unaligned_erms 8.15% app [.] ProcessChunk 5.22% libstdc.so.6.0.28 [.] std::__cxx11::basic_string::_M_replace第一列是开销占比第二列是符号所在的动态库或可执行文件第三列是函数名。看到哪一行占比高就说明时间烧在哪个函数上。按q退出按h查看帮助数字键可以展开当前符号的内部调用。这里有个很实用的习惯进来先看有没有大面积的unknown符号。如果unknown比例超过10%先别急着分析多半是权限或调试信息没配好分析出来的结论也是错的。另外看到swapper/0、irq/这类内核线程出现在前列不用慌正常现象重点盯用户态的热点。3.3 perf record 加 perf report离线深挖perf top适合现场观察但很多时候需要保存现场、事后慢慢分析或者对比优化前后的变化这时候要用perf record把采样数据落盘。典型的采集命令perf record -F 99 -p PID -g -- sleep 30这条命令的意思是以每秒99次的采样频率追踪PID进程开启调用栈采集持续30秒后停止。采样数据默认保存在当前目录的perf.data文件里。几个高频参数列一张表参数作用-e指定性能事件如cycles、instructions、cache-misses-F指定采样频率生产环境推荐49到99-c指定采样周期每发生N次事件采样一次-p追踪指定PID可逗号分隔多个-a全系统采样不加进程限制-g采集调用栈--call-graph指定调用栈采集方式dwarf或fp-o指定输出文件名默认perf.data-C指定CPU核心列表比如-C 0,2关于--call-graph值得多说两句。fp方式依赖栈帧指针性能好但编译时如果没加-fno-omit-frame-pointer拿到的调用栈往往会断掉只能看到零散几层。dwarf方式通过调试信息展开栈栈更深、更完整但开销明显更大。生产环境我会优先试fp栈不完整再换dwarf。采集完成后用perf report分析结果perf report --stdio -g graph,0.5,caller--stdio把报告直接打到终端省事-g graph,0.5,caller表示按调用者视角展示调用链且只显示占比超过0.5%的节点。数据大的时候我习惯加一个--percent-limit避免终端刷屏。如果只需要调用链折叠输出方便脚本处理还可以用perf report -g folded3.4 perf annotate精确到指令行当perf report定位到热点函数之后更细的问题是函数里几百行代码到底是哪一行最烧CPUperf annotate粉墨登场perf annotate -i perf.data进入交互界面后定位到目标函数按回车展开你会看到函数对应的汇编代码每一行前面标着采样占比。这一排百分比就是性能的“分子解剖图”。如果占比集中在一条load指令上说明缓存缺失严重集中在分支跳转指令上说明分支预测失败率高集中在mul、div这类指令上说明真的是计算密集型。这一招在排查“为什么编译优化后反而变慢”时特别管用。编译器重排指令后肉眼看不出来但annotate会给出数据层面的答案。4. 进阶perf还能分析什么4.1 perf sched调度延迟狙击手接口偶尔抖一下CPU利用率又不高十有八九是调度延迟或锁等待。perf sched专门用来量化内核调度行为。先采集再分析perf sched record -- sleep 10 perf sched latency输出的核心字段是wait time和sched delay。wait time反映任务从就绪到真正被调度上CPU的等待时间如果某个任务的wait time动辄几十毫秒说明CPU资源充足但调度策略或cgroup限额在捣乱。sched delay则表示调度器本身的处理延迟。配合perf sched map可以看到每个CPU上任务切换的时间线多核负载不均一目了然。遇到那种“明明CPU没跑满但任务就是卡住不执行”的问题perf sched几乎是首选工具。4.2 perf lock锁竞争与死锁并发程序性能杀手第一名就是锁竞争。perf lock record -- sleep 10 perf lock report报告会列出每个锁的争用次数、等待时间、持有时间。看到某个锁的wait time特别高就说明大量线程在排队等锁。再往下用perf lock contention可以直接看锁的调用栈perf lock contention -b -I 100-b表示收集调用栈-I 100表示只查看前100条记录。这样能直接看出来是谁拿着锁不撒手。相比自己写代码打点来说这套方案最大的优势是不用改一行业务代码纯观测。4.3 perf trace系统调用追踪strace虽然常用但ptrace方式在业务进程上跑性能开销可能让进程直接卡死。perf trace采用内核perf_event机制开销低一个量级。perf trace -p PID它会实时打印进程发起的系统调用、耗时和返回值。只看某类系统调用可以加事件过滤perf trace -e syscalls:sys_enter_openat cat /etc/hostname排查“文件打开慢”“网络send卡顿”这类问题perf trace比strace安全得多尤其是面对高并发线上服务时这是我首选的原因。4.4 火焰图一图看懂调用链perf report虽然信息全交互界面不够直观。把perf数据转成火焰图是团队内外分享结论时的标准姿势。先安装FlameGraph工具集git clone https://github.com/brendangregg/FlameGraph.git然后一套组合拳perf record -F 99 -p PID -g -- sleep 30 perf script out.perf ./FlameGraph/stackcollapse-perf.pl out.perf out.folded ./FlameGraph/flamegraph.pl out.folded flamegraph.svg最后用浏览器打开SVG文件。火焰图底部是根顶部是叶子函数每一个色块的宽度代表采样数占比。看到顶部哪个色块最宽就是最热的热点。读火焰图有个反直觉的点x轴方向不代表时间顺序它只是把相同的调用栈合并排列在一起。真正要看的就是“哪条路最宽”。如果色块边上有很多尖尖的小平顶往往说明大量不同调用路径汇聚到了同一个函数这种函数通常是公共库接口比如malloc、memcpy。如果perf script生成的文件太大可以用perf report -g folded直接输出折叠栈省去中间文件环节。5. 真实案例从CPU飙高到定位瓶颈的完整过程5.1 现象与初步判断上一个真实案例。某生产服务突然CPU占用飙到380%QPS却从正常的5000掉到1500用户访问明显变慢。登录机器先看top确认是打印服务进程print-server在烧CPU。这种场景千万别重启。重启确实能暂时“治好”症状但下次复发还是两眼一抹黑。我的习惯是先留证据马上跑一个perf top看看当前热点。perf top -p PID -F 99几秒后热点出来了集中在模板渲染库的RenderTemplate函数上占比接近40%。初步判断CPU都花在渲染逻辑上但单一进程的多个线程到底在哪个分支路径上perf top还看不清楚需要完整调用链。5.2 采样采集与调用链解析执行离线采样时间为60秒保留足够多的样本perf record -F 99 -p PID -g -- sleep 60然后查看报告perf report --stdio -g graph,0.5,caller关键调用链非常清晰main └─ WorkerThread └─ ProcessRequest └─ RenderTemplate ├─ ParseAndEvalExpr │ ├─ yaml_parser_parse │ └─ TokenizeString └─ BuildCacheKey热点集中在ParseAndEvalExpr下面每一个请求都在重复解析同一份模板YAML配置。优化前代码里每次请求都会重新加载模板文件并做YAML解析而这是一张很少变化的配置表。5.3 指标验证与优化对比方案很简单把模板解析结果缓存起来只在配置变更时刷新。改完后先别急着测QPS直接用perf stat做个前后对比优化前perf stat -e cycles,instructions,cache-misses ./print-server /dev/null优化前IPC大约0.42cache-misses占比很高很大一部分CPU周期都在等待内存。优化后把模板缓存改成进程启动时一次性加载IPC提升到0.85CPU从380%降到140%QPS恢复到5000以上。这个案例的价值在于整个定位过程中没有改一行业务日志没有重启一次服务全程靠采样数据还原了真相。如果凭直觉去优化我大概率会先去调线程池大小或加内存方向完全跑偏。perf的价值不是给你答案而是给你证据链。6. 高频问题排查速查表6.1 十类高频问题与解决思路问题现象常见原因排查命令与思路Operation not permittedperf_event_paranoid受限、容器无权限sysctl -w kernel.perf_event_paranoid-1容器加--privileged或CAP_PERFMONperf: command not found未安装或版本不匹配安装perf包确认perf版本与uname -r匹配出现大量unknown符号缺debuginfo、编译无-g、kptr受限装debuginfo包编译加-g检查kptr_restrict采样数据文件巨大采样频率过高、时长过长降-F到99或49缩短时长-o单独指定输出路径report结果为空事件不支持或采样时间太短perf list确认事件增加采样时长到至少10秒JIT程序栈看不懂Java/Node缺少符号支持Java类应用优先用async-profilerperf用jitdump方式辅助分析容器内采集失败缺少cgroup访问权限宿主机用perf -a采集或容器加--privileged并共享pid namespace短生命周期进程抓不到进程跑完record还没attach上perf record -- 直接包裹命令或用execsnoop配合录制内核态热点占比高网络驱动、虚拟化、内核bug检查内核版本与驱动用perf report -k指定System.map多核采样分布乱任务频繁迁移taskset绑定CPU后再perf record -C指定核采集6.2 perf使用中的实用经验补充有几个经验不是文档里会写的但实战价值非常高。采集动作别污染现场数据。perf record一个进程时顺带把执行perf命令的终端进程也采进来报告里就会出现一堆bash、ssh相关符号。生产环境我习惯用perf record -p PID指定进程并配合过滤避免SSH会话打扰。采样时长至少10秒钟最好到30秒以上。采样原理决定了样本数量太少会丢失细节10秒钟每秒99次也才1000个样本左右对于复杂调用链来说不够。宁可一次采久一点也不要反复采多次。线上排障别迷信perf一点就能看到所有问题。perf对CPU密集问题非常灵但IO密集型瓶颈往往要结合iostat、blktrace、文件系统日志一起分析。perf不是万能药它是性能工具链的第一块基石。遇到“延迟抖动但CPU不高”这种疑难杂症建议perf sched和perf lock一起看。我遇到过一次典型的互斥锁排队导致P99飙高CPU总量才20%不到perf top看不出任何问题但perf lock report直接列出了某个锁平均等待时间超过80毫秒问题秒定位。7. 一些容易被忽略的经验最后分享几点自己长期使用形成的工作习惯不是命令参数但对排查效率影响很大。第一线上出性能问题不管现象是CPU高还是延迟抖动我的第一动作永远是先花30秒留一份perf record现场再做其他操作。因为很多性能问题是瞬间的等监控告警通知到人、再登录上去现场可能已经没了。提前建立“先采样再处理”的条件反射能帮你留住最关键的证据。第二改完代码做优化验证时不要只看业务指标比如QPS、耗时这些指标受影响因素太多。我的习惯是优化前后各跑一轮perf stat对比IPC、cache-misses、branch-misses这几个硬指标。数据对了业务指标自然会好数据不变业务指标变好了反而是运气成分居多。第三对perf_event_paranoid这个参数要有敬畏心。测试环境随便改没问题但生产环境要把“临时开、用完关”写进规范。我见过有同学把线上所有机器永久设成-1被安全团队通报批评。权限越界不仅影响稳定性还有合规风险。这份手册到这里就是把日常工作中最高频的perf用法全部覆盖了建议你收藏下来真正遇到CPU飙高、延迟抖动、瓶颈不明的问题时直接翻到对应章节跟着做就行。perf值得花一晚上练熟因为它会在未来每一次性能应急里加倍回报你。
返回列表