ARTICLE DETAIL

资讯详情

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

Linux top命令详解:从负载均衡到CPU与内存排查实战

Linux top命令详解:从负载均衡到CPU与内存排查实战 1. 先看懂top的输出界面拆解与字段逻辑1.1 顶部概况区load average与CPU状态很多人在终端里敲top眼睛只盯着那个不断跳动的%CPU列谁的数字大就觉得谁是罪魁祸首。这个习惯不能说错但会漏掉大量关键信息。top命令真正的价值首先是那几行总览数据它告诉你整台机器当前处于什么状态然后才是进程级别的那张表。打开top后第一行左侧依次是系统当前时间、机器已运行时长、当前登录用户数以及最关键的三项load average后面的1分钟、5分钟、15分钟平均负载。这三个数的含义不是CPU使用率而是单位时间内处于可运行状态和不可中断睡眠状态的进程平均数量。所以判断负载是否正常不是看它小于100%就安全而是要和CPU核数对比。一台4核机器load average长期在4.0左右说明CPU刚好占满超过6.0就已经明显过载了而如果只有2核却顶着8.0的负载机器基本处于排队堵车状态这时候你敲什么命令都会觉得卡。这三组数字的组合还有一个判断趋势的技巧1分钟远大于15分钟说明负载正在快速上涨可能是刚上了一个高消耗的任务也可能是流量高峰突然来了如果1分钟小于15分钟说明高峰期已经过去系统正在恢复。只看当前CPU使用率是看不到这个趋势的。第二行展示进程状态统计分别是total总进程数、running运行中、sleeping休眠、stopped停止、zombie僵尸。这里有个经常被忽略的值zombie。如果僵尸进程数量持续不为0并且有增长趋势说明有父进程没有正确回收子进程这在编程不规范的长驻服务里很常见需要注意。第三行是CPU状态分布这一行才是真正的CPU时间去哪了:字段含义简单理解us用户态占用应用程序在跑代码sy内核态占用系统调用、内核逻辑在干活ni被修改过nice值的进程占用低优先级任务在跑id空闲无事可做wa等待IO完成在等磁盘、网络等外设hi硬中断硬件设备在请求CPUsi软中断内核处理软件层面的中断st被偷走的时间虚拟化环境下被宿主机或其他虚拟机占走实际排查的时候us高说明应用层在计算密集运转sy高说明系统调用频繁wa高是磁盘IO在拖后腿st高则说明宿主机资源超卖严重。很多人只盯着id以为id接近0就是出问题了其实us、sy、wa各有各的问题方向需要结合现场判断。第四行和第五行是物理内存与交换分区。这里新版本top展示的字段比较友好有total总内存、free空闲内存、used已使用、buff/cache文件缓存和内核缓冲区以及一个avail Mem字段。这个avail Mem很关键它代表在不触发交换的情况下还能分配给新进程的内存大致有多少比直接看free更有参考价值。1.2 进程列表那一长串字段到底什么意思概况区往下就是大家最熟悉的进程表格。top默认显示的列包括PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME、COMMAND每一列都有实际意义但很多人就只关心PID、%CPU、%MEM和COMMAND。PR和NI合在一起是进程优先级。PR是内核实际使用的动态优先级NI是用户可通过nice命令调整的静态优先级。NI范围是-20到19数值越低优先级越高一般用户只能调高不能调低root则都可以调。看到某个进程NI是负值时说明它被特意提高了优先级。VIRT、RES、SHR这三列是内存理解的核心。VIRT是进程虚拟内存总量包含代码段、数据段、共享库、以及已经被映射但还没实际吃物理内存的部分所以VIRT通常非常大。RES才是进程当前实际占用的物理内存也就是free看到的used的里真正被进程吃掉的量。SHR是共享内存包括共享库、共享内存段等这部分会同时统计在多个进程的RES里所以你把所有进程的RES加起来经常会大于free里的used就是这个原因。S列是进程状态常见的有R运行、S休眠、D不可中断休眠、Z僵尸、T停止。这里D状态经常被忽略但线上排查IO瓶颈时D状态的进程数量非常有参考价值后面实战部分我会专门讲。%CPU默认是进程占单个CPU核心的百分比所以多核机器上看到某个进程显示175%不用惊讶它只是吃满了接近两个核。%MEM表示RES占总内存的百分比。TIME是进程累计消耗的CPU时间精确到百分之一秒这个值不会因为进程休眠而增长只统计真实占用CPU的时间。如果一个进程TIME在持续快速增长即使当前%CPU不高也说明它在高频运转。理解完这些字段再看top界面就不会只盯着%CPU发呆了。排查问题时我会先扫一眼概况区定位方向再去进程列表找具体对象。2. 交互式操作top的快捷键才是效率关键2.1 排序切换P/M/T/N四键定乾坤top启动之后默认是按%CPU降序排列的所以哪个进程吃CPU最狠一眼就能看到。但实际排查时我们需要频繁切换排序维度这时候快捷键比任何鼠标操作都高效。按P按CPU使用率排序按M按内存占用排序按T按累计CPU时间排序按N按PID排序。这四个键是我日常用得最多的尤其是M排查内存问题的时候没有它寸步难行。排序快捷键有一个容易踩的坑这些键区分大小写而且必须是小写状态。如果开着大写锁定按P的时候实际触发的是别的功能界面不会有任何变化很多人还以为是自己按错了。另外top自身的排序逻辑是降序默认把最占资源的进程放在第一行这个设计符合排查场景一般不需要改。按T按累计时间排序有个妙用。比如一个进程现在%CPU不高但你怀疑它长年累月偷跑CPU按T之后TIME最大的进程排在最上面一眼就能识别出谁是长期消耗大户。这在排查电池消耗、服务器电费异常、或者某个服务为什么总是超时时特别好用。2.2 显示控制x/y/b/1/H/f各有各的用处默认的top界面只有行和列没有视觉重点。按x键会在当前排序字段的整个列上高亮显示再按一次取消。配合x之后就算你不小心切换了排序字段眼睛也能迅速定位到当前的排序依据。按y键会高亮所有处于R运行状态的进程。按b键是加粗或反色显示新版top里b和x、y配合起来视觉效果非常清晰。这三个键很推荐组合使用按x高亮排序列按y高亮运行进程再按b加深对比整个界面就变成了一个实时监控仪表盘而不是一堆枯燥的数字。按数字1可以展开或折叠每个CPU核心的单独统计。默认只显示一行CPU汇总按1之后每个核占一行能直观看到多核负载是否均衡。比如一台16核机器有些核已经100%有些核还是0%说明负载不均可能是单线程应用在死循环也可能是中断都打在一个核上。按字母H可以在进程视图和线程视图之间切换进程视图下看到的是每个进程一行按H切换后每个线程单独占一行排查多线程应用的CPU问题时这是必须的操作。按f进入字段管理界面。这个界面很多人不敢按其实它就是一个可以上下选择、空格选中/取消字段的配置页。进入后按上下键选择字段按空格控制是否显示按d或s选择排序字段按q退出。用f把不需要的列去掉比如PPID、ni、swapped这些你用不到的字段只保留核心信息top界面会清爽很多。2.3 进程管理k杀进程、r调优先级、W保存配置top不仅能看还能直接管理进程。按k可以终止进程按完之后提示输入PID输入后回车会要求选择信号默认是15SIGTERM如果进程不响应可以再输入9SIGKILL强制终止。这个操作比另开一个终端用kill命令要快但代价是容易误操作按下9之后进程瞬间没所以现场操作时一定要看清PID。按r可以修改进程的nice值重新设置运行优先级。比如一个普通的测试脚本跑起来把CPU吃满了你不想杀掉它可以按r输入PID然后把nice值调高降低它的调度优先级让出更多CPU给其他进程。还有一个我很推荐的快捷键是W它的作用是保存当前所有显示配置包括排序字段、显示列、高亮设置等。保存之后下次启动top会自动加载这些配置配置文件在用户主目录下的.toprc里。从运维角度来说W键可以让你把一台机器上调好的top界面复制到其他机器只需要把.toprc文件一并拷贝过去就行。H键在线程视图与进程视图之间切换这个在Java、Node.js等大量使用线程的应用排查中极其重要。比如一个Java进程占了300%的CPU在进程视图下只能看到PID但不知道是哪个线程在忙按H之后就能看到具体的线程ID再配合jstack就能定位到具体代码逻辑。3. 命令行参数与脚本化采集3.1 常用启动参数让top按你想要的方式启动top的交互快捷键确实好用但真正体现它强大之处的是命令行参数尤其是批处理模式。先说最常用的几个启动参数。-d指定刷新间隔单位是秒。比如top -d 2表示每2秒刷新一次。默认间隔是3秒但在高节奏排查时3秒感觉太慢1秒又可能对系统造成额外负担我一般用2秒比较折中。-p指定监控特定PID后面可以跟多个PID用逗号分隔比如top -p 10086,10087。这在只想盯一个进程的时候特别有用不会因为其他进程偶尔飙高而干扰判断。-u按用户名过滤比如top -u www只看www用户进程对于排查某个业务用户下的资源占用情况非常高效。-H启动即进入线程视图这个参数在定位线程级热点时可以直接节省一次按键。-b进入批处理模式这是脚本化采集的核心参数。在批处理模式下top不会进行交互式刷新而是把输出持续打印到标准输出必须配合-n指定输出的次数比如top -b -n 1输出一次快照后退出。还有一个很实用的参数是-o可以指定排序字段。比如top -b -n 1 -o %MEM表示按内存排序输出一次快照这样在脚本里可以直接拿到内存占用Top 10的列表比输出后再排序方便得多。还有一个容易被忽略的参数是-i它表示不显示空闲进程和僵尸进程。配合批处理模式使用可以让输出内容更干净只保留有实际活动的进程。-w可以设置输出宽度默认情况下批处理模式输出的命令行会被截断到固定宽度设置-w 512可以输出更完整的命令行信息。3.2 批处理模式定时采集与数据加工top命令在交互模式下适合人看但在批处理模式下就变成了一条可编程的性能数据管道。我最常用的做法是用它做定时采样采集系统的性能快照用于事后分析。最简单的用法是top -b -n 1直接输出当前快照。但要注意一个细节如果你用top -b -n 1采集到的数据第一条输出往往不是最准确的。因为top启动后的第一帧数据进程的CPU使用率统计是从进程创建开始的平均值而不是最近一个周期的瞬时值。官方也建议采样时至少输出两次取第二次的数据比如top -b -n 2 -d 2然后取第二组输出。我在脚本里通常这么写top -b -n 2 -d 2 | grep -A 20 top - | tail -n 20这个命令先输出两次快照间隔2秒再用grep和tail取出第二组的前20行。加-A 20是为了连同进程列表一起取出来。如果你需要定期采集可以配合cron定时任务把数据追加到日志文件。比如每5分钟记录一次*/5 * * * * top -b -n 2 -d 2 | tail -n 30 /data/logs/top_$(date \%Y\%m\%d).log因为cron传参时百分号需要转义这里的日期格式化里写了\%Y。采集到的日志可以用awk、sed或者干脆导入Excel做后续分析。批处理模式下top的输出格式是稳定的列字段会以空格分隔任何数据处理工具都能直接上手。还有一个进阶用法是结合grep和PID过滤。比如脚本里明确知道要观察某个进程先通过pgrep拿到PID再传入top的-p参数PID$(pgrep -f java.*app.jar | head -n 1) top -b -n 1 -p $PID这样每次采集到的就是指定进程的精确状态数据噪声非常小。如果需要对比多个进程可以给-p参数传多个PID用逗号分隔即可。4. 实战演练用top快速定位三类性能问题4.1 CPU飙高从进程到线程再到代码遇到线上CPU飙升的情况很多人的第一反应是重启服务。但作为合格的技术人应该在重启前尽量拿到现场证据。top就是拿证据的第一步。假设你发现某台应用服务器load average从2.0涨到了8.0SSH登录进去后先执行top看到某个Java进程的%CPU到了350%。这时候先用top -H -p PID从进程视图切换到这个进程内部的线程视图观察哪个线程的CPU占用最高。假设你看到PID为12345的线程CPU占到了120%把它记下来。线程ID在Java的线程转储文件里是十六进制表示的需要转换一下printf %x\n 12345输出结果是3039再执行jstack采集线程快照jstack 12345 /tmp/jstack.out grep -A 50 0x3039 /tmp/jstack.out就能看到这个线程正在执行的代码调用栈从而定位到具体业务代码。这一套top找进程、top -H找线程、print转十六进制、jstack定位代码的操作是排查Java应用CPU问题最经典的链路每一步都用了Linux自带或JDK自带的工具不需要任何额外的安装。对于非Java进程比如Python、Node.js或者自定义的C程序也可以套用类似思路。先top找到进程和线程ID再用/proc/PID/task/TID/stack查看内核栈或者用perf工具采样用户态调用栈。总之top负责锁定目标后面的工具负责深挖细节。4.2 内存异常VIRT与RES的误判内存问题比CPU问题隐蔽得多因为看着内存吃了很多和真的把内存吃没了是两回事。我在排查内存问题时第一步就是用top按M键排序看看RES最高的进程是谁。有一类典型场景是某个进程的VIRT特别大比如几十GB但RES只有几百MB。很多新手会把VIRT当成这个程序吃了多少内存一看到几十GB就慌了到处找人问是不是内存泄漏。其实VIRT大很常见因为Java等语言会预先申请一大块虚拟地址空间但只有真正写入数据的部分才会占用物理内存。判断是否真的内存紧张要看RES和系统级的free、avail Mem。真正危险的是RES持续上涨的情况。比如一个进程启动时RES占500M运行了几天慢慢涨到3G并且没有回落的趋势这时候就大概率存在内存泄漏。用top观察RES变化曲线的技巧是连续多次采集比如每隔10分钟记录一次RES值如果单调递增而不收敛就可以基本确定了。配合top -p PID持续观察同时用cat /proc/PID/smaps分析进程内部哪些内存段在增长定位是堆、栈还是其他内存区域的问题。另外还有一个容易误判的点是SHR列。SHR是共享内存多个进程共用的库和内存映射都会算进去。如果你看到一个进程RES很高但SHR也高可能它只是加载了很多共享库并不是真正吃掉了那么多独享内存。真正需要关注的是RES减去SHR后剩下的部分。4.3 负载高但CPU低不可中断休眠进程排查有一种场景非常让人头疼load average已经飙升到十几但进top一看CPU的id还有70%us和wa都不高。这种情况很多人会怀疑是top坏了或者数据不准。其实问题多半出在D状态进程上。D状态是不可中断的休眠状态通常是进程在等待磁盘IO或网络IO等内核操作完成。大量进程进入D状态意味着它们都在排队等待某个IO操作完成这些进程也会被计入load average但它们不消耗CPU。所以CPU空闲、负载却很高是IO瓶颈的典型信号。在top里这些D状态进程会出现在S列显示为D。如果看到大量D进程可以先用ps做一次精确筛选ps -eo state,pid,cmd | grep ^D这会列出所有D状态进程及其命令。接着用iostat -x 1看磁盘的%util和await指标如果磁盘利用率已经接近100%、IO等待时间很长说明磁盘确实是瓶颈。也可能是某个进程在频繁写入大量数据而不是整个系统都在做IO这时候从top里找到那个最可疑的进程再配合strace -p PID看看它到底在做哪些系统调用。4.4 压测与调优用top做实时反馈top不只是故障排查工具在性能压测和调优时也很有价值。比如你对服务做压测另开一个SSH窗口跑top -d 1能实时看到服务的CPU、内存、线程状态变化。通过观察us和sy的比例可以判断这个服务是计算密集还是系统调用密集。如果sy占比很高说明服务在内核态花的时间多可能是大量的网络收发、文件读写或者锁竞争这时候调优方向是减少系统调用而不是盲目加CPU核数。用top对比压测前后的进程状态也很有用。比如压测之前某进程有100个线程压测之后线程数暴涨到800说明服务在频繁创建线程处理请求很可能有连接泄漏或线程池配置不合理的问题。top的-H线程视图在这种场景下是直接可用的数据来源。5. 常见问题与实用避坑清单5.1 高频问题速查表现象原因处理方法%CPU显示超过100%多核累计使用率正常不用处理按核数理解即可僵尸进程状态为Z父进程未回收子进程找到父进程修复回收逻辑或重启load高但CPU空闲多数为D状态进程等待IO用ps筛D进程再看iostat磁盘队列内存used很大但系统流畅buff/cache缓存占内存可回收用avail Mem判断真实可用内存命令行显示不完整终端宽度不够或未开启完整显示按c/C切换完整命令行或用-w参数某字段找不到字段被隐藏或版本不支持按f进入字段管理界面开启top反映速度慢默认刷新间隔3秒按d或s调整刷新间隔想监控的进程排序不在最上面排序字段不对按P/M/T/N切换排序批处理输出第一条数据异常第一帧CPU统计不准使用-n 2取第二次输出某进程不显示被-u过滤或-i忽略掉去掉过滤参数重新看5.2 几个容易忽略的小细节用好top细节很重要。第一个细节是刷新间隔的精度问题。top默认的计时器是3秒但这个3秒不是绝对的它受top自身调度影响在系统负载高的时候实际间隔可能会拉长。如果你需要非常精确的采样间隔建议使用-d参数并搭配外部定时器或者干脆用sar、collectl这类专门做性能采样的工具top的定位是快速观察而不是精确测量。第二个细节是top的配置文件。当你在top界面按W保存配置后配置文件里会记录你的各项设置包括排序字段、显示列、颜色方案等。但如果你在另一台机器上拷贝了这个.toprc文件要注意它的格式可能在不同版本的top之间不兼容特别是显示的字段名有变化时可能导致top启动异常。遇到这种情况直接把配置文件删掉让top恢复默认即可。第三个细节是top在批处理模式下的输出宽度问题。默认情况下批处理输出的每一行宽度是固定的命令行字段过长会被截断。如果你需要完整的命令行务必加上-w 512之类的宽度参数。但也要注意输出文件的行太长可能导致后续用awk等工具处理时字段错乱需要提前规划好分隔规则。第四个细节是top不擅长历史数据的追溯。它是实时工具窗口一关数据就没了。如果你的目的是事后分析比如复盘一次性能故障建议配合完整的日志采集方案用top -b -n 600 -d 10持续采集10分钟把输出保存到文件事后慢慢看。这个方式比人盯着屏幕更可靠因为人总会走神。第五个细节也是我个人使用过程中的一个体会top的-p参数在监控动态进程时有点笨。比如进程重启后PID会变你用固定的PID监控会失效。我在脚本里会动态解析PID而不是写死数字PID$(pidof myservice) top -b -n 1 -p $PID这样每次采集时都能拿到最新的进程ID。如果你需要综合判断整台机器的健康状况我建议在top之外再搭配一两个工具比如sar看历史趋势、iostat看磁盘IO、vmstat看内存换页这样形成一套完整的工具链比单纯依赖top要多几分底气。top是那个先手但永远不是全部。
返回列表