1.1 踩坑案例

踩坑的程序是个常驻的Agent类管理进程, 包括但不限于如下类型的任务在执行:

  • a. 多线程的网络通信包处理

    • 和控制Master节点交互
    • 有固定Listen端口
  • b. 定期作业任务, 通过subprocess.Pipe执行shell命令
  • c. etc

发现坑的过程很有意思:

  • a.重启Agent发现Port被占用了

    • => 立刻

      想到可能进程没被杀死, 是不是停止脚本出问题

      • => 排除发现不是, Agent进程确实死亡了
      • => 通过 netstat -tanop|grep port_number 发现端口确实有人占用
    • => 调试环境, 直接杀掉占用进程了之, 错失首次发现问题的机会

  • b.问题

    在一段时间后

    重现

    , 重启后Port还是被占用

    • 定位问题出现在一个叫做xxxxxx.sh的脚本, 该脚本占用了Agent使用的端口

      • => 奇了怪了, 一个xxx.sh脚本使用这个奇葩Port干啥(大于60000的Port, 有兴趣的砖友可以想下为什么Agent默认使用6W+的端口)
      • => review该脚本并没有进行端口监听的代码
  • 一拍脑袋,

    c.进程共享了父进程资源

    • => 溯源该脚本,发现确实是Agent启动的任务中的脚本之一
    • => 问题基本定位, 该脚本属于Agent调用的脚本
    • => 该Agent继承了Agent原来的资源FD, 也就是这个port
    • => 虽然该脚本由于超时被动触发了terminate机制, 但terminate并没有干掉这个子进程
    • => 该脚本进程的父进程(ppid) 被重置为了1
  • d.问题出在脚本进程超时kill逻辑

1.2 填坑解法

通过代码review, 找到shell具体执行的库代码如下:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
self._subpro = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE,preexec_fn=_signal_handle
)
# 重点是shell=True !

把上述代码改为:

self._subpro = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE,stderr=subprocess.PIPE, preexec_fn=_signal_handle
)
# 重点是去掉了shell=True

1.3 坑位分析

Agent会在一个新创建的threading线程中执行这段代码, 如果线程执行时间超时(xx seconds), 会调用 self._subpro.terminate()终止该脚本.

表面正常:

  • 启用新线程执行该脚本
  • 如果出现问题,执行超时防止hang住其他任务执行调用terminate杀死进程

深层问题:

  • Python 2.7.x中subprocess.Pipe 如果shell=True, 会默认把相关的pid设置为shell(sh/bash/etc)本身(执行命令的shell父进程), 并非执行cmd任务的那个进程
  • 子进程由于会复制父进程的opened FD表, 导致即使被杀死, 依然保留了拥有这个Listened Port FD

这样虽然杀死了shell进程(未必死亡, 可能进入defunct状态), 但实际的执行进程确活着. 于是1.1中的坑就被结实的踩上了.

1.4 坑后扩展

1.4.1 扩展知识

本节扩展知识包括二个部分:

  • Linux系统中, 子进程一般会继承父进程的哪些信息
  • Agent这种常驻进程选择>60000端口的意义

扩展知识留到下篇末尾讲述, 感兴趣的可以自行搜索

1.4.1 技术关键字

  • Linux系统进程
  • Linux随机端口选择
  • 程序多线程执行
  • Shell执行

1.5 填坑总结

  1. 子进程会继承父进程的资源信息
  2. 如果只kill某进程的父进程, 集成了父进程资源的子进程会继续占用父进程的资源不释放, 包括但不限于
    • listened port
    • opened fd
    • etc
  3. Python Popen使用上, shell的bool状态决定了进程kill的逻辑, 需要根据场景选择使用方式

