Scrapy的内存泄露问题总结
当前位置:以往代写 > Python教程 >Scrapy的内存泄露问题总结
2019-06-14

Scrapy的内存泄露问题总结

Scrapy的内存泄露问题总结

  这几天随着小同伴一起做项目,遇到不少平时碰不到的技能问题,真是很好玩的一件事。好比Scrapy这个爬虫框架的的内存泄露问题就是一个很让人头疼的问题。

  向来OOM(OOM – Out of Memory,内存溢出)问题都是项目里最棘手的问题,这种问题debug的难度很大,原因在于问题不太好定位。因为OOM的成因往往较量巨大,不公道的工具建设,数据布局利用的不公道性,漫衍式架构中各系统的共同欠好等环境,都有大概呈现这个问题。

  而爬虫这个任务,涉及网站各个页面的遍历,凡是会在网站抓去期间发生大量的HTTP Request,而Request的处理惩罚往往是通过任务行列来处理惩罚的。由于不是网站的所有的页面都要抓去,但我们险些需要遍历大部门的页面,再思量并发的环境,爬虫任务开始后,往往会有大量的pending request进入行列。而这些行列,框架对其最常见的处理惩罚方法是放在内存中,因此,当要抓去的页面条理位于网站的较深层时,这个行列的内存占用到了任务的中后期会变得很是可观。以我这次遇到的环境看,在用完我所有想到的能用到的要领优化内存利用今后,在抓到快要20w条数据的时候,行列里pending request数量已经占到了差不多40w个。此时耗损了差不多1.7G内存,而我整个虚拟机也只有2G内存。

  需要说明的一点是,这个数值,按照差异的网站,爬虫写法的差异,会有差异的值。这里只是我的项目中的数据。在没有做任何优化之前,根基上跑到几千甚至1w条数据的时候,爬虫就吃光内存被ubuntu强制杀掉了。Scrapy的官方文档也提到过memory leak的debug要领,各人可以参考Scrapy文档中的Debugging memory leaks一节。官方文档给了较量具体的说明, 详情参考 Scrapy文档 – 调试内存溢出

  那么,Scrapy会造成OOM的原因是否只有request?谜底是不是。这个项目内里利用了django的orm作为数据操纵的框架。可以说,之前吃内存太快的原因,主要不在于Scrapy的pending request膨胀得太快,而是django带来的坑。

  因为我们要抓取的数据量也是很大的,因此也会有大量的数据会往数据库里写,同时,也会有很大都据被读取。有时候为了制止过多的数据库io,我们会将常用的数据留在内存中,需要的时候直接取用。但很不幸的是,django的orm也会思量同样的问题。当我们挪用django orm的QuerySet接口查询的时候,django会把数据缓存。这样,同样的对象会保持2份(一份是我们本身维护的内存缓存,一份是orm本身的session缓存)。只有利用QuerySet的iterator要领来迭代输出的时候,django orm才不会有缓存行为,这是django官方文档中的表明。

  可是,工作并不会如此简朴,在开拓阶段,我们往往会把框架的debug参数设为True以便于debug的时候做profile和异常定位。可是在开拓阶段用debug=True的设置来跑措施的时候,orm永远城市缓存,因此在这种设置下,依然无法制止内存泄露的问题。另一个坑就是,像MySQL-Python(MySQLdb)和Psycopg2这样的数据库驱动,都有客户端缓存,因此,数据库驱动也会生存一份缓存,这样内存中就是3份缓存,假如数据量大了,内存开销的增长速度会相当可观。因此,在有需要缓存的数据的查询的时候,要制止把所有的对象查出来,只取出本身需要的字段就好。

  django的QuerySet有values和value_list要领来担保只取到需要的字段,另一个步伐就是本身操纵数据库毗连,写SQL来获取本身需要的字段。前一种要领是较好的方法。其实这个问题对付其他的orm也会存在,因此也是相当的具有参考性。

  所以总结一下,当你在scrapy碰着内存泄露的问题的时候应该查抄以下环境:

  1.Scrapy的任务行列中的请求数是否过多?

  假如是,那么你应该看看本身的url抓取的rule是否应该优化,将完全没有须要会见的页面都剔除去,不抓取,不会见。查察pending request数量的要领请参看Scrapy的telnet console说明和文档中debugging memory leaks这一节。

  2.orm的写法是否利用了缓存,假如是,请寻找不缓存的查询要领,可能按时手动清理orm缓存。

  3.看看数据库驱动的特性里是否存在缓存功效的特性,是的话,可以看看可否封锁并在查询的时候只查出本身需要的字段,不要查出所有字段。

    关键字:

在线提交作业