20

Quartzスケジューラが1秒間に実行できるジョブの数には制限があるようです。このシナリオでは、1秒あたり約20のジョブが24時間365日起動し、クォーツは1秒あたり最大10のジョブ(JDBCがサポートするJobStoreの場合は100のクォーツスレッドと100のデータベース接続プールサイズ)で正常に機能しましたが、20に増やすと1秒あたりのジョブ数が非常に遅くなり、トリガーされたジョブが実際のスケジュールされた時間に比べて非常に遅くなり、多くの失火が発生し、最終的にシステムの全体的なパフォーマンスが大幅に低下します。興味深い事実の1つはJobExecutionContext.getScheduledFireTime().getTime()、このような遅延トリガーの場合、スケジュール時刻から10〜20分、さらにはそれ以上になることです。

クォーツスケジューラーがジョブのスケジュールされた時間に影響を与えることなく1秒間に実行できるジョブの数と、そのような負荷に最適なクォーツスレッドの数はいくつですか?

それとも私はここで何かが欠けていますか?

達成したいことの詳細:

ほぼ1万個のアイテム(2つ以上のカテゴリに分類され、現在は2つのカテゴリがあります)があり、15、30、60 ...分の特定の頻度で処理する必要があり、これらのアイテムはその頻度で処理する必要があります1分あたりの特定のスロットルで。たとえば、60分間の頻度で、各カテゴリの5kアイテムは、1分あたり500アイテムのスロットルで処理する必要があるとします。したがって、理想的には、これらのアイテムは1日の各時間の最初の10(5000/500)分以内に処理され、1分ごとに500個のアイテムが処理され、1分ごとに1秒ごとに均等に分散されるため、約8分になります。 1つのカテゴリで1秒あたり9アイテム。

これを実現するために、これらのアイテムを処理するためのジョブをトリガーするスケジューラーとしてQuartzを使用しました。ただし、Job.executeメソッドで各アイテムを処理することはありません。これは、Webサービス呼び出しを含むアイテム処理ごとに5〜50秒(平均30秒)かかるためです。むしろ、 JMSキューで処理するアイテムごとにメッセージをプッシュし、別々のサーバーマシンがそれらのジョブを処理します。Job.executeメソッドにかかる時間が30ミリ秒を超えないことに気づきました。

サーバーの詳細:

Solaris Sparc 64ビットサーバー(8/16コア/スレッドCPU)、16GB RAMのスケジューラー用。スケジューラークラスターには、このようなマシンが2台あります。

4

5 に答える 5

12

以前のプロジェクトで、私は同じ問題に直面しました。私たちの場合、クォーツは1秒の粒度で優れたパフォーマンスを発揮しました。1秒未満のスケジューリングは一気に進み、観察しているように、失火が頻繁に発生し、システムの信頼性が低下しました。

2つのレベルのスケジューリングを作成することでこの問題を解決しました。Quartzはn個の連続するジョブのジョブ「セット」をスケジュールします。クラスタ化されたQuartzの場合、これは、システム内の特定のサーバーがこのジョブを「設定」して実行することを意味します。次に、セット内のn個のタスクが「マイクロスケジューラー」によって取り込まれます。基本的には、ネイティブJDK APIを使用して、ジョブを10ミリ秒の粒度までさらに計測するタイミング機能です。

個々のジョブを処理するために、マスターワーカーの設計を使用しました。この設計では、マスターがマルチスレッドのワーカープールへのジョブのスケジュールされた配信(スロットリング)を処理していました。

今日もこれを行う必要がある場合は、ScheduledThreadPoolExecutorを使用して「マイクロスケジューリング」を管理します。あなたの場合、それは次のようになります:

ScheduledThreadPoolExecutor scheduledExecutor;
...
    scheduledExecutor = new ScheduledThreadPoolExecutor(THREAD_POOL_SIZE);
...

// Evenly spread the execution of a set of tasks over a period of time
public void schedule(Set<Task> taskSet, long timePeriod, TimeUnit timeUnit) {
    if (taskSet.isEmpty()) return; // or indicate some failure ...
    long period = TimeUnit.MILLISECOND.convert(timePeriod, timeUnit);
    long delay = period/taskSet.size();
    long accumulativeDelay = 0;
    for (Task task:taskSet) {
        scheduledExecutor.schedule(task, accumulativeDelay, TimeUnit.MILLISECOND);
        accumulativeDelay += delay;
    }
}

