首页 > 代码库 > 爬虫任务调度

爬虫任务调度

背景介绍

爬虫系统:一台是control server,其他的100台做crawler。server每天定时分发采集任务。

问题出现:由于目标采集任务比较大,准备增加10台crawler。期望在不改变原有任务分配规

则的基础上,同时优先分配任务少的机器上,而且能够对任务较少的机器进行平均分配(尽可

能保证机器有任务而不空跑)。

解决方案

方案一:对已经分配任务的每台机器统计任务数和task_sum,加上待分配任务数dis_num,平均分到

每一台机器,得到一个分发任务后的平均任务数avg_task_num,对于已分配任务数少于avg_task_num

的机器,就分配。分配数为avg_task_num减去每台机器上的已分配任务数。如果任务数足够,就会优先

分配给任务数少的机器。

分析:这个方案乍一看是很合适的,任务会合适的分发完,而且分发量也会被合适的计算到,不会

出现任务集中分发在某台机器上的情况。

但是,如果任务量不够多的情况下,就会出现不能平均分发的情况。假设下面五台机器的任务数量为

[50,50,50,0,0],机器4和5为新加入crawler系统的机器,任务数和task_sum为150,在待分配任务数

dis_num分别为200,100,50,10的情况下每台机器分配后的任务数情况如下:

待分配任务数
dis_num

分配后平均任务数avg_task_num

机器1 机器2 机器3 机器4 机器5
200 70 50+20 50+20 50+20 0+70 0+70
100 50 50+0 50+0 50+0 0+50 0+50
50 40 50+0 50+0 50+0 0+40 0+10
10 32 50+0 50+0 50+0 0+10 0+0

上表中,每台机器的任务数情况表示为a+b的形式,其中a为该机器上已分配的任务数,b为实际可分配到的

任务数。当待分配任务数(dis_num)为200和100的时候,我们发现这个方案还可以优先并平均分配任务;

但是当待分配任务数(dis_num)为50的时候,我们可以发现,该方案可以优先为没有任务的机器4和5分配

任务,但是任务数量有一定的偏差;当待分配任务数(dis_num)为50的时候,我们发现由于分配的先后顺

序,机器5分配到任务数为0。这样并不是我们期望的结果,我们期望的是,如果待分配任务数(dis_num)为

10,为了不让机器空跑,我们希望对机器4和5各分配5个任务。这个问题该怎么解决呢?

此时,可能你更容易想到的就是,添加条件判断,如果有数量为0的机器,优先处理,并且平均分配。但是,

如果待分配任务量足够多,我们又该怎么确定给这些任务数为0的机器优先分配多少?如果优先分配多了,最后

其他机器就少了,crawler的负载不够均衡,如果优先分配少了,剩下很多怎么办?难道再执行一次分配么?

这样的思路似乎总是存在一些瑕疵,如果转换成代码,最后都要加一些额外的if语句来判断,如果考虑的不够全

面,我们的任务调度可能就会有很大的隐患。

 

方案二:我们可以简单的把问题转换一下:

图一:正常情况下理想的任务分配

image

图二:新加机器情况下的理想任务分配

image

我们把任务分配比做连通的水桶加水的过程,假设水桶是相连通的(理想的任意情况下都连通),水桶中或多或

少的有一些冰块(理想冰块不会浮动,并且冰和水的体积仍为1:1)。在加水后,最后的水平面肯定是水桶中最低

的位置(读者自行脑补,人往高处走,水往低处流!)。

如果把水桶视为我们crawler机器上的任务池,冰块视为已经分配给crawler机器的任务,加水就可以视为我们的

任务分配,加水后的水平面就完全可以等价于任务分配完成后的最少任务数,我称之为最低水准线(min_line)。

对于上面的任务分配示意图,如果我们在分配前可以计算出这个最低水准线(min_line),我们就能很容易实现理

想的任务分配。每台机器的实际分配任务量为最低水准线min_line与已分配任务数的差值,如果差值为负数,则不

进行任务分配。这个min_line能计算出来吗?这个嘛,当然是可以的。

 

min_line计算过程描述

total_sum:参与分配的机器上已经分配的任务数之和(假设所有的机器参与了分配,初始化为所有机器的任务数和)

dis_num:待分配的任务数

t_num:实际参与任务分配的机器数量(假设所有的机器参与了分配,初始化为所有机器数)

avg_num:参与分配的机器在完成分配后的任务数

思路:

1.min_line实际上就是 最后真正参与分配的avg_num=(total_sum+dis_num)/t_num,假设所有机器参与了分配。

2.首先检查假设参与分配的机器的已分配任务数是否全部比avg_num小遍历每台机器,把每台机器的已分配任务和avg_num比较,

如果有机器的已分配任务数大于avg_num,那么可以说明这台机器肯定没有参与最后的分配,需要需要把这台机器剔除掉。

否则min_line=avg_num。在完成一次遍历后,重新计算avg_num,重新执行本步骤。

 

总结

我只是在尝试一种可以更好的调度任务的规则而已,就像流水一样,真正优先、均衡地分配任务(至少理论上是这样)!