Python踩坑之旅其一杀不死的Shell子进程
发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,1.1 踩坑案例踩坑的程序是个常驻的Agent类管理进程, 包括但不限于如下类型的任务在执行:a. 多线程的网络通信包处理和控制Master节点交互有固定Listen端口b. 定期作业任务, 通过su
千家信息网最后更新 2025年02月04日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该脚本并没有进行端口监听的代码
- 一拍脑袋, 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的逻辑, 需要根据场景选择使用方式
Life is short. We use Python
工号: 程序员的梦呓指南
进程
脚本
问题
端口
代码
任务
线程
资源
知识
程序
选择
信息
兴趣
命令
时间
状态
系统
逻辑
重点
a.
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网站防盗链网络安全
cvh数据库
包头嵌入式软件开发招聘网
网络安全行业资质证书
软件开发课题结题报告ppt流程
图书从哪个数据库查询
贵州时代网络技术服务产品介绍
三级考的数据库
grails使用数据库
软件开发 生产者
空间数据库的具体应用
平顶山网络安全
数据库修改和删除触发器
防范网络安全手抄报
电信网络安全宣传进校园
数据库表名 统计信息
数据库虚拟化集群
山东软件开发能赚多少钱
国家网络安全宣传活动直播
互联网访问数据库服务器
战神网络安全工程师
python 进程池数据库
ftp管理服务器部署
珠海家教平台软件开发哪个好
南京睿红网络技术有限公司
江西pdu服务器电源多少钱
cisaw软件开发培训
北京字节网络技术有限公司官网
服务器生产过程
星际争霸如何建服务器