これにより、JDK機能を使用してタスクをマイクロスケジュールする方法に関する一般的なアイデアが得られます。(免責事項:失敗したタスクのチェック、再試行の管理(サポートされている場合)など、本番環境に対してこれを堅牢にする必要があります...)。

いくつかのテストと調整により、Quartzジョブと1つのスケジュールされたセット内のジョブの量との間の最適なバランスが見つかりました。

このようにして、スループットが100倍向上しました。ネットワーク帯域幅が実際の制限でした。

于 2012-07-19T18:29:54.957 に答える
6

まず最初に、JDBC-JobStoreのパフォーマンスを改善するにはどうすればよいですか?Quartzのドキュメント。

ご想像のとおり、絶対値と明確なメトリックがあります。それはすべてあなたの設定に依存します。ただし、ここにいくつかのヒントがあります。

  • 1秒あたり20ジョブは、更新とロックを含め、1秒あたり約100のデータベースクエリを意味します。それはかなりたくさんです!

  • Quartzセットアップをクラスターに配布することを検討してください。ただし、データベースがボトルネックである場合、それは役に立ちません。多分TerracottaJobStore救助に来るのだろうか?

  • システムにKコアがあると、システムが十分に活用されなくKなります。ジョブがCPUを集中的に使用する場合Kは、問題ありません。外部のWebサービスを呼び出している場合、ブロックしている場合、またはスリープしている場合は、はるかに大きな値を検討してください。ただし、100〜200を超えるスレッドは、コンテキストの切り替えによりシステムの速度を大幅に低下させます。

  • プロファイリングを試しましたか?あなたのマシンはほとんどの時間何をしていますか?スレッドダンプを投稿できますか?CPUではなくデータベースのパフォーマンスが低いと思われますが、ユースケースによって異なります。

于 2012-07-19T17:23:52.907 に答える
2

スレッドの数を、使用可能なプロセッサの数との間nのどこかに制限する必要がn*3あります。nより多くのスレッドをスピンアップすると、ほとんどの場合ブロックされるため、多くのコンテキスト切り替えが発生します。

1秒あたりのジョブ数に関しては、実際には、ジョブの実行時間と、ネットワークやディスクioなどの操作のためにジョブがブロックされる頻度によって異なります。

また、考慮すべきことは、おそらくクォーツはあなたが必要とするツールではないということです。1日に1〜200万のジョブを送信する場合は、カスタムソリューションを検討することをお勧めします。1日200万の仕事で何をしているの?

別のオプションは、問題に取り組むための非常に悪い方法ですが、時々機能します...それが実行されているサーバーは何ですか?古いサーバーですか?それはラムをぶつけているかもしれません、またはそれに他のスペックはあなたにいくつかの余分な「アンフ」を与えるでしょう。確かに最善の解決策ではありません。それは問題を遅らせるのであり、対処するのではありませんが、危機に瀕している場合は役立つかもしれません。

于 2012-07-19T17:19:51.973 に答える
0

1秒あたりのジョブ数が多い状況では、SQLサーバーがテーブルロックではなく行ロックを使用していることを確認してください。mysqlでは、これはInnoDBストレージエンジンを使用して実行され、テーブルロックのみを提供するデフォルトのMyISAMストレージエンジンではありません。

于 2014-08-19T10:49:15.310 に答える
0

基本的に、一度に1つのアイテムを実行するというアプローチは、非常に多くのことを短時間で処理する場合、運命が悪く非効率的です。物事をグループ化する必要があります-個々のジョブをマイクロスケジュールするジョブセットを使用するという提案されたアプローチは最初のステップですが、それでもジョブごとにほとんど何もしないことを意味します。Webサービスを改善して、一度にN個のアイテムを処理するように指示し、処理するアイテムのセットを使用してWebサービスを呼び出すことができるようにすることをお勧めします。さらに良いのは、Webサービスを介してこの種のことを行わないようにし、それらすべてをデータベース内でセットとして処理することです。これは、データベースに適しています。一度に1つのアイテムを処理するあらゆる種類のジョブは、基本的にスケーラブルでない設計です。

于 2017-10-09T18:27:43.210 に答える