资讯详情

资讯详情

Linux top命令按用户过滤进程:从基础到实战,快速定位CPU异常

监控平台拉了一条CPU告警我习惯性ssh上去敲top结果满屏都是别的用户进程业务A、数据库、监控唯独想看的那个用户进程不知道被挤到哪一屏去了。这种场景下用top指令查看指定用户进程就是最直接的办法。这篇文章围绕这个高频需求把top -u参数、运行中按键过滤、PID集合组合、线程视图、批处理监控这些用法一次讲透顺便把踩过的几个坑也写出来适合Linux运维、开发和经常在服务器上排查问题的同学收藏。1. 默认top的盲区满屏进程里找不到目标用户1.1 一次CPU告警暴露的真实问题先还原一个很典型的排查场景。某天下午一台共享开发机负载突然拉高top打开之后整个屏幕被几十个进程塞满——有同事在跑编译任务有数据库备份脚本还有采集日志的agent。我所负责的服务进程排到了第二屏CPU和内存占用看得断断续续几乎没法判断是不是当前用户进程把机器搞垮的。这就是默认top模式的尴尬它展示全量进程并且默认按CPU占用排序。在进程少的实验室环境里没问题但放到多用户服务器、生产数据库节点或者跑着大量daemon的机器上目标用户进程会淹没在嘈杂的列表里。更麻烦的是top每3秒刷新一次排序位置一直在变你想在脑子里手动摘出某个用户的进程很容易漏掉中间一帧。这个痛点背后是一个很基础的运维认知top指令真正擅长的不是看全部而是快速圈定关注范围。圈定范围的方式有很多按用户过滤是最常用的一种因为它指向的是一个清晰的业务问题——某某用户的进程现在到底在干什么。无论是想确认tomcat用户是不是在抢CPU还是想统计mysql用户在内存上的总消耗第一步都是先把列表缩到这个用户身上。1.2 按用户过滤的本质从全局视图到动态局部视图很多人以为top按用户过滤只是显示的时候隐藏掉其他行其实不是。在procps-ng的实现里top -u 用户名会在top维护任务列表的环节直接做一次前置过滤不匹配用户条件的任务根本不会进入显示和排序流程。这意味着过滤后的列表是动态的用户进程里后来fork出来的新子进程也会自动被拉进来不会像静态PID列表那样漏掉新进程。这一点在后面对比-p参数时会非常关键。按用户过滤适用的场景很典型多用户共享服务器上快速定位某人/某角色自己的进程资源占用。数据库或中间件专项观察比如只盯mysql用户、nginx用户。出现CPU或内存异常时先确认是不是某个用户下的进程引起的。针对同一用户多个实例做资源对照比如Java应用的多实例部署。把视野从全部进程收窄到指定用户进程本质上就是在给排查问题画一个边界。边界画得越准后续定位根因的路就越短。2. 三种按用户查看进程的常规姿势2.1 启动时锁定top -u username最直接、也最推荐的用法是在启动top时直接带-u参数。语法非常简单top -u tomcat top -u 1001 top -u tomcat -d 2-u后面可以接用户名也可以接UID。我习惯在跨环境操作时优先用用户名因为同一个人的UID在不同的机器上可能不一样用户名可读性更强也便于排查问题的人一眼就看明白。假如环境里出现了用户不存在的情况再改用UID兜底。-d 2这个参数我是强烈建议配合使用的。top默认3秒刷新一次排查问题时等3秒刷新总觉得节奏太慢把它调成2秒或者1秒观察CPU波动的实时性会好很多。top -u tomcat -d 1就是每秒刷新一次只看tomcat的进程列表定位问题时非常舒服。这里还要提一个容易被忽略的细节top -u过滤的是进程的当前归属用户对应的是top输出里的USER列。如果用户名输错了或者该用户当前没有任何进程top不会报错只会在表头下面留一片空白。2.2 运行中切换交互模式按u有时候你已经打开了top看到了全局概览突然想临时看某个用户这时候没必要退出重开直接在交互界面按小写字母u。按下u之后top底部会出现一行提示Which user (blank for all)输入用户名回车列表立刻只剩该用户的进程。如果想换一个用户再按一次u重新输入如果想取消过滤回到全量视图按u之后不输入任何内容直接回车就行。这个方式的优点在于操作灵活适合临时切换场景。命令行参数是启动前就锁定按键是运行中随时换人。二者结合基本覆盖了日常所有查看指定用户进程的需求。需要注意一点交互模式下输入用户名时区分大小写而且要求输入的是当前系统里能匹配到的用户名。你输一个Tomcat和tomcat结果可能完全不同。2.3 按PID集合查看pgrep配合top -p除了用户维度top还支持直接指定进程ID集合参数是-p。这个参数本身和按用户没有直接关系但通过pgrep组合一下就能实现跨用户、跨进程的特殊观察需求top -p $(pgrep -u tomcat -d,)这条命令先用pgrep -u tomcat拿到tomcat用户的所有PID再用-d,让pgrep用逗号拼接最后传给top -p。top -p支持一次指定多个PID以逗号分隔即可。这种方式比较适合两种情况一是只想观察某用户下的固定几个进程不想看该用户所有杂七杂八的东西二是想同时观察多个用户的关键进程比如把nginx和php-fpm的PID拼在一起看。不过-p有一个很明显的短板——PID集合是命令执行那一刻的快照。如果tomcat用户下的进程会不断变化比如PHP-FPM动态拉起worker、批处理任务不断创建子进程那么后面新启动的进程不会被自动纳入top的观察范围。这种动态场景用-u才合适。这个差异很关键后面单独展开说。2.4 三种姿势怎么选一张表说清楚方式命令/操作动态性多用户适用场景启动参数top -u 用户名动态匹配用户所有进程新版本top支持逗号分隔老版本可能不行日常定向查看、异常排查首选交互按键top运行中按u动态匹配用户所有进程一次只能一个用户已经打开top临时切换视角PID集合top -p $(pgrep -u 用户 -d,)静态快照新增进程不加入可以任意组合PID只看固定进程或跨用户组合绝大多数场景下top -u 用户名就是最优解它动态、直观、命令短。交互按键适合临时起意PID集合适合处理复杂组合需求。3. 看透用户进程的四个深化操作只用-u过滤出用户进程还不够很多问题需要联合top的排序、线程、字段和树形视图才能看清。这四个操作配合起来才算是真正看透了一个用户进程列表。3.1 用P/M/T重新排序把重点进程顶到最上面过滤出tomcat用户的所有进程后进程默认还是按CPU占用排序的。但有些场景下需要换排序维度。P按%CPU降序排列看谁在吃CPU最合适。M按%MEM降序排列马上就能找出内存大户。T按TIME累计CPU时间降序排列看长期占用CPU的进程。N按PID降序排列直观看到最新启动的进程。我排查用户进程时的习惯动作是先top -u 用户名然后按一次x。x会在当前排序列上做高亮标记这样我一眼就知道现在到底按哪个字段排的序不会盯着列表看了十几秒才反应过来排序字段不是自己想要的。如果想看某用户下谁的内存占用最大操作顺序就是top -u tomcat然后按M。列表立刻重新按内存排序干净利落。3.2 按H切到线程视图揪出单线程消耗进程级别只能看到整个进程吃了多少CPU但如果一个进程内部有几十上百个线程其中某一个线程把CPU打满整体显示可能就是%CPU达到200%多核场景你根本不知道是哪个线程在搞事。这时候就要用线程视图。两种方式进入线程模式top -H -p PID这条命令直接看某个进程的所有线程。另一种方式先top -u tomcat然后在top界面按H整个列表会切换成线程模式显示该用户所有线程。再次按H退出。在线程模式下PID列实际显示的是线程IDTID。如果你看到某个TID的%CPU明显高于其他线程基本就锁定了热点线程。这个TID在后面配合jstack排查Java问题时是极其关键的输入。3.3 用f定制字段和W保存做专属仪表盘top默认显示的字段足够应付大多数情况但做专项排查时有些字段加上去能省很多事。在top界面按f进入字段管理界面。上下移动光标选择字段空格键切换显示/隐藏右侧会有字段含义说明。我常用的定制是加这两列PPID父进程PID配合父子进程关系判断。TIME累计CPU时间看长期消耗。nTH进程内线程数判断线程数量是否异常。选定之后按q退回列表视图。如果希望以后每次打开top都用这套布局按W保存配置。top会把配置写到当前用户的~/.toprc文件里下次启动自动读取。这套组合很有用。比如我习惯在排查用户进程时只看这些字段PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME、PPID、COMMAND。列表更紧凑关键信息一目了然。3.4 按V打开树形视图理清父子进程当一个用户下挂着几十个worker进程时单看平铺列表很难分清谁是父进程、谁是子进程。top里按V可以切换到树形视图Forest View父子进程会通过缩进和连线关系展示出来。这个视图特别适合分析类似master进程worker进程架构的程序比如nginx、php-fpm、gunicorn。先用top -u nginx过滤再按V一下子就能看出哪个是master、哪些worker挂在它下面。如果想恢复平铺列表再按一次V即可。树形视图配合-u过滤还有一个好处由于列表里只有目标用户的进程树形结构不会被其他用户的进程打断父子关系看起来更清晰。不过要提醒一句如果过滤出来的进程数量特别多树形视图下缩进层级会占用不少屏幕宽度这时候小屏终端会很难受建议终端宽度调大一些再观察。4. 实战复盘用户进程CPU飙高的一次完整排查4.1 故障现象与初步判断一次线上告警某Java应用服务器load average飙到20以上业务方反馈接口响应明显变慢。登录服务器后的第一件事不是去看业务日志而是先确认到底是哪个用户、哪个进程在消耗资源。服务器上运行着tomcat用户的应用和mysql用户的服务两个都有可能。用默认top全局看界面太乱。这时候我直接执行top -u tomcat -d 1一下子锁定范围tomcat用户下只有两个Java进程其中一个的%CPU已经到780%另一个只有个位数。8核的机器一个进程吃掉将近8个核问题已经非常明确。4.2 用top -u圈定嫌疑进程在top -u tomcat的界面上按P按CPU重新排序按x高亮当前排序列确认那个高CPU的Java进程排在第一位。记录下它的PID假设为23140。到了这一步进程级别的结论已经出来了tomcat用户下的PID 23140的Java进程在疯狂占用CPU。但还不够因为一个Java进程内部有几十个线程我还想知道是哪段代码逻辑在烧CPU。先看进程内的线程视图top -H -p 23140 -d 1线程列表刷新后发现TID为23145的线程%CPU稳定在110%左右其他线程基本都在1%以下。热点线程锁定了。4.3 从线程ID一路追到jstack堆栈TID是十进制的jstack输出的线程栈里nid是十六进制的需要先做一次转换printf 0x%x\n 23145输出0x5a69然后对目标进程做一次线程栈输出再按nid过滤jstack 23140 | grep -A 40 nid0x5a69输出里能看到线程名是类似http-nio-8080-exec-55这样的业务处理线程栈顶停留在某个业务类的循环查询方法上。顺着代码一查果然是一个接口里对数据库做了逐条循环查询在高并发下CPU被打满。如果排查的不是Java应用或者没有JDK环境这个环节可以用strace -p 23145看系统调用或者perf top -p 23140看内核态热点。但对Java系的问题jstack是最直接的手段。4.4 恢复后的验证与观察确认根因后先把有问题的节点从负载均衡摘掉临时重启应用让线上恢复正常。随后对代码做了循环查询改批量的优化发布后再观察。恢复期间的验证动作很简单top -u tomcat -d 2盯着Java进程的%CPU是否回到个位数load average是否逐步下降。因为只用-u过滤tomcat用户下两个Java进程的变化一目了然不需要再从全局列表里分辨。这次排查从告警到定位根因总耗时大概十几分钟其中top相关操作占了初期的大部分时间。整个链路就是top -u一层一层缩范围核心价值在于把某个用户进程CPU飙高从模糊感知变成了精确定位。5. 版本差异与显示误区这几个坑踩过一次就不会忘5.1 批处理单帧输出的%CPU不可信很多人想把top接进脚本或定时监控里于是写了类似这样的命令top -b -n 1 -u tomcat-b是批处理模式-n 1是只输出一帧。初看好像能拿到快照但实际用起来会发现一个问题这一帧里的%CPU数据和你在交互界面看到的对不上。原因在于top的%CPU默认计算的是上次刷新到本次刷新之间进程消耗的CPU增量。交互模式下top有持续刷新这个差值很准确但-n 1只采样一次没有上一次的数据可用top只能退而求其次用进程启动以来的累计CPU时间除以存活时间来估算。这个值是个平均值不是实时值在脚本采集里基本没有参考价值。正确做法是取连续两帧丢掉第一帧用第二帧的数据top -b -n 2 -d 1 -u tomcat | tail -n 25-d 1意思是帧与帧之间间隔1秒。tail取末尾一段留下第二帧的输出。这套写法在做简易监控时够用也更接近你在交互界面上看到的真实数值。5.2 -u是动态匹配-p是静态快照这是我见过最容易混淆的一组参数。top -u tomcat是动态的它自己会持续匹配tomcat用户下所有存在的进程哪怕你观察期间tomcat用户又fork了新的子进程也会被自动加进列表里。但top -p $(pgrep -u tomcat -d,)是静态的。命令执行的那一刻pgrep抓到几个PIDtop就只看那几个PID一旦有新的worker进程启动不会自动进列表。如果观察窗口内有进程退出、又重新拉起新进程-p模式下的列表会慢慢只剩下一堆已经消失的PID数据就失真了。所以判断标准很简单观察对象是会变化的进程团比如php-fpm动态worker、批量任务子进程用-u观察对象是几个固定PID比如一个主Java进程的核心线程用-p更干净。5.3 多用户过滤和用户名不存在的坑新版的procps-ng top支持多用户过滤比如top -u user1,user2但也见过部分发行版或精简版top比如busybox环境不支持这种写法有的甚至连-u参数都不支持。跨环境操作时不要默认所有服务器行为一致建议先跑一条top -v确认版本或者直接分开执行。另一种常见问题是用户不存在。如果你输入的登录名在当前系统里不存在或者该用户是通过LDAP等外部认证源配置的top界面会显示空列表不会有任何提示。这时候可以先id 用户名看UID然后用UID过滤top -u 21001用UID还有一个额外好处不受用户名长度、字符大小写影响脚本里传参更稳定。5.4 有效UID、容器namespace带来的过滤误差top -u匹配的是进程当前的用户归属。极少数情况下一个普通用户启动的程序会通过setuid机制切换有效用户比如passwd这类命令运行时实际身份是root。如果遇到我启动的程序在-u 我的用户名里找不到这种诡异现象多半就是这类情况。容器环境下问题更隐蔽。如果容器没有隔离PID namespace你在容器里执行top看到的其实是宿主机的全部进程top -u root会把宿主机上所有root进程全列出来根本分不清哪些属于容器。如果容器做了PID namespace隔离top只看得到容器内的进程过滤意义反而不大。另外容器启用了user namespace做UID映射时进程显示出来的UID和宿主机未必一致。排查跨容器问题前先确认一下当前容器看到的UID上下文避免被数字误导。6. 把top -u改造成简易监控watch与批处理模式组合6.1 数行截断的watch方案前面提到批处理模式取第二帧才有参考价值这个特性可以和watch命令组合把一个固定的top视图变成持续刷新的监控面板watch -n 2 top -b -n 2 -d 0.5 -u tomcat | tail -n 25拆开看watch -n 2每2秒执行一次命令。top -b -n 2 -d 0.5批处理模式输出两帧帧间隔0.5秒。tail -n 25只保留末尾25行把第一帧输出丢掉留下第二帧的进程列表。这比直接watch top -u tomcat更靠谱因为watch里的命令是非交互的每次执行都是新进程单帧输出依然存在%CPU不准的问题。用连续两帧的方案能让监控数据更接近真实值。运行起来后屏幕会持续展示tomcat用户的进程列表每2秒刷新一次CPU、内存、TIME变化都看得清清楚楚。CtrlC退出。6.2 窗口宽度与折行问题批处理模式输出有多少列取决于终端宽度。如果当前终端窗口太窄top会在一行放不下字段时自动折行后续的tail、head、sed截取行数就会错乱监控面板变得难以阅读。解决办法有两种最简单的是在命令前面临时指定列宽COLUMNS180 watch -n 2 top -b -n 2 -d 0.5 -u tomcat | tail -n 25或者先执行export COLUMNS180让当前shell环境里的top都按180列排版。这样输出行的字段不会被截断进程名太长导致换行的问题也能规避。如果还想更精确地只提取进程数据行可以配合grep过滤top -b -n 2 -d 0.5 -u tomcat | grep -- ^ *[0-9]专门抓以数字开头的进程行。但这个方法在进程名因为长度折行时可能失效我一般还是优先把COLUMNS固定好。6.3 W不保存过滤条件与别名固化有一个细节很多人试过之后都会困惑在top里按W保存了配置重启top结果还是全量进程列表过滤用户的条件并没有被记住。原因在于W保存的是显示布局、排序字段、刷新延迟、是否线程模式这类偏好设置-u过滤条件是临时交互状态不会写入~/.toprc。如果想一打开top就自动盯住某个用户只能通过别名或脚本把参数固化。我个人习惯在~/.bashrc里加几个别名alias top-tomcattop -u tomcat -d 2 alias top-mysqltop -u mysql -d 2再进阶一点可以写一个通用脚本#!/bin/bash user${1:-tomcat} exec top -u $user -d 2保存到/usr/local/bin/top-monitor加执行权限之后想盯哪个用户就跑top-monitor mysql top-monitor www这套组合拳我在生产环境用了很久最明显的体感是把找进程的时间从几十秒降到几秒排查单线程问题时靠top -u加H基本是首选动作。读完这篇文章建议你找一台测试机把-u、H、V、f这些键逐一点一遍用熟了之后你会发现top这个老指令的潜力比想象中大得多。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →