首页 / 资讯中心 / 文章详情

pstree命令详解:用进程树一眼看清Linux进程父子关系

pstree命令详解:用进程树一眼看清Linux进程父子关系 ★ FEATURED ARTICLE
1. pstree到底解决什么问题1.1 系统管理员日常中的真正定位管理Linux服务器的时候我几乎每天都要面对同一个问题系统里到底在跑什么它们之间谁是谁的父进程谁又挂在谁下面。ps命令能列出所有进程但密密麻麻的数据量到了几百行眼睛扫过去很难看出层次关系。pstree这个命令就是把进程之间的父子关系用一棵树画出来一眼看穿整个系统的运行结构。pstree的全称是process tree它不关心每个进程占了多少内存、吃了多少CPU它只做一件事把进程作为树形节点展示出来。树根默认是systemdPID 1往下展开就是各类服务、会话、子进程。比如你用systemctl启动Nginx它会挂在systemd下用户在SSH里开bash又会挂在对应的sshd节点下。这种血缘关系在排查进程起不来服务反复重启有僵尸进程赖着不走这类问题时是无价的。1.2 pstree与ps的对比为什么需要一棵树ps命令能显示完整的信息但它默认是平铺的列表。你需要特意去看PPID列然后自己在脑子里拼出父子关系。进程少的时候还行但生产服务器上一跑起业务进程数动辄几百上千光靠ps排序去追血缘关系完全是灾难。pstree的价值就在于把关系前置你不需要自己去join PID和PPID它直接以缩进和字符连接符号展示出一棵树。有一次我的Tomcat容器启动后一直退出日志里什么错误都没有我用ps看到Tomcat进程在但完全看不出它是被谁拉起来的。后来用pstree -p一看发现Tomcat挂在一个supervise进程下面而supervise的配置写错了每次拉起后马上又杀掉。这个现象用ps很难定位但pstree一眼就点明了关系。2. 安装与基础用法2.1 各发行版的安装方式pstree属于psmisc软件包。绝大多数Linux发行版默认已经安装了它因为psmisc里面包含fuser、killall这些常用命令基本不可能缺席。但如果你的系统是最小化安装或者某些精简容器镜像可能没有Debian / Ubuntuapt install psmiscCentOS / RHEL / Rockyyum install psmisc老版本或dnf install psmisc新版本openSUSEzypper install psmiscAlpineapk add psmisc我在Docker容器里就踩过这个坑官方alpine镜像默认不带psmisc进容器想用pstree看进程关系结果command not found。装一下也就几秒钟的事但如果你是在离线内网环境就得提前把psmisc的安装包准备好。安装完成后验证输入pstree如果看到一棵以systemd开头的树说明环境正常。2.2 基本语法与参数总览pstree的语法很简单pstree [选项] [PID或用户名]不带任何参数时它从PID 1开始展示整棵进程树。参数可以是一个数字PID表示从那个进程开始往下展开也可以是一个用户名表示只展示该用户拥有的进程。常用选项我用一张表列出来方便你快速查阅选项作用典型使用场景-p显示每个进程的PID最常用追查父进程时离不开它-a显示命令行参数区分同名进程比如多个java进程跑不同jar包-h高亮当前进程排查单个PID时快速定位-H PID高亮指定PID所在路径调试服务启动链时首选-u显示用户切换看进程有没有降权运行-n按PID排序让树形结构更接近启动顺序-g合并进程组减少输出行数聚焦组间关系-c不合并相同分支保留完整的重复进程分支-l不截断长行输出量大的时候必开-A / -U指定连线字符集终端显示乱码时切换-z包含SELinux上下文有安全策略需求时用-T隐藏线程专注进程层级不被线程干扰-s显示指定进程的父链快速拿到血缘路径脚本里很好用这些参数看着多实际高频使用的就那么几个。我的日常组合是pstree -aplu展开所有细节定位具体问题时用pstree -H PID。3. 核心选项详解与实战3.1 -p把PID标在树枝上-p选项是pstree的灵魂功能。它会用括号标注每个进程的PID比如sshd(1024)──bash(2048)──php(3072)。没有-p的话你只能看到名字而排查问题往往需要拿PID去配合top、lsof、strace使用。一个特别实用的场景你在top里看到某个进程CPU占用异常记下它的PID然后跑pstree -p | grep 该PID就能找到它在树上的位置进而判断它是谁的子进程。如果是某个父进程fork出来的临时任务那排查方向就完全不一样了。需要注意一点pstree会把完全相同的进程合并显示标记为进程名*N。这是它的智能合并行为减少重复分支的刷屏感。但有时候合并反而掩盖了差异如果你发现nginx*4这样的标记想逐个查看每个nginx的PID可以用后面讲的-c参数。3.2 -a和-u区分同名进程多实例部署的时候最常见的困惑就是系统里有七八个java进程到底哪个对应哪个微服务-a参数能显示进程的完整命令行参数这让java -jar app.jar这种启动方式得以区分开来。我遇到过一件特别典型的事项目组在服务器上部署了三个Tomcat实例有人改完配置后重启了其中一个结果把另外两个也连带重启了。既然Tomcat都叫做java光看进程名根本分不清谁是谁。用pstree -a后每个java进程后面的-catalina.home参数清清楚楚哪个实例对应哪个目录一目了然。从此我再也不裸启Tomcat了每次启动都会先pstree -p -a确认当前实例。-u选项则负责显示进程权限切换。比如nginx的master进程是root运行worker进程自动降成nginx用户在pstree里就会看到nginx(root)──nginx(nginx)这样的结构。如果你发现某个进程意外以root身份运行了子进程这是安全审计里非常值得注意的红旗。3.3 -H高亮定位一条启动链当你拿到一个格外的PID想知道它到底挂在树的哪个位置在千行输出里用眼睛扫显然是低效的。-H参数可以直接让从根到该PID的路径高亮显示如果你的终端支持色彩。结合管道再配一个sed把颜色去掉或者保留效果都非常好。我第一次用这个功能是在排查Java微服务的启动顺序问题。A服务启动时依赖B服务但B服务没完全就绪A就启动了然后失败。通过pstree -H A服务的PID我能看到A是systemd直接拉的还是由某个shell脚本包装拉的还能看出A进程的父进程是否已经退出。这个信息直接改变了排查思路如果是systemd直管看systemd服务文件如果有包装脚本优先查脚本里的启动顺序逻辑。3.4 -c、-l与-g输出控制的三个细节默认情况下pstree会合并重复的进程分支——比如很多定时任务脚本都挂在cron下面如果它们命令行完全一样就会显示成脚本名*10这样一个节点。这种合并非常省版面但也意味着你无法直接拿到每个实例的PID。-c参数就是用来告诉pstree别给我合并老老实实把每个分支都列出来。-l参数解决的是长命令行被截断的问题。如果不加-l一个特别长的命令行可能只显示到某处就断了或者显示不完全。虽然用-c之后输出量会暴涨但配合管道处理时完整输出往往正是你需要的。还有一个和-l配合的点如果你的命令显示不完整检查一下终端宽度。pstree默认会参考终端宽度来换行如果宽度不够就可能截断。用-l强制整行输出后配合less -S横向滚动是处理超长进程树的经典组合。-g参数则用来合并同一个进程组里的进程。进程组的概念比较底层日常排查用得少但在你只想看清进程组间的层次关系、不想被组内大量的同类进程刷屏时pstree -g的输出会干净很多。3.5 -n和-p的叠加按PID排序展示默认情况下pstree把同一层级的进程按名称排序这方便按名字查找。但如果你更关心启动顺序可以加-n参数让同层级的进程按PID从小到大排列。Linux的PID分配是顺序递增的在未回绕的前提下所以PID越小通常启动越早。这个特性在排查谁先启动、谁后启动时很有用。-p和-n同时使用时效果是这样的所有子进程都带上PID并且子进程的排列顺序反映了它们的创建次序。我对服务编排的排查常常先用这个组合再看日志能节省不少时间。4. 实战案例从定位问题到一键体检4.1 场景一定位后台任务的父进程很多团队用nohup启动任务启动后任务脱离了当前终端。如果你忘了记录PID后来想找到它并且确认它没有被终端关闭信号影响pstree就能派上用场。假设你记得任务的命令行特征可以这样pstree -ap | grep mytask这样能看到mytask挂在哪个父进程下。如果它的父进程已经变成1systemd说明它确实脱离了会话基本不会再受SSH断开影响如果父进程是你自己的SSH会话bash那说明这次脱离不彻底SSH断了就有可能收到SIGHUP任务随时可能挂掉。这个判断在真实运维中非常关键。好几次同事们说我明明nohup了怎么断了SSH之后任务就没了我过去pstree一看任务的父进程还是那个bash根本没有真正脱离。原因通常是nohup只处理了标准输入输出或者在子shell里执行导致进程组关系不对。用pstree看到了真相再改用setsid或者systemd-run去启动问题就彻底解决了。4.2 场景二排查僵尸进程与孤儿进程Linux的僵尸进程Zombie会让系统飘着很多不死不活的占位符。ps能看到标着Z的进程但要说清楚它是谁的孩子、为什么不收尸pstree更直观。最简单的做法pstree -p 输出文件然后grep包含defunct标记的路径。但更常用的观测姿势是pstree -ap直接看带括号的PID找到目标进程后顺着它的父进程往上看确认父进程是否还活着。僵尸进程的产生是因为父进程活着但没有调用wait()收尸如果父进程已经死了僵尸会被1号进程PID 1领养由1号进程负责回收。如果你发现大量僵尸进程挂在一个特定的服务下面排查方向就很明确这个服务的代码里有子进程没被正确回收。老掉牙但一遍遍出现的问题pstree能帮你快速锁定嫌疑人。除去僵尸进程孤儿进程也值得用pstree确认。用脚本在后台启动一堆任务然后把父进程杀掉再pstree查看它们的归属你会看到它们全部挂到了PID 1下面。知道这一点你就明白为什么某些后台任务即使孤儿了也还能继续跑。4.3 场景三容器内进程树与PID命名空间Docker容器里看到的进程树和宿主机上的并不一样因为容器有自己的PID命名空间。在容器内运行pstree你会看到树的根部是容器的1号进程通常是java、nginx或entrypoint脚本而不是systemd——前提是exec进入容器时ls /proc是隔离的pstree本质上读取/proc目录来构建树。在容器里排查问题时容器内pstree的输出非常有价值。比如一个Java进程启动后你发现它有两个子进程一个成了僵尸另一个变成孤儿。顺势用pstree -ap确认它们的祖先是谁基本就能判定是容器entrypoint脚本对子进程管理不当。但有一点必须强调容器内的pstree不会显示宿主机上的其他无关进程-p看到的PID编号也是容器命名空间内的编号和宿主机的PID对应关系需要通过容器宿主侧ps配合确认。我见过有人拿着容器内的PID去宿主机上kill结果误杀进程这就是对PID命名空间理解不到位。用pstree的时候一定要清楚自己当前处于哪个PID名字空间。4.4 场景四与systemd服务的关系展示现代Linux系统上几乎一切服务的源头都是systemd即PID 1。pstree的第一行往往是systemd──...。你可以用它直观地检查某个systemd服务到底派生了哪些进程进程是否按预期组合在一起。有个常见需求查看某个服务的完整进程链。比如Nginx的worker数量是否符合配置pstree -ap | grep nginx一下一目了然。另一个需求是观察服务是否多级拉起用户服务可能通过systemd启动脚本脚本再启动一个子脚本子脚本才拉起真正二进制。这种链在pstree里会形成多级缩进从树形结构可以直接决定服务配置是否需要优化。4.5 场景五一键输出系统进程拓扑快照我平时巡检服务器习惯把进程树输出存成快照用来对比一段时间内系统进程的变化。设置一个cron任务每隔五分钟把pstree -apnu /var/log/pstree_snapshot_$(date %H%M).log积累几小时后对比后就会发现很多意外多出来的可疑进程、消失的服务、异常的重复分支等。有一次就是这样发现的服务器被植入挖矿程序的快照对比时突然多出一个奇怪的进程挂在crond下面而且它的父进程竟然不是crond的常驻分支。顺着pstree查父进程找到了被替换的定时任务脚本。当时如果没有历史快照排查时间会长很多。5. 常见问题与排查技巧实录5.1 输出乱码或显示问号有些终端编码下树形连线字符显示乱码。pstree默认使用ASCII字符并不是它默认根据环境自动选择。如果乱码试试-A参数强制使用ASCII字符或者-U强制使用UTF-8字符。ASCII字符在大多数SSH工具里的兼容性最好。我在Windows的MobaXterm、老版本Xshell上都遇到过连线乱码后来干脆在~/.bashrc里做了别名alias pstreepstree -A这样在任何终端下都不会出现乱码问题。5.2 输出太长怎么快速找到目标进程树一长直接翻屏根本翻不到头。高效的方法是配合greppstree -ap | grep -E nginx|php-fpm但grep会破坏树的缩进结构只返回匹配行。要想保留上下文可以用pstree -H 目标PID直接从根到目标节点的整个路径高亮展示这样纵览性最好。或者用awk、sed处理输出把PID提取出来pstree -p | awk /进程名/{print $0}注意pstree输出的是人类可读格式不是严格的分隔字段所以直接用cut有点麻烦用awk的正则匹配最省事。5.3 僵尸进程刷屏如何收场在大量僵尸进程的场景下pstree会显示很多[进程名] defunct字样的节点。这种节点不能直接kill杀掉僵尸进程本体没有意义——僵尸本身已经死了只是父进程没收尸。你要做的是处理父进程要么让父进程正常退出由1号进程收尸要么对父进程的代码打补丁让它正确调用wait()回收子进程或设置信号处理器。极少数情况下父进程长时间不处理子进程而你紧急需要清理僵尸可以选择重启父进程服务或者对父进程发送SIGCHLD信号但这不一定触发处理逻辑只是尝试。最彻底的还是代码层面修复。5.4 pstree -p的PID和top看到的PID对不上这是个常见的困惑。实际上二者应该是对的但如果你的终端宽度不够导致输出截断或者pstree把同名进程合并了PID显示和查询结果看起来就对不上。解决办法加-l强制完整输出加-c禁用合并再用pstree -apc | grep 目标PID对比。还有一种情况进程创建后又快速退出你top里看到的PID已经是新进程的但pstree里缓存的旧PID还没刷新。多跑几次pstree或者稍等片刻再对比即可。5.5 高版本Linux的线程显示问题Linux 5.x内核之后pstree的默认线程处理逻辑有时会变化。如果你只想看进程层级的组织不想被线程child threads淹没加-T参数。反之如果你想连带线程一起看可以配合其他参数。需要注意的是线程在pstree里也显示为子节点前缀与普通子进程相同容易混淆。但线程PID是独立的top里的TID和ps -eLf里的LWP都能对应上。在排查Java高CPU问题时经常需要把线程PID转换成十六进制去堆栈里找而第一步往往是先在pstree里确认该线程挂在哪个Java进程下。6. 与脚本结合的高阶玩法6.1 利用pstree做进程血缘审计自动化巡检脚本里pstree非常适合做血缘审计。一条命令就能判断某个服务是否以预期的父进程启动。比如要求所有业务进程必须挂在systemd的service单元下不允许用户直接nohup拉起来那么脚本里就可以写pstree -s 目标PID-s参数可以打印出从根到该PID的完整父链不需要pstree全量输出后再grep。这个参数在较新的psmisc版本中可用如果你的系统不支持可以用pstree -p | grep等替代手法。血缘审计的核心是抓住父进程这个信息。某个进程被人手工启动和通过systemd启动在pstree里呈现的树路径完全不同。我见过不少被入侵的服务器恶意进程大多以nohup方式被手工拉起的在pstree里它们完全暴露在正常服务的树结构之外。6.2 定时快照加diff检测异常前面提到快照对比具体可用脚本实现#!/bin/bash SNAP_DIR/var/log/pstree_snapshot mkdir -p $SNAP_DIR pstree -apc $SNAP_DIR/$(date %Y%m%d_%H%M%S).log # 清理超过7天的旧文件 find $SNAP_DIR -name *.log -mtime 7 -delete每天或每隔一段时间对比两个快照diff 前一个日志 后一个日志 | grep 新增的进程名这种方式的威力在于不需要像监控系统那样配置复杂的告警只需要在服务器上放一个cron任务就能对进程层面的变化保持敏感。对没有专职运维的小团队来说这种轻量体检性价比极高。6.3 进程数与关键节点的统计pstree输出的是文本可以用grep与wc做简单统计pstree -ap | wc -l统计总进程数粗略pstree -ap | grep -c 名称统计某一类型进程的数量pstree -ap | grep -c defunct统计僵尸进程数量这些统计指标可以用来自定义监控。例如当僵尸进程数量大于某个阈值时脚本发送告警我用crontab五分钟跑一次效果比看监控面板还直接。注意pstree会合并相同分支要统计真实数量记得加-c参数否则nginx*4只算一行。7. 一些踩坑与冷知识7.1 pstree真的只是读/procpstree的本质是遍历/proc目录下的每个进程目录读取PID、PPID等信息然后构建树。它是只读的操作不会修改任何进程状态也没有权限问题——普通用户就能看全所有进程的树结构不会像某些系统工具一样要求root。这一点为自动化脚本提供了很好的保障监控巡检时完全不用担心它影响性能。但也因为它是从/proc读取的在特殊的/proc挂载方式下如hidepid2普通用户可能看不到其他用户的进程。这种情况下pstree显示的不是完整树需要root权限才能看全。我在多用户服务器的安全配置里遇到过这个问题排查过很多次才反应过来是mount选项惹的祸。7.2 合并符号*n背后有哪些坑刚才提到pstree会合并相同的分支用名称N简化输出。这看起来省事但坑在于你看到php-fpm8并不代表有8个php-fpm在跑而是有8个同名进程其中可能有worker也可能有pool进程。要真正逐个查看必须加-c。此外-g可以合并同一进程组的进程减少行数但会牺牲一定细节。对审计场景我建议一律加-c宁可输出量大也不要漏信息。7.3 SELinux上下文与安全审计如果你的系统启用了SELinux可以加上-z参数让pstree显示安全上下文标签。在安全事件应急响应中把进程树与安全上下文结合分析能快速识别运行在非预期域中的进程。比如某个服务本应运行在httpd_t域里却出现在initrc_t或者其他奇怪的域这就是非常值得警惕的信号。当然大多数日常场景不需要过多关注更多是安全团队做应急响应时才会用。但至少知道有这个参数关键时刻不怕没工具用。我在实际使用中最大的体会是pstree这种命令单独看每个参数都很简单但把它们组合起来再放进真实场景里才能真正发挥价值。下次登录服务器查进程除了ps、top你不妨先敲一个pstree -ap说不定一眼就能看到答案。
阅读完成 · 觉得有帮助?
咨询建站