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


Best solution for running multiple intensive jobs at specific times

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

这些"作业"中的每一个都存储在MySQL数据库中,并带有作业运行时间的时间戳(可能在未来几个月内)。用户可以随时取消作业。

问题是,建立IMAP连接是一个缓慢的过程,在插入邮件之前,我们通常必须有条件地检查收件箱(或类似的收件箱)中是否有人回复,这给每个作业增加了相当大的处理开销。

我们目前有一个系统,其中cron脚本每分钟左右运行一次,它可以在接下来的X分钟内从DB中获取所有需要交付的作业。然后,它将它们拆分为Z个作业的批,并为每个批执行一个异步POST请求,返回到同一服务器,其中包含这些Z个作业中的所有数据(以实现"伪"多线程)。然后,服务器处理通过HTTP传入的每一批Z作业。

我们之所以使用异步HTTP POST进行多线程处理,而不是像pnctl_fork这样的方法,是为了添加其他服务器,让它们将数据POST到这些服务器,并让它们运行作业,而不是当前服务器。

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

我很欣赏beanstalkd这样的工作队列可以使用,但它们是否符合必须在特定时间运行作业的模式?

此外,因为我们无论如何都需要将作业保留在DB中(因为我们需要为用户提供一个用于管理作业的UI),所以在某个地方添加工作队列实际上会增加更多的开销而不是减少它吗?

我相信有更好的方法来实现我们所需要的——任何建议都将不胜感激!

我们使用PHP来实现这一切,所以我们真正想要的是一个基于PHP/兼容的解决方案。

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

然后,工作程序将正常运行,连接到beanstalkd守护进程并等待保留新作业。如果没有HTTP连接的开销,它的效率也会高得多。举个例子,我过去常常(通过http)向AmazonSQS发布消息。这最多只能完成20个QPS,但Beanstalkd几乎没有付出任何努力就接受了每秒1000多个QPS。

编辑添加:您不能在不知道作业ID的情况下删除作业,尽管您可以将其存储在外部。OTOH,用户必须能够在最后一分钟之前的任何时间删除作业吗?你不必提前几周或几个月将一个作业放入队列,因此你仍然只有一个数据库读取器,每隔1到5分钟运行一次,将接下来的几个作业放入队列中,并且仍然有尽可能多的工人,他们可以带来效率。

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

如果你现在所做的不是问题,并且在额外的负载下不会变成问题,那么继续。