1

私の状況 ...

それぞれ異なる間隔で定期的に実行するようにスケジュールされた一連のワーカーがあり、それらの実行を管理するための適切な実装を見つけたいと考えています。

例:店に行って週に1回ミルクを買ってくれる労働者がいるとしましょう。このジョブとその構成をmysqlテーブルに保存したいと思います。しかし、テーブルをポーリングして(毎秒?)、実行パイプラインに入れる準備ができているジョブを確認するのは、本当に悪い考えのようです。

私のワーカーはすべてjavascriptで記述されているため、実行にはnode.jsを使用し、パイプラインとしてbeanstalkdを使用しています。

新しいジョブ(つまり、特定の時間に実行するようにワーカーをスケジュールする)が非同期で作成されており、ジョブの結果と構成を永続的に保存する必要がある場合、テーブルのポーリングを回避するにはどうすればよいですか?

ありがとう!

4

2 に答える 2

2

私はそれがエレガントではないように見えることに同意しますが、コンピュータが*どこか*で何かを動作させる方法を考えると、どのジョブをいつ実行するかを判断するために何らかのポーリングを行う必要があります。それでは、いくつかのオプションについて見ていきましょう。

  1. データベーステーブルをポーリングします。これはまったく悪い考えではありません-とにかくMySQLにジョブを保存している場合は、おそらく最も簡単なオプションです。1秒あたり1クエリの速度は何もありません。試してみると、システムがそれを感じていないことに気付くでしょう。

    これを1秒あたり数百のクエリにスケーリングする、またはシステムリソース要件を抑えるのに役立ついくつかのアイデア:

    • 2番目のテーブル'job_pending'を作成します。このテーブルには、次のX秒/分/時間以内に実行する必要のあるジョブを配置します。
    • すべてのジョブの大きなテーブルに対して、長い間一度だけクエリを実行してから、短い間ごとにクエリする小さなテーブルにデータを入力します。
    • 小さいテーブルを維持するために、小さいテーブルから実行されたジョブを削除します。
    • 'execute_time'(またはあなたがそれを呼ぶもの)列にインデックスを使用します。
  2. さらに拡張する必要がある場合は、メインのジョブテーブルをデータベースに保持し、2番目の小さいテーブルを使用して、そのテーブルをRAMに配置します。DBエンジンのメモリテーブルとして、またはいくつかのキューに配置します。あなたのプログラムに親切にしてください。キューがある場合は、非常に短い間隔でクエリを実行します。ここでパフォーマンスの問題が発生する場合は、極端なユースケースが必要になります。

    このオプションの主な問題は、メモリ内にあったが実行されなかったジョブを追跡する必要があることです。たとえば、システムクラッシュが原因で、コーディングが増えます...

  3. 一連のジョブ(たとえば、次の分に実行する必要があるすべてのジョブ)ごとにスレッドを作成し、thread.sleep(millis_until_execution_time)(または、node.jsにあまり詳しくない)を呼び出します。

    このオプションには、noと同じ問題があります。2-クラッシュリカバリのためにジョブの実行を追跡する必要がある場所。これは、最も無駄なimoでもあります。スリープ状態のすべてのジョブスレッドは、依然としてシステムリソースを使用します。

もちろん、追加のオプションがあるかもしれません-他の人がもっと多くのアイデアで答えてくれることを願っています。

DBを毎秒ポーリングすることはまったく悪い考えではないことを理解してください。これは、imo(KISSを思い出してください)の最も簡単な方法です。このレートでは、パフォーマンスの問題は発生しないはずなので、時期尚早の最適化は避けてください。

于 2011-04-09T07:04:16.117 に答える
1

Jobデータベースに保存されているオブジェクトをnode.jsに入れてみませんか。

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

JobIDのみをRAMに保存し、他のすべてのデータはデータベースに残すことをお勧めします。タイムアウト関数が最終的に実行されるとき、.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 に答える