ARTICLE DETAIL

资讯详情

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

Linux进程查看实战手册:从ps到top的排障技巧

Linux进程查看实战手册:从ps到top的排障技巧 1. Linux下查看进程的核心思路在Linux服务器上排查问题的时候最常说的一句话就是看看进程在不在。这不是随口一问而是整个故障定位流程的第一步。不管是开发环境里启动的服务突然连不上了还是生产服务器负载飙高第一件事基本都是进终端敲一条进程查询命令把当前系统里跑着的东西摸清楚。Linux怎么查看进程这个问题的答案可以很简单一句ps -ef就能应付大多数场景。但这个命令背后的信息量其实很大每一列是什么意思、进程状态里的D和Z分别代表什么风险、为什么有些人会纠结ps aux和ps -ef的区别、怎么从一堆输出里快速定位你关心的那个应用。把这些细节吃透了排查问题的效率会高出很多。这篇内容我会从最常用的ps命令讲起把top、htop、pgrep、pstree这几个高频工具一并过一遍最后分享一些实际排障时才会用到的组合玩法。无论你是刚接触Linux的小白还是已经在服务器上摸爬滚打一阵子的运维应该都能找到对自己有用的部分。记住一个前提查看进程不是目的搞清楚进程的状态、资源占用、父子关系、是否异常才是目的。命令只是手段理解了背后的逻辑你才算真正掌握了这门基本功。2. ps命令拆解最经典的进程查看方式2.1 ps -ef 和 ps aux 到底有什么区别ps命令是Process Status的缩写几乎所有Linux发行版都自带。它最大的特点是快照式输出——运行命令的那一瞬间系统里有哪些进程它一次性列给你之后不会自动刷新。最常见这两种写法ps -ef ps aux这两个命令的输出格式略有不同但核心信息一致。-ef是Unix风格参数-e表示显示所有进程-f表示完整格式输出。aux是BSD风格参数a显示所有终端的进程、u显示进程所属用户、x显示没有控制终端的进程。实际输出长这样UID PID PPID C STIME TTY TIME CMD root 1 0 0 09:30 ? 00:00:05 /usr/lib/systemd/systemd root 342 1 0 09:30 ? 00:00:00 [kthreadd] root 521 1 2 09:32 ? 00:00:30 nginx: master process www 1024 521 0 09:32 ? 00:00:00 nginx: worker process这里每一列的信息值得记牢UID是这个进程跑在哪个用户下PID是进程唯一编号PPID是父进程编号C是CPU占用百分比STIME是启动时间TTY是关联终端?表示没有终端比如后台守护进程TIME是累计消耗的CPU时间CMD是完整的启动命令。小技巧如果你的系统里ps版本较老有些参数可能不兼容但-ef和aux这两套在主流发行版上都是通用的。2.2 看懂进程状态标记S、R、D、Z、Tps输出的STAT列在ps aux里是第8列是很多新手容易忽略但非常重要的信息。它用单个字母标记进程当前的状态状态标记含义风险等级R正在运行或可运行正常S可中断睡眠等待某事件正常D不可中断睡眠通常在等磁盘I/O需关注T已停止可能被CtrlZ挂起正常Z僵尸进程已退出但未回收需处理I空闲内核线程正常这里重点说D和Z。D状态的进程如果大量堆积通常是磁盘I/O出了瓶颈比如NFS挂载的存储有问题、磁盘坏道导致读写卡死这种状态很难用常规方式终止因为内核不让信号打断它只能等I/O恢复或者重启机器。Z状态的僵尸进程更常见一些。它代表子进程已经退出但父进程没有调用wait()系统调用去回收它的资源。少量僵尸进程其实无所谓但如果积累太多会耗尽系统进程表导致无法创建新进程。遇到这种情况重点不是杀僵尸进程本身杀不掉而是要找到它的父进程让父进程去回收。# 查看僵尸进程及其父进程 ps -ef | grep defunct ps -o pid,ppid,stat,cmd -A | grep -i defunct如果父进程是initPID 1僵尸进程通常会被自动收养清理如果父进程是你自己的某个应用那就得检查应用的子进程管理逻辑是不是出问题了。2.3 自定义输出列只看你想看的信息默认的ps输出列有时候信息太多反而干扰判断。可以用-o参数精确控制输出哪些字段# 只看PID、父进程PID、CPU、内存、启动命令 ps -eo pid,ppid,%cpu,%mem,cmd --sort-%cpu # 按内存占用排序前10个进程 ps -eo pid,ppid,%mem,rss,cmd --sort-rss | head -10这里的rss是物理内存占用单位KB排查内存泄漏的时候这个字段比%mem更直观。--sort后面跟字段名加负号表示降序排列。还有一个高频场景找某个具体进程。用管道加grep是最简单粗暴的方式ps -ef | grep java但注意这样会把grep java这个命令本身也匹配进去输出里会多一行带grep的进程。想过滤掉它可以用ps -ef | grep java | grep -v grep # 或者用pgrep更优雅 pgrep -lf javapgrep是专门为进程搜索设计的命令-l显示进程名-f匹配完整命令行而不是只匹配进程名。比如你想找一个Spring Boot应用进程名可能叫java但命令行里带了-jar app.jar参数这时候pgrep -f就非常管用。3. top和htop动态监控进程资源占用3.1 top的基本操作手法ps是静态快照看一眼就完事。但很多场景下你需要持续观察进程的CPU和内存变化比如某个服务刚启动时一切正常跑了半天内存持续上涨这时候就需要动态监控工具。top是系统自带的不需要额外安装用法也简单top进去之后默认按CPU占用排序每3秒刷新一次。常用交互快捷键P按CPU占用排序M按内存占用排序k终止进程输入PID后会让你选择信号r修改进程优先级nice值c切换显示完整命令行q退出top输出的第一行是系统概况当前时间、开机时长、登录用户数、系统平均负载。这里要特别解释一下load average后面的三个数字分别代表1分钟、5分钟、15分钟的平均负载。注意负载不等于CPU使用率它表示处于可运行状态和不可中断状态的进程平均数。粗略判断的话负载持续高于CPU核心数说明系统过载可能在排队。在排查CPU飙高问题时我习惯先看一眼top的%Cpu行区分用户态和内核态占用。us高通常是应用本身在大量计算sy高可能是系统调用频繁wa高则是I/O等待导致的处理思路完全不同。3.2 htop比top更友好的交互界面htop不是系统默认安装的在CentOS系可以用yum install htop安装Debian系用apt install htopmacOS上也可以用brew install htop。如果你第一次用会被它的界面惊艳到顶部有CPU和内存的进度条进程列表可以用方向键上下选择F键功能菜单也比top直观得多。htop比top强的地方主要是交互体验可以用F5键把进程切换成树形视图父子关系一目了然F6键按任意列排序F9键直接终止选中的进程不用手动输入PID。遇到需要频繁切换查看维度的场景htop确实比top顺手。不过要提醒一句线上生产环境不一定允许你随便装htop所以top的熟练度还是得有毕竟几乎每台Linux机器上都预装了它。3.3 用top定位真正的性能瓶颈分享一个实际排障的案例。有一次线上Java应用响应变慢我登上服务器先跑了top看到的情况是%CPU并没有很高但load average到了8左右。再细看wa这一项占到了30%以上基本可以判断瓶颈在磁盘I/O而不在CPU或内存。紧接着我用top按M排内存发现有个日志收集进程占了接近20G内存这明显不对劲。进一步排查发现它的日志文件在疯狂增长定位到是日志轮转配置失效导致的。虽然这不是查看进程单独能解决的问题但top在定位方向上帮了大忙。所以我的习惯是先top看全貌再ps精确查进程详情最后根据线索用lsof、strace这些工具深挖。进程查看只是第一步但这一步做扎实了后面能省很多时间。4. 进程树和父子关系pstree的巧妙用法4.1 为什么要关心进程的父子关系大多数进程都不是凭空产生的它们有明确的父子层级。systemdPID 1是系统的第一个进程所有服务都由它直接或间接启动。了解这个层级关系能帮你解答一系列问题这个进程是谁拉起来的、它在哪个服务组里、杀了它会不会连带影响其他进程。pstree命令能把进程树直接画出来比ps的PPID列直观得多pstree -p输出大概是这样的systemd(1)─┬─NetworkManager(860)─┬─dhclient(1196) │ └─dnsmasq(2184) ├─nginx(1024)──┬─nginx(1025) │ └─nginx(1026) ├─sshd(1059)───sshd(2088)───bash(2089)───vim(2100)加上-p选项会在进程名后面显示PID加上-a可以显示进程的完整启动参数。想单独看某个进程的子树在后面加进程名或PIDpstree -ap 1024这条命令会显示PID 1024nginx主进程以及它的所有子进程。排查为什么nginx的worker进程全挂了只剩master这类问题用这招最直接。4.2 从孤儿进程到systemd的守护逻辑有一种特殊情况叫孤儿进程父进程先退了子进程还没退出。此时内核会把孤儿进程过继给PID 1也就是systemd老系统是init。这就是为什么你看到的很多后台进程的PPID是1。这个机制本身是Linux的兜底设计保证每个进程都有父进程可供资源回收。但反过来想如果某些进程你希望它保持独立却发现它的父进程变来变去说明你的进程管理逻辑可能有问题。比如某个脚本用启动子进程后就退出了子进程成了孤儿后续想管理它就比较麻烦。这也是为什么在生产环境推荐用systemd来管理服务而不是裸奔脚本——至少进程树是可控的。5. 一键定位工具pgrep和pkill的配合使用5.1 pgrep按名字和属性找进程pgrep用起来比ps | grep干净得多它直接输出匹配的PIDpgrep nginx # 输出实例PID一行一个加上-l会在PID旁边显示进程名加上-a显示完整命令行。更强大的是-u按用户过滤、-U排除某用户、-x精确匹配进程名避免nginx匹配到nginx-worker这种不是很想要的。举一个比较典型的组合场景# 查看root用户下所有名字包含python的进程 pgrep -u root -a python # 查看java进程占用的PID方便后面用jstack pgrep -f java.*app.jar这里-f的威力需要多说一句普通pgrep java只能匹配进程名里带java的但用-f可以匹配整条命令行。很多应用启动脚本是sh -c方式调起java的进程名不一定是java用-f才找得到。5.2 pkill定位之后顺便干掉pkill和pgrep是配套的两者的匹配逻辑完全一样只是动作不同——一个是列出PID一个是发信号。最常用的场景是重启某个服务的进程组pkill -f java.*app.jar默认情况pkill发送的是TERM信号相当于请求进程优雅退出。如果进程不响应再用KILL信号强制杀pkill -9 -f java.*app.jar这里必须严肃提醒一件事pkill -f是双刃剑。-f匹配的是整个命令行如果匹配模式写得太宽可能误杀其他进程。我知道的就有个事故案例某人执行pkill -f test想把测试进程杀掉结果把自己也在命令行上带test字样的生产环境的shell窗口全杀了服务直接被中断。建议执行pkill -f之前先用同样的参数跑一遍pgrep -f看看到底会命中哪些进程。5.3 kill命令的常用信号表kill命令配合-l参数可以查看所有信号列表但日常运维记住这几个就够了信号数字行为场景TERM15请求正常终止默认信号先礼后兵KILL9强制终止不可阻塞进程无响应时用HUP1挂断常用于重载配置重新读取配置文件而不中断进程STOP19暂停进程临时冻结进程CONT18恢复暂停的进程继续运行被STOP的进程比如nginx修改了配置想让配置生效不用重启进程直接kill -HUP $(cat /var/run/nginx.pid)。很多服务都把当前进程的PID写到/var/run/下的pid文件里方便外部管理。6. 实操案例从查看到定位的全流程演示6.1 场景Java应用内存持续上涨怎么入手你接手一台服务器跑了部署在Tomcat里的Java应用这两天发现它的内存一直在涨重启能好一阵子过两天又涨上去了。这个时候进程查看工具就是第一把刀。第一步确认进程基本信息# 找到Java进程的PID ps -ef | grep tomcat # 假设PID是8853 # 看这个进程的资源占用趋势 top -p 8853top -p可以只监控指定PID比看全局输出更聚焦。持续观察几分钟如果RES列物理内存稳步上涨说明确实存在内存泄漏嫌疑。第二步确认线程层面的情况# 看进程的线程数变化 top -H -p 8853-H选项会把线程也展开显示如果线程数异常增多可能是在循环创建新线程没释放。第三步配合其他工具深挖# 统计线程数量 ls /proc/8853/task | wc -l # 查看打开文件数 ls /proc/8853/fd | wc -l这里用到的是/proc虚拟文件系统。每个进程在/proc下都有一个以PID命名的目录里面存放着这个进程的实时信息包括task目录线程、fd目录文件描述符等。进程查看不只是看命令行的输出直接读/proc也是资深工程师常用的路数。6.2 场景端口被占用找到底是哪个进程启动服务时报端口被占用这个坑应该是很多人踩过的。排查思路分两步先看端口监听状态再反向找进程。# 查看哪个进程占用了8080端口 ss -lntp | grep 8080 # 或者用lsof lsof -i :8080ss -lntp的输出里有users:((java,pid8853,fd13))这样的字段直接告诉你PID是8853。拿到PID之后再ps -fp 8853看详细信息就能确认这个进程是什么、启动参数是什么。如果lsof没安装可以用更朴素的方式# 通过netstat查PID老系统常见 netstat -lnpt | grep 8080 # 直接查/proc ls -l /proc/8853/fd | grep socket有些情况下你查到占用端口的进程是个僵尸进程端口一直被它占着但进程已经死了这时候正常kill是杀不掉的需要先把进程状态搞清楚再决定处理方案。6.3 场景批量操作同一类型的进程假设你是从CDH或ElasticSearch集群上做维护同一组进程在多台机器上跑想统一重启某个组件的所有worker进程。分步操作如下# 先精确匹配研究对象 pgrep -f elasticsearch.*worker # 确认无误后优雅停止 pkill -f elasticsearch.*worker # 确认进程是否真的退出了 pgrep -f elasticsearch.*worker || echo 进程已全部退出 # 如果需要检查残留把Z状态的也找出来 ps -ef | grep elasticsearch | grep defunct这里挂上||判断的好处是有反馈输出脚本化的运维操作里这个细节很加分。我见过很多人在脚本里直接pkill然后不管结果进程没杀掉也没感知到后续服务必然出问题。7. 调度监控场景如何实时捕捉进程的活动7.1 用watch命令定期刷新ps输出ps是快照但你想要一个持续更新的快照效果时不必非用top。把watch和ps组合起来是个非常灵活的自定义监控方案# 每2秒刷新一次Java进程列表 watch -n 2 ps -ef | grep java | grep -v grep # 每秒刷新一次CPU前5的进程 watch -n 1 ps -eo pid,comm,%cpu --sort-%cpu | head -6watch -n指定刷新间隔秒后面跟的命令用引号包起来。这种方式的自由度比top高很多你可以把管道、排序、过滤任意组合想看什么形状的输出都能定制。排查问题时把关键监控放在一个终端里挂着另一个终端做操作效果非常直观。7.2 前台进程与后台进程的处理逻辑监控前台进程这个说法可能让人困惑。Linux里的前台进程指的是当前终端正在交互运行的进程占用终端输入输出后台进程则是在末尾加启动的或者通过nohup、systemd等方式脱离终端运行。查看当前后台任务用jobs -l把后台任务调回前台用fg %1这里的%1是任务编号。不过这些操作仅限于当前shell会话里启动的任务重启终端后jobs列表就没了。如果是系统服务进程的归属关系要看systemd比如# 列举所有服务进程 systemctl list-units --typeservice # 看某个服务的状态 systemctl status nginxsystemctl status的输出的一个亮点是它会显示这个服务的进程树和资源占用排查服务明明显示active但进程怎么没了这类问题非常好使。7.3 从进程监控延伸文件与连接排查三板斧进程不是孤立的它一定会和文件、网络打交道。排查问题的完整链路是进程 → 打开的文件 → 网络连接。比如进程运行缓慢可能是它在等待某个文件锁也可能是它在等待一个网络响应。相关的三条命令值得放在一起记# 进程打开了哪些文件 lsof -p 8853 # 进程当前的网络连接 lsof -i -a -p 8853 # 进程的工作目录 ls -l /proc/8853/cwd/proc/8853/cwd是个符号链接指向进程的工作目录。为什么这个有用遇到进程读取了错误路径下的配置或者日志文件落在意外位置的情况可以通过它直接确认进程启动时的工作目录。操作时一条命令就能定位问题源头。8. 多维度极客玩法自定义进程监控工具箱8.1 从文件描述符到线程统计的连环招式如果要给我认为排查进程问题时最有价值的/proc信息排个序大概是stat进程状态、status汇总信息、fd文件描述符、task线程个数、environ环境变量、cmdline命令行。# 一行命令查看进程的完整环境变量 cat /proc/8853/environ | tr \0 \n | grep -i java_home # 查看进程的启动时刻判断是不是这次部署的 ps -o lstart -p 8853 # 查看所有线程的状态分布 for t in /proc/8853/task/*; do cat $t/stat 2/dev/null | awk {print $3} ; done | sort | uniq -cenviron文件里各个键值对之间用空字符分隔所以要用tr \0 \n把它转换成一列一行。用它确认某个进程实际拿到的环境变量排查为什么我设置了JAVA_HOME但应用没生效这类问题尤其好用。8.2 进程状态字母的进一步细分ps输出的STAT列有时候是两个字符比如Ss、R、D。第一个字符是主状态第二个字符是修饰符修饰符含义s会话领导者通常是终端的主进程位于前台进程组l多线程进程高优先级nice值为负N低优先级nice值为正看到Ss说明它是一个会话的头进程且正在睡眠则说明它在终端前台运行。了解这些细节能帮助你判断进程的运行方式是否符合预期比如java进程如果被标成R而你又没有在终端前台跑它那说明它的启动方式可能和你预期的不一样。8.3 与线程概念的区分对比讨论进程查看绕不开线程与进程这个话题。简单理解进程是资源分配的最小单位线程是CPU调度的最小单位。同一个进程内的多个线程共享内存空间、文件描述符但各自有独立的栈和寄存器状态。Linux下用ps -eLf可以看线程级的信息其中NLWP列是线程数每行对应一个线程。查看进程里的线程对定位多线程应用的问题很重要比如Java应用出现死锁通常要配合jstack把现场dump出来。日常排查时如果你发现一个进程CPU占用很高但代码逻辑上不应该这么高可以用以下命令定位线程# 统计进程的线程数 ps -o nlwp -p 8853 # 看每个线程的资源占用 top -H -p 8853top -H会列出所有线程以及它们各自的CPU占用再结合jstack打印的线程名和方法栈就能精准定位到是哪个业务线程在空转。9. 常见问题与排查技巧实录9.1 ps命令找不到或权限不够怎么办有次在一台精简过的容器镜像里执行ps -ef直接提示bash: ps: command not found。这种场景多出现在基于Alpine的Docker容器里它默认没有安装procps工具包。解决办法是# Alpine系 apk add procps # Debian系 apt install procps # CentOS系 yum install procps-ng如果连ps都装不了还有一个备选方案直接读/proc目录。ls /proc | grep -E ^[0-9]$这些数字目录就是当前系统的PID进去看里面的comm文件就知道进程名看cmdline文件可以拿到命令行。这个方法在极端精简环境下很管用。9.2 为什么ps里看到的时间比实际长有网友提过一个困惑ps -ef输出的TIME列为什么比自己启动到现在的时间要长这里有个误解需要澄清一下。TIME列显示的是进程累计消耗的CPU时间而不是墙上时钟时间wall clock time。比如一个进程启动了一个小时但实际只用了5秒CPU那TIME列就是00:00:05。如果进程大部分时间在等待I/O或睡眠CPU时间自然比实际运行时间短很多。反过来某个进程启动才10分钟TIME已经攒了8分钟说明它几乎一直在消耗CPU这通常是性能瓶颈的重要信号。同理ps aux里的%CPU是进程CPU时间占墙钟时间的比例数值可能大于100%多核环境下如果进程有多个线程在跑高概率会看到150%甚至300%。9.3 僵尸进程清理的完整方案僵尸进程的清理是经典场景前面说过它杀不掉关键在父进程。具体流程分这几步# 第一步找到僵尸进程及其父进程 ps -ef | grep defunct # 第二步看父进程是什么 ps -fp PPID # 第三步如果父进程还在正常运行试试向它发TERM信号 # 让它自己处理子进程回收 kill -TERM PPID如果父进程是个长期运行的核心服务不能随便重启那只能接受僵尸进程存在的事实。它们占用的资源很少只要数量不持续增长就影响不大。但如果父进程本身退出了僵尸进程会被systemd收养并清理通常会自动消失。还有一种极端情况僵尸进程的父进程也是僵尸。这会导致系统进程表条目无法释放碰到大量这种嵌套僵尸最简单有效的办法是重启机器。虽然粗暴但在进程表耗尽前处理是最理智的决策。9.4 进程名看着像但其实是假的现在容器和微服务普及之后进程名伪装的问题也多了。比如有个恶意程序叫nginx但实际路径在/tmp下面怎么看ps -ef里只看进程名可能会被骗需要看完整路径# 列出带路径的完整命令行 ps -eo pid,ppid,user:20,args # 查看进程的可执行文件真实路径 ls -l /proc/PID/exe/proc/PID/exe指向进程运行的实际可执行文件。如果nginx进程的exe指向的是/tmp/...这种非标准路径基本可以断定有问题。排查安全事件时这个技巧出现的频率相当高。另外也可以用ls -l /proc/PID/cwd看工作目录以及/proc/PID/root看进程视角下的根文件系统是否被劫持。9.5 拿到进程PID后进一步运维的常用动作查看进程的终点往往是管理进程把几个高频操作串一遍# 调整进程优先级nice值让它在低负载时段运行 renice 10 -p 8853 # 临时暂停进程 kill -STOP 8853 # 恢复进程 kill -CONT 8853 # 查看进程的启动时间 ps -o lstart -p 8853 # 查看进程是否在响应命令 kill -0 8853 echo 进程存活这里重点说下kill -0这个用法。它不会真的向进程发送信号只是检测进程是否存在且当前用户是否有权限。脚本开发中用它判断进程状态是个非常稳的做法比ps -p $PID更轻量也不容易产生误判。10. 结束语我个人在实际操作中的体会是进程查看命令用得熟不熟练直接反映了一个人对Linux系统底层的理解程度。ps的命令参数就那么几个但配合上/proc文件系统、top的交互快捷键、pgrep的灵活匹配你能组合出来的排查手段其实非常多。关键还是要形成自己的拆解思路先看整体还是先查目标进程状态反映的问题属于哪一类下一步该往哪个方向深挖。最后再分享一个小技巧在你日常操作烦琐的机器上把常用的进程查看组合写成shell别名或函数比如alias pscpups -eo pid,user,%cpu,%mem,cmd --sort-%cpu | head -20省得每次敲一长串。工具本身不复杂复杂的是通过它们把问题定位得又准又快这个能力多练几次就会有质变。
返回列表