在特定时间运行多个密集型作业的最佳解决方案

时间:2012-01-16 10:23:29

标签: php multithreading message-queue jobs beanstalkd

我们有一个网络应用程序,它使用IMAP在用户定义的时间有条件地将邮件插入用户的邮箱。

这些“作业”中的每一个都存储在MySQL数据库中,其中包含应该运行作业的时间戳(可能是未来几个月)。用户可以随时取消作业。

问题在于进行IMAP连接是一个缓慢的过程,在我们插入消息之前,我们经常需要有条件地检查收件箱中是否有人回复(或类似),这会给每个作业增加相当大的处理开销

我们目前有一个系统,我们每隔一分钟就会运行一次cron脚本,从而获得需要在接下来的X分钟内交付的数据库中的所有作业。然后将它们分成多批Z个作业,并为每个批处理执行异步POST请求,将这些Z作业的所有数据返回到同一服务器(以实现'假'多线程)。然后,服务器处理通过HTTP进入的每批Z作业。

我们使用异步HTTP POST进行多线程而不是像pnctl_fork这样的原因是我们可以添加其他服务器并让他们将数据发送给那些服务器,让他们运行作业而不是当前服务器。

所以我的问题是 - 有更好的方法吗?

我感谢像 beanstalkd 这样的工作队列可以使用,但它们是否适合在特定时间运行作业的模型?

另外,因为我们需要保留数据库中的作业(因为我们需要为用户提供用于管理作业的UI),所以在某处添加工作队列实际上会增加更多的开销而不是减少它?

我确信有更好的方法来实现我们的需求 - 任何建议都会非常感激!

我们正在使用PHP来实现这一切,因此我们正在寻找基于PHP的/兼容解决方案。

1 个答案:

答案 0 :(得分:0)

Beanstalkd是一种合理的方法。它具有put-with-delay的概念,因此您可以定期从主存储中填充一条消息,该消息可以在X秒内保留并运行(您希望它运行的时间) -现在的时间。)

然后,工作人员将正常运行,连接到beanstalkd守护程序并等待保留新作业。如果没有HTTP连接的开销,它也会更有效率。例如,我曾经将消息发布到Amazon SQS(通过http)。这最多只能达到20 QPS,但是Beanstalkd几乎没有任何努力地接受了每秒一千多次。

已编辑添加:您无法在不知道ID的情况下删除作业,但可以将其存储在外部。 OTOH,用户必须能够在最后一分钟内随时删除作业吗?您不必提前几周或几个月将作业放入队列中,因此您仍然只有一个DB-reader,每隔1到5分钟运行一次,以便将接下来的几个作业放入队列中,仍有尽可能多的工人,他们可以带来效率。

最终,它取决于您正在执行的数据库读/写次数,以及数据库服务器如何处理它们。

如果您正在做的事情现在不是问题,并且在额外负载下不会变成问题,那么请继续。