300 多个服务跑在一台机器上 我怎么知道谁在干活

我的一台机器上跑着 300 多个进程。 定时器 守护脚本 各种助手和流水线。 都是这几年一个一个攒上去的 攒的时候没觉得多 有一天凌晨内存告警了。
告警本身不吓人 吓人的是我答不上一个问题。 这 300 个进程里 哪些是真活儿。 哪些是早就该退出的残骸 我居然一个都说不清
第一反应很简单 重启不就完了 但我忍住了 因为上一次重启之后 问题过了半个月又回来。 说明有个东西一直在悄悄吃内存 我没找到它。
那天晚上我决定不重启 把它揪出来。 先说结论 我找到的是一个孤儿进程。 一个早就该退出的老脚本 母进程死了 它没死 挂在那慢慢吃内存。
但比找到它更值钱的 是找到它的办法。 因为这台机器上 300 个进程里 起码有一半名字长得差不多 谁是正经活儿 谁是僵尸 看名字根本看不出来。
我先用了最笨的办法 看列表 ps 一敲 屏幕滚了十几屏 看得眼晕 唯一的收获是知道总数对不上。 进程数比我以为的多出一截
对不上的那截 就是问题 我把思路换了一下 不挨个看 而是按问题倒着查 内存不是平均吃的 总有几行特别高
排序之后 前几名里有三个名字眼熟 眼熟是因为名字是同一种脚本 只是参数不同 问题来了 它们是三个人还是同一个人的三个马甲。
这一步我用了一招 看家谱 Linux 上每个进程都有父进程 用 pstree 把树拉出来 一眼就能看出谁是谁的孩子
正常的服务 家谱是干净的 主进程管着一两个子进程 子进程干完活就退 树很整齐 像个正常的组织架构图
孤儿进程的形态一眼就能认出来 它的父进程位置是空的或者是 1 意思是它亲爹早没了 它被系统收养 却还占着原来的资源
那三个高内存的进程 一查就是孤儿 同一个脚本的三次残骸 三次都是跑完没退出 母脚本已经更新过三版 它们仨还挂着旧版本。

找到之后我先没杀 做了个验证 看它们的启动时间 三个时间正好对上三次脚本更新的日子。 时间线对上了 这个判断就有底气了
但真正的坑在后面 我以为孤儿只有这三个 用同样方法扫了一遍 又扫出十几个小的
加起来的内存 比那三个大的还多 这就是这类问题最烦的地方 单看每一个都不痛不痒 合在一起才是告警的真正来源
教训很具体 脚本退出这件事不能靠自觉。 我的老写法是脚本干完活 自己 end。 一旦中间异常退出 子进程就成了孤儿。 后来我在每个脚本外面包了一层超时兜底。 到点没退 连子带孙一起收
杀完之后我又干了三件事 第一 把清扫逻辑写成了定时检查 每天看一遍孤儿数 第二 给长驻脚本统一加了超时参数 第三 把这套排查步骤写进了交接文档。
现在回头看 那晚最有用的不是那十几条命令。 是三个判据 可以直接拿走 第一 看父进程 孤儿的爹一定是空的或者 1。 第二 看启动时间 对不上版本时间的都可疑。
第三 也是最反直觉的一条 不要只盯着内存最高的那个 要盯着名字相似的那一组 机器上真正吃内存的 往往不是一个大怪兽。 是十几个看起来无害的小残骸
如果你也管着一台进程越来越多的机器。 我建议你现在就做一件事 把进程树拉出来扫一眼 重点看父进程是 1 的那些 它们多半是某次异常退出留下的孤儿
内存告警会过去 但孤儿不会自己消失。 我那台机器 清完之后稳定运行到现在。 每天定时检查 只需要看一个数字 机器不需要聪明 它需要有人替它记账。
是为记
最后说一句心态上的变化 以前我总觉得进程多了是机器老了 该换机器。 现在我知道 大多数时候不是机器老 是我欠的账没人替我记