Python踩坑之旅其一杀不死的Shell子进程
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该脚本并没有进行端口监听的代码
- 定位问题出现在一个叫做xxxxxx.sh的脚本, 该脚本占用了Agent使用的端口
- 一拍脑袋, c.进程共享了父进程资源了
- => 溯源该脚本,发现确实是Agent启动的任务中的脚本之一
- => 问题基本定位, 该脚本属于Agent调用的脚本
- => 该Agent继承了Agent原来的资源FD, 也就是这个port
- => 虽然该脚本由于超时被动触发了terminate机制, 但terminate并没有干掉这个子进程
- => 该脚本进程的父进程(ppid) 被重置为了1
- d.问题****出在脚本进程超时kill逻辑
1.2 填坑解法
通过代码review, 找到shell具体执行的库代码如下:
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 填坑总结
子进程会继承父进程的资源信息
如果只kill某进程的父进程, 集成了父进程资源的子进程会继续占用父进程的资源不释放, 包括但不限于
- listened port
- opened fd
- etc
Python Popen使用上, shell的bool状态决定了进程kill的逻辑, 需要根据场景选择使用方式
建议大家也看一下这篇文章的姊妹篇, 此篇是子孙进程无法 kill/杀死的终极解法 [Python 踩坑之旅进程篇其三pgid是个什么鬼 (子进程\子孙进程无法kill 退出的解法)] (https://www.cnblogs.com/mythmgn/p/10945941.html)
Python踩坑之旅其一杀不死的Shell子进程的更多相关文章
- Python 踩坑之旅进程篇其三pgid是个什么鬼 (子进程\子孙进程无法kill 退出的解法)
目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4.1 技术关键字 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 Github: https: ...
- [代码修订版] Python 踩坑之旅 [进程篇其四] 踩透 uid euid suid gid egid sgid的坑坑洼洼
目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 技术关键字 1.5 坑后思考 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 代码示例: 公 ...
- Python 踩坑之旅进程篇其四一次性踩透 uid euid suid gid egid sgid的坑坑洼洼
目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4 技术关键字 1.5 坑后思考 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: 2.7.14 代码示例: 菜 ...
- [代码修订版] Python 踩坑之旅进程篇其五打不开的文件
目录 1.1 踩坑案例 1.2 填坑和分析 1.2.1 从程序优化入手 1.2.2 从资源软硬限入手 1.4.1 技术关键字 下期坑位预告 代码示例支持 平台: Centos 6.3 Python: ...
- Python 踩坑之旅文件系统篇其一文件夹也是个文件
目录 1.1 案例 1.2 分析 1.3 扩展 1.4 技术关键字 下期预告 代码示例支持 平台: Mac OS Python: 2.7.10 代码示例: - wx: 菜单 - Python踩坑指南代 ...
- Python踩坑之旅其二裸用os.system的原罪
目录 1.1 踩坑案例 1.2 填坑解法 1.3 坑位分析 1.4.1 技术关键字 1.5 填坑总结 2. 前坑回顾 2.1 Linux中, 子进程拷贝父进程哪些信息 2.2 Agent常驻进程选择& ...
- EasyTrader踩坑之旅总结
easytrader是用python写的可以调用主要券商完成自动化炒股的一个软件 ,但我用的是同花顺,在研究过程中,发现同花顺暂时调不通.后来搜索发现thstrade的源码作者说是easytrad ...
- 我的微信小程序入门踩坑之旅
前言 更好的阅读体验请:我的微信小程序入门踩坑之旅 小程序出来也有一段日子了,刚出来时也留意了一下.不过赶上生病,加上公司里也有别的事,主要是自己犯懒,就一直没做.这星期一,赶紧趁着这股热乎劲,也不是 ...
- vue+ vue-router + webpack 踩坑之旅
说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案 老司机可以忽略下面的内容了 1)起因 考虑到数据分离的问题 因为server是express搭的 自然少 ...
随机推荐
- window下rails4.1 发生TZInfo::DataSourceNotFound 错误 - smallbottle
在官网上学习rails 4.1 ,启动rails server之后发生了如下错误 $ rails server Booting WEBrick Rails 4.1.0 application star ...
- 元素(Element)和结点(Node)的区别(org.w3c.dom)
1.元素(Element)和结点(Node)的区别, 元素是一个小范围的定义,必须是含有完整信息的结点才是一个元素,例如 - . 但是一个结点不一定是一个元素,而一个元素一定是一个结点. 什么是nod ...
- Mysql 增量备份和全量备份
全量备份: # vim /root/DBFullyBak.sh //添加以下内容 #!/bin/bash # Program # use mysqldump to Fully backup mysql ...
- Servlet编程实例 续3
----------------siwuxie095 Servlet 跳转之请求的转发 修改 LoginServlet.java: package com.siwuxie095.servlet; im ...
- Multi-task Pose-Invariant Face Recognition 论文笔记
摘要: 在不受限制的环境中拍摄的人脸图像通常包含显著的姿态变化,这会显著降低设计用于识别正面的算法的性能.本文提出了一种新颖的面部识别框架,能够处理±90°偏航范围内的全方位姿势变化.所提出的框架首先 ...
- 如何保持blog的高质量(相对于自己的进步而言的)
多写! 多改!! 多删!!!
- 【mybatis-记录】
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...
- 滴水穿石 C#中多线程 委托的使用
什么是多线程?我们在建立以个C#项目时,往往会在Form1上添加控件,然后写代码,初 学者都是在重复这个过程,其实这个过程是单线程的,可以理解为只有“main”主线程,有 的时候往往需要同时测量多个东 ...
- Jquery选择器(三)
过滤选择器 4.属性过滤器 查找所有含有 id 属性的 div 元素$(document).ready(function(){ $("div[id]").css("col ...
- sql server 2008 r2安装
选择功能(好像报错了-下次重装系统测试)