1

我的情况 ...

我有一组计划定期运行的工作人员,每个工作时间间隔不同,并且希望找到一个好的实现来管理他们的执行。

示例:假设我有一个工人每周去商店给我买一次牛奶。我想将此作业及其配置存储在 mysql 表中。但是,轮询表(每秒?)并查看哪些作业已准备好放入执行管道似乎是一个非常糟糕的主意。

我所有的工作人员都是用 javascript 编写的,所以我使用 node.js 执行,beantalkd作为管道。

如果正在异步创建新作业(即安排工作人员在给定时间运行)并且我需要持久存储作业结果和配置,我如何避免轮询表?

谢谢!

4

2 回答 2

2

我同意这似乎不优雅,但考虑到计算机工作的方式*某处*将不得不进行某种轮询,以便确定何时执行哪些作业。所以,让我们来看看你的一些选择:

  1. 轮询数据库表。这根本不是一个坏主意——如果您将作业存储在 MySQL 中,这可能是最简单的选择。每秒一个查询的速度没什么——试一试,你会发现你的系统甚至感觉不到它。

    一些想法可以帮助您将其扩展到每秒可能数百个查询,或者只是降低系统资源需求:

    • 创建第二个表“job_pending”,您可以在其中放置需要在接下来的 X 秒/分钟/小时内执行的作业。
    • 在较长时间内仅在所有作业的大表上运行一次查询,然后填充您每隔较短时间查询的小表。
    • 从小表中删除已执行的作业以使其保持小。
    • 在您的“execute_time”(或您所称的任何名称)列上使用索引。
  2. 如果您必须进一步扩展,请将主作业表保留在数据库中,并使用我建议的第二个较小的表,只需将该表放在 RAM 中:要么作为数据库引擎中的内存表,要么放在一些队列中在你的程序中。如果您也有的话,请以极短的时间间隔查询队列 - 需要一些极端的用例才能在此处引起任何性能问题。

    此选项的主要问题是您必须跟踪内存中但未执行的作业,例如由于系统崩溃 - 为您编写更多代码......

  3. 为一堆作业中的每一个创建一个线程(例如,所有需要在下一分钟执行的作业),然后调用 thread.sleep(millis_until_execution_time) (或者其他什么,我对 node.js 不太熟悉)。

    这个选项和 no 有同样的问题。2 - 您必须跟踪作业执行以进行崩溃恢复。这也是最浪费的imo - 每个休眠的作业线程仍然占用系统资源。

当然可能还有其他选择 - 我希望其他人回答更多想法。

只要意识到每秒轮询数据库并不是一个坏主意。这是 imo 最直接的方式(记住 KISS),按照这种速度,您不应该遇到性能问题,因此请避免过早的优化。

于 2011-04-09T07:04:16.117 回答
1

为什么不在Jobnode.js 中有一个保存到数据库的对象。

var Job = {
   id: long,
   task: String,
   configuration: JSON,
   dueDate: Date,
   finished: bit
};

我建议您只将 id 存储在 RAM 中,并将所有其他Job数据保留在数据库中。当您的超时功能最终运行时,它只需要知道.id获取其他数据。

var job = createJob(...); // create from async data somewhere.
job.save(); // save the job.
var id = job.id // only store the id in RAM
// ask the job to be run in the future.
setTimeout(Date.now - job.dueDate, function() {
    // load the job when you want to run it
    db.load(id, function(job) {
        // run it.
        run(job);
        // mark as finished
        job.finished = true;
        // save your finished = true state
        job.save();
    });
});
// remove job from RAM now.
job = null;

如果服务器崩溃,您只需查询所有具有 的作业,将[finished=false]它们加载到 RAM 并再次启动 setTimeouts。

如果出现任何问题,您应该能够像这样干净地重新启动:

db.find("job", { finished: false }, function(jobs) {
    each(jobs, function(job) {
         var id = job.id;
         setTimeout(Date.now - job.dueDate, function() {
             // load the job when you want to run it
             db.load(id, function(job) {
                 // run it.
                 run(job);
                 // mark as finished
                 job.finished = true;
                 // save your finished = true state
                 job.save();
             });
         });
         job = null;
    });
});
于 2011-04-11T16:36:56.777 回答