代码之家  ›  专栏  ›  技术社区  ›  Steven Mercatante Dimitri Kopriwa

在一个非常大的过程中需要关于cron作业的建议

  •  1
  • Steven Mercatante Dimitri Kopriwa  · 技术社区  · 14 年前

    我有一个从外部服务获取数据并将数据保存到我的数据库的PHP脚本。我需要每分钟为系统中的每个用户运行一次这个脚本(我希望是几千个)。我的问题是,每用户每分钟运行这个程序最有效的方法是什么?起初我以为我有一个函数可以从我的数据库中获取所有的用户ID,迭代ID并为每个ID执行任务,但是我认为随着用户数量的增长,这将花费更长的时间,并且不再是1分钟的时间间隔。也许我应该将用户ID排队,并为每个ID分别执行任务?在这种情况下,我实际上不确定如何进行。

    事先谢谢你的建议。

    编辑

    回答奇怪的问题:

    我想同时为每个用户启动进程。当每个用户的进程完成时,我希望等待1分钟,然后再次开始该进程。所以我认为每个用户的每个进程都应该是异步的——用户1的进程不应该关心用户2的进程。

    回答Sims的问题:

    我无法控制外部服务,并且外部服务的用户与我的数据库中的用户不同。恐怕我不知道其他任何脚本语言,所以我需要使用PHP来完成这项工作。

    5 回复  |  直到 13 年前
        1
  •  1
  •   d-_-b    14 年前

    所以,让我直截了当地说:您在查询一个外部服务(什么?肥皂?MySQL?)数据库中每个用户的每一分钟,并将结果存储在同一个数据库中。对吗?

    这似乎是一个设计问题。

    如果外部服务上的用户与数据库中的用户相同,那么可能应该更紧密地配置这两个用户。我不知道PHP是否是同步这些数据的方法。如果你提供更多细节,我们可以考虑另一个解决方案。如果您控制着外部服务,那么您可能希望让该服务转储它的数据,甚至直接写入数据库。其他一些同步机制可能更好。

    编辑

    似乎您正在开发一个应用程序,为用户存储数据,然后按时间顺序查看数据。否则,您也可以在用户请求时获取数据。

    1. 在Go中获取所有用户ID。

    2. 一个接一个地迭代它们(假设所获取的数据对每个用户都是唯一的),并且(在这里,由于php线程不存在afaik,您必须具有创造性)为每个请求调用一个进程,因为您希望它们同时执行,如果一个用户不返回数据,则不会延迟。

    3. 所述过程应在返回数据后立即将返回的数据插入数据库。

    至于cron是否适合这项工作:只要你有一台足够强大的服务器,能够同时处理数千个以上的cron工作,你就应该没事了。

    您可以通过几个PHP脚本获得创造性。我不确定,但是如果对php的每个cli调用都启动了一个新的php进程,那么您可以这样做。

    foreach ($users as $user)
    {
        shell_exec("php fetchdata.php $user");
    }
    

    这一切都非常沉重,您不应该期望用PHP快速完成。做一些测试。别相信我的话。

        2
  •  2
  •   Oddthinking    14 年前

    我的总结正确吗?

    你想每分钟完成数千项任务,但你不确定是否能按时完成?

    你需要决定什么时候你开始超过你的时间表。

    • 你会一直走到结束,然后马上重新开始吗?
    • 你一直走到结束,然后等一分钟,然后重新开始吗?
    • 你是否中止这个过程,不管它到达哪里,然后重新开始?
    • 您是否会降低频率(例如从现在开始,每2分钟一次)?
    • 您是否同时运行了两个进程,并希望下次运行更快(如果您第一次清除积压工作,这可能会起作用,因此第二次运行会很快运行。)

    这些问题的答案取决于应用程序。根据答案,cron可能不是适合您的工具。您最好让一个进程永久地运行和调度自己。

        3
  •  1
  •   Alex Weinstein    14 年前

    数据库可以同时处理大量的记录。如果你一个接一个地处理它们,你就是在找麻烦。您需要找到一种方法来成批处理您的“每分钟”任务,这样通过执行单个(复杂)查询,可以检索所有受影响用户的信息;然后,您可以对结果进行PHP处理;然后,在另一个查询中,您可以将结果推回到数据库中。

        4
  •  1
  •   UtahPhunk    14 年前

    根据你对大局的描述,听起来你有一个死胡同的设计。如果你能让它现在工作,它很可能是非常脆弱的,它不会扩大。

    我猜,如果您无法控制外部服务,那么外部服务可能不高兴被这样的脚本重击。你有没有向他们提出你的总体计划?

    你真的每次都需要做所有的用户吗?您是否可以使用任何类型的时间戳来选择哪些用户需要“更新”?如果你能更好地描述目标,我们也许能给出更具体的建议。

        5
  •  1
  •   Oddthinking    14 年前

    如果您明确希望同时运行用户处理…

    最简单的解决方案是让每个用户都有一个线程。在Windows上,线程比进程便宜得多。

    然而,无论您使用线程还是进程,同时运行数千个线程几乎肯定是行不通的。

    相反,有一个 水塘 线程的池的大小取决于您的机器一次可以轻松处理多少线程。我希望像30-150这样的数字能达到你想达到的程度,但这在很大程度上取决于硬件的容量,我可能会以另一个数量级退出。

    每个线程都将从共享队列中获取下一个要处理的用户,对其进行处理,并将其放回队列的末尾,可能具有不应在其之前进行处理的日期。

    (根据处理的数量和类型,可以在数据库的单独框中执行此操作,以确保数据库不会被与数据库无关的处理超载。)

    此解决方案确保始终处理尽可能多的用户,而不会使机器过载。随着用户数量的增加,处理它们的频率降低了,但总是尽可能快地处理硬件。