记录特殊情况的Python脚本的内存异常与处理
问题
Python 脚本使用 requests 模块做 HTTP 请求,验证代理 IP 的可用性,速度等。 设定 HTTP 请求的 connect timeout 与 read response timeout 均为 3 秒,allow_redirects 设定为 False。Linux shell 启动 10 个 Python 进程持续从 Redis 队列中读取数据。监控软件持续获取进程内存信息。多个小时之后出现,极个别进程内存占用量暴增,其余进程内存均处于正常且相等的水平。
脚本分析
猜测 Python 脚本出现内存过大问题的可能原因:
- 重复,相互引用
- 重复实例化
- 打开文件数量过多,并且未释放
针对上面猜测的检查方案:
- print 打印主函数中的每个对象,在 while 循环中,被引用的次数。结果:无重复引用。
- memory_profiler 与 objgraph 模块输出主函数内存使用情况,连续测试 10K 条IP,未发现内存爆增问题
- lsof 命令对比 异常进程与正常进程打开的文件对比,结果:打开文件相同,没有异常。
外部分析
外部分析工具:
- strace 跟进进程调用系统调用
- lsof 检查进程的开发的句柄,包括文件,网络连接等
- tcpdump 抓包,进程网络连接等数据包。
首先 strace 跟踪 Python脚本的系统调用。
正常进程的系统调用是这样的:
gettimeofday({1472383894, 582049}, NULL) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
fcntl(4, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(7777), sin_addr=inet_addr("123.57.190.51")}, 16) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=4, events=POLLOUT}], 1, 3000) = 1 ([{fd=4, revents=POLLOUT|POLLERR|POLLHUP}])
getsockopt(4, SOL_SOCKET, SO_ERROR, [111], [4]) = 0
close(4) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=414, ...}) = 0
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
stat("/root/.netrc", 0x7ffd418e1fe0) = -1 ENOENT (No such file or directory)
stat("/root/_netrc", 0x7ffd418e1fe0) = -1 ENOENT (No such file or directory)
异常进程的系统调用是这样的:
gettimeofday({1472384309, 884266}, NULL) = 0
poll([{fd=4, events=POLLIN}], 1, 3000) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\22\4p\327\252\313\5opera\20\4x\244)\303\5opera\21\4r}?\265\5o"..., 3907, 0, NULL, NULL) = 1448
gettimeofday({1472384310, 89236}, NULL) = 0
poll([{fd=4, events=POLLIN}], 1, 3000) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\247p\364\0%\4ry\353\355\4jake\22\4p\327\227b\5opera\22\4\312C("..., 2459, 0, NULL, NULL) = 506
异常进程无休止的系统调用 poll 获取数据,开辟内存使用。初步猜测,TCP连接上有问题。
第二步 lsof 查看异常进程建立的网络连接。
python 12245 root 4u IPv4 9012524 0t0 TCP 10.0.21.226:54452->s30-06-09.opera-mini.net:9000 (ESTABLISHED)
根据 Python脚本的设定,HTTP请求, 连接超时(connect timeout)与读取回复超时 (read response timeout) 都是 3 秒。也就是说一般情况,进程不应该对这个IP(域名)连接了。
在6秒之后,在此查看该进程的 tcp连接,发现已然与此IP建立连接。
思考:为什么 Python requests 模块设定的超时时间无效?
第三步 tcpdump 抓去这个异常进程正在连接的 的数据包。
tcpdump -i eth0 host 107.167.113.32 tcp port 9000 -w /tmp/connect.log
tcpdump 抓到的数据包扔到 WireShake 打开分析。
TCP标志位:ACK 与 PSH。(传输数据)
持续观察之后,确定为特殊IP的特殊端口,在TCP建立连接之后,回传送大量垃圾无用数据。导致极个别进程出现内存异常问题。
另外由于 TCP 层持续传送数据, 经过测试,无论是 urllib2 还是 requests 的超时时间设定对此类问题均无效。
处理方案
思考:
- 由于是 TCP 层的连接问题,HTTP层的超时时间对此无效,需要外部对每次多 HTTP 连接作超时处理。
- 此脚本行为更多占用的系统 IO 而非 CPU 计算,多进程方案会占用很多内存,Python多线程存在 GIL 问题
方案:
- 协程
- gevent 模块
gevent.with_timeout(seconds=15, function=worker)- 协程池
from gevent.pool import Pool
worker_poll = Pool(10) # 最大协程数 10
记录特殊情况的Python脚本的内存异常与处理的更多相关文章
- 基于binlog来分析mysql的行记录修改情况(python脚本分析)
最近写完mysql flashback,突然发现还有有这种使用场景:有些情况下,可能会统计在某个时间段内,MySQL修改了多少数据量?发生了多少事务?主要是哪些表格发生变动?变动的数量是怎 ...
- Linux服务器CPU、内存、磁盘空间、负载情况查看python脚本
[本文出自天外归云的博客园] 网上搜,东拼西凑,组装了一个可以查Linux服务器CPU使用率.内存使用率.磁盘空间占用率.负载情况的python脚本. 脚本内容如下: # -*- coding:utf ...
- Python脚本控制的WebDriver 常用操作 <十二> send_keys模拟按键输入
下面将使用WebDriver中的send_keys来模拟键盘按键输入 测试用例场景 send_keys方法可以模拟一些组合键操作: ctrl+a ctrl+c ctrl+v 等. 另外有时候我们需要在 ...
- [Java/Python] java调用python脚本问题记录
Java调用Python的的两种方式 1.Runtime private static String call_python(String input_argv) { String python_py ...
- python学习 —— 获取系统运行情况信息并在Linux下设置定时运行python脚本
代码: # -*- coding:utf-8 -*- from psutil import * def cpu_usage_rate(): for i, j in zip(range(1, cpu_c ...
- spark-submit提交python脚本过程记录
最近刚学习spark,用spark-submit命令提交一个python脚本,一开始老报错,所以打算好好整理一下用spark-submit命令提交python脚本的过程.先看一下spark-submi ...
- 用于监视Linux上的内存使用情况的Bash脚本
用于监视Linux上的内存使用情况的Bash脚本 2019-06-17 11:32:45作者:戴进稿源:云网牛站 在本文中,我们添加了两个shell脚本来监视Linux操作系统上的内存利用率,即用于监 ...
- 记录一次坑爹的Python脚本抢购低价手机经历!
无意间浏览到魅族官网,说魅族3限量100台.30号中午12点抢购.正好我爪机目前处于报废状态,就来一试手气了.11点多种,习惯性的看了下网页脚本,发现了检测是否到抢购时间,并返回抢购消息的ajax.于 ...
- c#调用python脚本实现排序(适用于python脚本中不包含第三方模块的情况)
引用:https://www.cnblogs.com/zoe-yan/p/10374757.html 利用vs2017c#调用python脚本需要安装IronPython.我是通过vs2017的工具- ...
随机推荐
- Hibernate3回顾-1-部署
web备份版本,详见doc版本. 一.背景(部署简单回顾) 我们知道,一个Hibernate快速上手的简单流程是这样. 1引入对应jar包. 中间涉及log4的jar包和配置,略. 2 实体类 pac ...
- windows p12(pfx)个人证书安装过程
证书库个人证书存储区为其中的每个证书维护一个属性CERT_KEY_PROV_INFO_PROP_ID,该属性指定了证书对应的密钥容器的相关信息,包括密钥容器名,CSP名称,CSP类型,密钥用途,以及C ...
- css中的继承、层叠、样式优先级机制
一.继承与层叠:
- lucene.net 使用过程中的 几个注意事项(含termquery 和QueryParser 的区别)
几个注意事项1.建立索引时 插入的顺序(不设置document和字段的boost) 会影响到 查询结果的默认排序,建议:将最新生成的文章 最后建索引 这样 查询结果首先显示的是 最后插入的数据2.Bo ...
- php 自带函数
memory_get_usage()://查看当前内存使用情况单位 bytes str_repeat("liuhui", 2);//字符串重复指定次数,liuhui重复2次
- golang的连接池例子
github.com/jolestar/go-commons-pool 测试代码 package main import ( "github.com/jolestar/go-commons- ...
- GCC同时使用静态库和动态库链接
一 在应用程序需要连接外部库的情况下,linux默认对库的连接是使用动态库,在找不到动态库的情况下再选择静态库.使用方式为: gcc test.cpp -L. -ltestlib 如果当前目录有两个库 ...
- SVN服务器几种备份策略---重点svnsync备份---OK
配置管理的一个重要使命是保证数据的安全性,防止服务器应硬盘损坏.误操作造成数据无法恢复的灾难性后果.因此制定一个完整的备份策略非常重要. 一般来说,备份策略应规定如下几部分内容:备份频度.备份方式.备 ...
- java学习日志(1):命令行and小程序
1.dos命令行,常见的命令 dir:列出当前目录下的文件以及文件夹md:创建目录rd:删除目录(必须空)cd:进入指定目录cd.. :退回到上一级目录cd/:退回到根目录del:删除文件exit:退 ...
- ylbtech-Unitity-CS-Arrays:数组
ylbtech-Unitity-CS-Arrays:数组 1.A,效果图返回顶部 1.B,源代码返回顶部 1.B.1, using System; class DeclareArraysSampl ...