Python 之杀不死的Shell子进程相关推荐

  1. python shell下载很慢_Python踩坑之旅其一杀不死的Shell子进程

    1.1 踩坑案例 踩坑的程序是个常驻的Agent类管理进程, 包括但不限于如下类型的任务在执行:a. 多线程的网络通信包处理和控制Master节点交互 有固定Listen端口 b. 定期作业任务, 通 ...

  2. Python Process类开启多层级进程杀不死问题解决(从父进程杀死子进程)

    Python Process类开启多层级进程杀不死问题 问题描述 问题分析 解决方案 问题描述 在使用python multiprocess包下的Process打开子进程,并在打开的子进程中再打开一个 ...

  3. python定时杀进程

    python定时杀进程 之前写了个python脚本用selenium+phantomjs爬新帖子,在循环拉取页面的过程中,phantomjs总是block住,使用WebDriverWait设置最长等待 ...

  4. 如何让Java应用成为杀不死的小强?(中篇)

    [这是一猿小讲的第 48 篇原创分享] 各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 上期我们抛了一个砖:"如何实现 Java 应用进程的状态监控,如果被 ...

  5. mysql 进程一直杀不死_进程一直杀不死

    就是一个简单的杀死进程,名字也是对的,不知道为何用下面方法一直杀不死 private void KillProcess(string processName) { //获得进程对象,以用来操作 Sys ...

  6. 解决liunx进程杀不死的问题

    liunx中有时候通过命令ps -ef|grep 进程名,查看进程pid号,杀进程的时候会杀不死,是因为可能杀的是子进程而不是父进程,整个进程树没有死.针对这种情况,我苦寻到一个命令,来解决这种问题. ...

  7. Android中创建杀不死的APP进程(5.0以下)

    所谓的杀不死指的时进程被杀掉后,会自动重启. 即便时在设置里面强行停止后,也能够自动重启. 那么如何自动重启呢?目前想到的有3种方式: 1.使用AlarmManager来定时发intent启动 2.N ...

  8. 关于GPU上进程杀不死的解决

    最近GPU上某些进程杀不死,查了一下说是因为父进程虽然kill了,但是子进程的内存还没有释放.因此要重新杀死父进程,我们通过  ps -ef|grep 进程ID  ,来查找其父进程.然后再使用    ...

  9. python中执行shell脚本之subprocess模块_如何使用Python中的subprocess模块检查shell脚本的状态?...

    我有一个简单的Python脚本,它将使用Python中的subprocessmdoule来执行shell脚本.在 下面是我的pythonshell脚本,它正在调用testing.shshell脚本,它 ...

最新文章

  1. Spring多数据源配置和使用
  2. Arduino 各种模块篇 motor shield
  3. 征战蓝桥 —— 2013年第四届 —— C/C++A组第10题——大臣的旅费
  4. POJ - 1284 Primitive Roots(原根+欧拉函数)
  5. 高等数学上-赵立军-北京大学出版社-题解-练习2.3
  6. 用计算机MR,计算机上的【MC、MR、M
  7. 又一位!发40篇SCI,90后博士受聘985教授
  8. php什么是变量6,PHP变量是什么
  9. core api其他电脑不能访问接口_第 12 篇:加缓存为接口提速
  10. c语言格式化浮点数多余的0
  11. 2022-2028年全球与中国细菌生物农药行业市场深度调研及投资预测分析
  12. 笔记本电脑应用商店服务器错误,打开win10商店出错 出现win10商店请稍后重试问题怎么办 - 驱动管家...
  13. android adb 分析,android adb shell常用脚本分析课件.ppt
  14. python怎么获取向量中非零元素的行号
  15. css之@media网页适配
  16. 【3d游戏模型】女骑士制作指南:硬表面和纹理
  17. 给定空间的四个点的笛卡尔积坐标,使用python、shell计算二面角
  18. k8s 中部署kafka集群
  19. c语言除法取两位小数点,高精度除法小数点位数
  20. 回归预测 | MATLAB实现ANN神经网络多输入单输出

热门文章

  1. 根据当前日期算前一年、前一月、前一天(java基础)
  2. PLSQL developer 连接不上64位Oracle 的解决方法
  3. AutoLISP将多段线各个端点坐标写入外部文件
  4. 阿里云安装git_阿里云服务器快速建网站_安装BT宝塔面板和wordpress
  5. 【转】SAP地产业正青春
  6. sap 状态栏添加竖线
  7. ABAP--如何快速从BSEG读取数据
  8. Oracle 海量数据处理- 索引的选择
  9. ABAP中Conversion Routine示例
  10. SAP、ORACLE、用友、金蝶四大ERP软件供应商的区别