使用py-spy解决scrapy卡死的问题
背景
在使用scrapy爬取东西的时候,使用crontab定时的启动爬虫,但是发现机器上经常产生很多卡死的scrapy进程,一段时间不管的话,会导致有10几个进程都卡死在那,并且会导致数据产出延迟。
问题定位
使用py-spy这个非常好用的python性能分析工具来进行排查,py-spy可以查看一个python进程函数调用用时,类似unix下的top命令。所以我们用这个工具看看是什么函数一直在执行。
首先安装这个工具
pip install py-spy
用py-spy看看scrapy哪个函数执行时间长
# 先找到这个卡死的scrapy进程的pid
ps -ef |grep scrapy
# 启动 py-spy 观察这进程
py-spy top --pid 53424
首先我们按3,按OwnTime进行排序,这个表示函数自身执行的时间,可以看到read这个函数执行的时间最长,那看来是IO导致的,程序中的IO行为就是读写磁盘和网络IO,磁盘读写一般不会有问题,所以初步定位是网络IO导致的。
接下来进行进一步确认,再按4,按TotalTIme 所有子函数执行时间总和进行排序,可以看到是在process_item和download,upload_image这些主流程函数的执行时间比较长,这一步是先把图片下载到本地,然后上传到静床,看来是下载这步从网络中read数据时出现了问题,进一步追踪代码。
看下download的函数的代码:
if filename == '':
filename = os.path.basename(url)
path = path + '/' + filename
try:
res = request.urlretrieve(url,filename=path)
print(url,res)
return path
except Exception as e:
print('download img failed')
print(e)
return False
可以看到用了urllib这个库里面request.urlretrieve函数,这个函数是用来下载文件的,去看看python官网文档的函数说明,发现里面没有超时时间这个参数,所以是由于没有超时时间,导致一直在read,进而使得进程卡死。
urllib.request.urlretrieve(url, filename=None, reporthook=None,
data=None)
解决方案
使用另一种方式来下载图片,使用支持超时时间的urlopen函数,封装成一个自定义的url_retrieve,这样就不再会出现没有超时导致的卡死问题了。
def url_retrieve(self,url, path):
r = request.urlopen(url, timeout=5)
res = False
with open(path,"wb") as f:
res = f.write(r.read())
f.flush()
f.close()
return res
上一篇: 学习KEA的GPIO
推荐阅读
-
使用py-spy解决scrapy卡死的问题
-
【重要总结】使用gulp来解决浏览器缓存的问题。还有遇到的bug。missing script: gulp和Task function must be specified
-
Java使用openOffice对于word的转换及遇到的问题解决
-
Yii使用DeleteAll连表删除出现报错问题的解决方法
-
使用asp.net MVC4中的Bundle遇到的问题及解决办法分享
-
高效的使用 Response.Redirect解决一些不必要的问题
-
使用MySQL Slow Log来解决MySQL CPU占用高的问题
-
使用LengthFieldBasedFrameDecoder解决复杂的自定义协议-粘包与半包问题
-
java接口中私有方法定义和使用(解决代码重复的问题)
-
使用MySQL Slow Log来解决MySQL CPU占用高的问题