概述
问题背景:基于golang 实现了一个自助化配置的通用命令任务管理模块,这样运营人员可以直接通过修改配置,完成 if do 的命令逻辑:当磁盘满时,做什么?当网卡down 时做什么;并且可以支持各类环境 和规则。
确定僵尸进程问题:
但是灰度后不久,命令执行报错: fork exec resource temporarily unavailable;
进一步查看syslog 报错 fork rejected by pids controller in xxx.service,cat pid limits 查看上限,也就是说,进程fork 出错 service 控制上限了
执行 ps -ef |grep -c pid 发现service 创建了太多进程 ,大部分都变成了Z状态,另外通过top 也可以看到 zombile 个数
我们知道僵尸进程是子进程退出,父进程没有wait 捕捉状态;配置了多个命令,每分钟 每30秒执行一次,为什么大部分僵尸进程是 wc 和grep 呢?即:不是所有命令执行变成了僵尸进程,而是某一部分命令变成了僵尸。
通过分析这些特殊的命令有助于缩小命令调用变僵尸进程的bug代码范围:
确定僵尸进程的命令特征
一种方式是:注释配置 使用排除法,但是效率太低;
另一种方式使用动态追踪方式 来查看具体僵尸进程(不断在产生),以grep僵尸进程为例:
python execsnoop.py -n grep -T |grep 父进程 -B 1
execsnoop 通过getppid,/proc/pid/status 中的ppid 来获取父进程,但是有时候命令马上执行完就退出了,难以获取祖父进程等,另外获取打印参数也是一个问题;实际上 有时候我们需要追踪到最开始的进程,因此稍作修改:
for (int i = 0; curr_pid != 1 && i < MAX; i++) {
curr = curr->real_parent;
curr_pid = curr->tgid;
data.ppid[i] = curr_pid;
bpf_probe_read(&c, sizeof(c), curr->comm);
comm_cache.update(&curr_pid, &c);
}
cmd pipeline 的问题
从上一步 可以明确是 cmd pipeline 的问题;当pipe line 的命令都执行成功时,不会出现Z,但是当前面有进程异常退出时,后面的wc 等命令出现了Z
https://stackoverflow.com/questions/36050503/golang-child-processes-become-zombies
func RunCmds(maxtime int, cmds []*exec.Cmd) error {
// start processes in descending order
for i := len(cmds) - 1; i > 0; i-- {
cmds[i].SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
if maxtime == 0 {
maxtime = 600
}
time.AfterFunc(time.Duration(maxtime)*time.Second, func() {
if cmds[i].Process != nil {
syscall.Kill(-cmds[i].Process.Pid, syscall.SIGINT)
syscall.Kill(-cmds[i].Process.Pid, syscall.SIGKILL)
}
})
if err := cmds[i].Start(); err != nil {
return err
}
}
// run the first process
if err := cmds[0].Run(); err != nil {
return err
}
// wait on processes in ascending order
for i := 1; i < len(cmds); i++ {
if err := cmds[i].Wait(); err != nil {
return err
}
}
return nil
}
仔细阅读:start run wait 接口:
start 会调用os.StartProcess 创建一个新的进程 也是cmd.Process, 而wait 相当于等待子进程退出 清理资源,wait 等待子进程退出 或者 stdin stdout copy complete. 所以类似wc -l 等命令得以继续等待stdin 而不退出,但是直接wait 会 使得wc -l 退出(待确认)
所以一定要 wait start后的进程,否则会产生僵尸进程,pipeline 更好实现方式可以参考 上面stackoverflow 连接
如何通过扩展自己的知识面来提升工作效率;单纯的动态追踪命令,仅在排查谁调用了命令时使用,想不到在排查命令导致的僵尸进程时正好可以用到
最后
以上就是激昂黄豆为你收集整理的golang exec cmd pipeline zombile 进程的全部内容,希望文章能够帮你解决golang exec cmd pipeline zombile 进程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复