我有一个作业队列(使用 Amazon SQS),它将作业交给许多机器,以通过 HTTP 获取和处理各种文档。有数百个不同的主机被访问,并且这些作业没有可预测的顺序。
为了礼貌,我不希望我的系统反复锤击单个主机。因此,如果我得到一个作业 #123 来从 example.com 获取一些东西,但我发现我刚刚在过去 X 秒内从 example.com 获取了另一个东西,我应该继续做其他事情并将作业 #123 保存为之后。
问题是,实现这种模式的好方法是什么?
第一步似乎是让工作运行者在某处保留所有域的列表,以及最后一次访问该域上的某些内容。我想这可能是一个简单的数据库表。
如果消息处理器获得必须推迟的工作,那么有许多可能的选择。
只需将消息的副本推送到队列的末尾,然后将其丢弃而不执行。希望下次它出现时,已经有足够的时间过去了。这可能会导致大量冗余 SQS 消息,特别是如果同一域的大型作业集群同时通过。
在礼貌要求可以执行该工作之前,需要多睡几秒钟。这可能会导致许多队列处理器同时无所事事。
接受该作业,但将其保存在每个队列处理器的某个本地队列中。我想每个处理器都可以通过这种方式“声明”许多工作,然后选择以任何顺序处理它们以达到最大的礼貌。这仍然是不可预测的,因为每个队列处理器都需要知道所有其他队列处理器所命中的域。
为每个域建立单独的队列,并为每个队列设置一个专用进程。每个进程在执行每个作业之间都必须暂停 X 秒,因此有很多睡眠进程开销,但这也许不是一件坏事。
你有设计这种东西的经验吗?你会推荐什么策略?