Scrapy分布式连接计数

时间:2017-02-01 19:23:57

标签: redis scrapy middleware

让我们说我有几台服务器,每台服务器同时运行多个Scrapy蜘蛛实例。每个蜘蛛仅限于CONCURRENT_REQUESTS = 4的4个并发请求。具体来说,让我们说一次有10个蜘蛛实例,所以我一次也不会期望超过40个请求。

如果我需要知道在任何给定时间有多少并发请求在所有10个蜘蛛中都有效,我可能会考虑将这个整数存储在某些" connection_count"下的中央redis服务器上。键。

我的想法是编写一些示意性的下载中间件:

class countMW(object):

    def process_request(self, request, spider):
       # Increment the redis key

    def process_response(self, request, response, spider):
        # Decrement the redis key
        return response

    def process_exception(self, request, exception, spider):
        # Decrement the redis key

然而,使用这种方法,似乎中心密钥下的连接数可以超过40.我甚至得到> 4,对于单个蜘蛛运行(当网络负载不足时),甚至对于单个蜘蛛,当redis存储刚被替换为将计数存储为蜘蛛实例本身的属性的方法时,以消除任何滞后远程redis密钥服务器更新是问题。

我之所以不工作的理由是,即使每个蜘蛛的请求并发数限制为4,Scrapy仍会在此期间创建并排队4个以上的请求,并且这些额外的请求会调用{{1在获取之前很久就递增计数。

首先,这个理论是否正确?其次,如果是的话,是否有一种方法可以仅在发生真正的提取时(当请求变为活动状态时)递增redis计数,并且类似地减少它。

2 个答案:

答案 0 :(得分:1)

在我看来,自定义调度程序更好,因为它更适合Scrapy架构,并且您可以完全控制请求发出过程:

  

<强>计划

     

调度程序接收来自引擎的请求,并在引擎请求它们时将它们排入队列以便稍后(也引用到引擎)。

https://doc.scrapy.org/en/latest/topics/architecture.html?highlight=scheduler#component-scheduler

例如,您可以在此处找到有关如何自定义计划程序的一些灵感创意:https://github.com/rolando/scrapy-redis

答案 1 :(得分:1)

你的理论部分正确。通常请求的执行速度比实现请求快得多,并且引擎会向调度程序提供(而不是一些)所有这些请求。但是这些排队的请求不会被处理,因此在获取之前不会调用process_request

调度程序发出请求和下载程序开始获取请求之间存在轻微的延迟;并且,这允许您观察到同时有多个CONCURRENT_REQUESTS个请求处于活动状态的情况。由于Scrapy以异步方式处理请求,因此有一种草率的双重浸渍可能性;那么,如何处理它。我确定你不想同步运行。

所以问题就变成了:这背后的动机是什么?你是否只是对Scrapy的内部运作感到好奇?或者,您是否有一些ISP带宽成本限制要处理?因为我们必须通过并发来定义我们真正的意思。

请求何时变为“活动”?

  • 当调度程序发布时?
  • 当下载程序开始获取它时?
  • 创建基础Twisted延迟时?
  • 何时发送第一个TCP数据包?
  • 何时收到第一个TCP数据包?

也许您可以添加自己的调度程序中间件以实现更细粒度的控制,也许可以从Downloader.fetch中获取灵感。