这是我参与更文挑战的第3天
scrapy killed原因探究
用scrapy爬取网站的时候,爬取到一定的时间,会被系统主动kill 掉.
原因
在爬取到一定的时间,再爆掉,说明不是网络或者系统问题,只有一种可能,就是爬取的时候积累内存,最后内存溢出,导致系统kill,值得一提的是,被kill时,日志是不会记录停止原因的,最后死的不明不白,但会在console中output一个killed(如果你不是后台运行的话)
使用命令查看
egrep -i 'killed process' /var/log/syslog
total-vm:进程总共使用的虚拟内存; anon-rss:虚拟内存实际占用的物理内存; file-rss:虚拟内存实际占用的磁盘空间; OOM killer LINUX内核Out-Of-Memory killer机制是一种防止内存耗尽影响系统运行而采用的一种自我保护机制。 根据内核源码oom_kill.c中的定义,系统会依据“进程占用的内存”,“进程运行的时间”,“进程的优先级”,“是否为 root 用户进程“,”子进程个数和占用内存“,”用户控制参数oom_adj ”等计算一个oom_score值,分数越高就越会被内核优先杀掉。
可以看到确实是内存爆了,导致被杀.
什么会导致scrapy内存溢出呢?
众所周知,scrapy作为一个异步框架,内存溢出听起来就很怪,事实上,scrapy的一些设置是会导致内存溢出的,如官方文档所示(重点关注==too many request==):
可能导致内存溢出的元素
lxml吃掉内存
由于scrapy的底层解析是建立在lxml上的,当lxml解析文档时,一些操作会导致它大量吃掉内存,官方doc: ==写xpath的时候,如果保留对解析元素的引用,就会保留树的记忆,从而导致内存暴涨,所以不推荐那样的写法==
如何查看scrapy内存使用
使用telent
在shell里使用:
telent localhost 6023
username: 默认是scrapy
Username: scrapy
password是爬虫运行时输出的telent password
Password:
使用prefs()查看scrapy指标
从上图可以看到,爬虫运行2000多秒时,scrapy的scheduler已经堆积了1318个request等待处理,600多的response等待处理.
使用 muppy 查看内存 使用
__author__ = '笑笑布丁'
# 首先
pip install Pympler
# 盗文死妈
from pympler import muppy
from pympler import summary
all_objects = muppy.get_objects()
suml = summary.summarize(all_objects)
len(all_objects) 查看大小
summary.print_(suml) 综合分析
可以看到问题爬虫运行到600s秒时,bytes就已经暴涨到500多MB了,这是导致问题爬虫运行一段时间后暴毙的原因.
解决办法
措施
- 减少xpath对元素的引用
- 调整 yield request的访问次序
- 减少同时运行爬虫数目
- 检查代码中是否不正确的判断,导致陷入死循环