RedisSpider并发设置未达预期性能的问题求助
Scrapy-Redis爬虫并发行为不符合预期的原因
我使用Python3.7与Scrapy-Redis编写了RedisSpider,将CONCURRENT_REQUESTS设置为10,期望爬虫能保持10个并发请求,单个请求完成后立即从Redis获取新请求补充。但实际情况是爬虫会一次性从Redis获取10个请求,必须等这10个全部完成后才会拉取新请求。
爬虫配置
custom_settings = { "DOWNLOADER_MIDDLEWARES": { "projects.middlewares.MediaFileCheckMiddleware": 300, }, "DOWNLOAD_TIMEOUT": 300, "CONCURRENT_REQUESTS": 10, "SCHEDULER_PERSIST": True, "SCHEDULER_FLUSH_ON_START": False, "SCHEDULER_IDLE_BEFORE_CLOSE": 0, }
预期与实际执行流程
预期的线程执行流程
thread1 --job1--|-----job2-----|-job3-|--job4--|... thread2 ----job1----|----job2----|----job3----|... thread3 -job1-|-job2-|----job3----|--job4--|...
每个线程完成当前任务后立即启动新任务,持续维持并发数。
实际的线程执行流程
thread1 --job1-- |-----job2-----|-job3- |--job4--,... thread2 ----job1----|----job2---- |----job3----|... thread3 -job1- |-job2- |----job3---- |--job4--,...
所有线程先完成第一批10个任务,才会开始下一批任务。
核心爬虫代码
class FileHandler(RedisSpider): name = 'filehandler' redis_key = 'news:multimedias' file_path = r'/data/temp' img_header = Headers(content_type='img') size_limit = 50 * 1024 * 1024 custom_settings = { "DOWNLOADER_MIDDLEWARES": { "projects.dapoo.middlewares.MediaFileCheckMiddleware": 300, }, "DOWNLOAD_TIMEOUT": 300, # "DOWNLOAD_WARNSIZE": 0, "CONCURRENT_REQUESTS": 10, "SCHEDULER_PERSIST": True, "SCHEDULER_FLUSH_ON_START": False, "SCHEDULER_IDLE_BEFORE_CLOSE": 0, } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def make_request_from_data(self, data): obj = json.loads(data) suffix = obj.get('suffix') src = obj.get("src") err = obj.get('err') media_type = obj.get('media_type') if err: pass # logging else: return scrapy.Request( src, method="GET", headers=self.img_header(), dont_filter=True, meta={'file_name': str(int(datetime.datetime.now().timestamp()))}, callback=self.parse ) def parse(self, response): file_name = response.meta.get('file_name') file_path = os.path.join(self.file_path, file_name) with open(file_path, 'wb') as f: f.write(response.body)
原因分析与解决方案
原因
这是Scrapy-Redis调度器的默认批量拉取机制导致的:
- Scrapy-Redis的
RedisScheduler会在本地维护一个请求队列,当本地队列的请求数低于CONCURRENT_REQUESTS时,会一次性从Redis任务队列拉取足够的请求填满本地队列(最多CONCURRENT_REQUESTS个)。 - 只有当本地队列的所有请求都处理完毕后,调度器才会再次去Redis拉取新的一批请求,因此出现了“必须等10个全部完成才取新请求”的现象。
解决方案
调整Scrapy-Redis的批量拉取参数,在custom_settings中添加:
"REDIS_START_URLS_BATCH_SIZE": 1
该参数控制每次从Redis拉取请求的数量,设置为1后,每当有一个请求处理完成,调度器会立即从Redis拉取一个新请求补充到本地队列,从而维持稳定的10个并发请求,符合你的预期。
另外,如果你的MediaFileCheckMiddleware存在同步阻塞操作,也可能影响并发效率,建议检查中间件实现是否存在耗时的同步逻辑。
内容的提问来源于stack exchange,提问作者vassiliev
相关产品推荐
相关产品推荐

