web-dev-qa-db-ja.com

一般的なジョブスケジューラを設計する

アーキテクチャに関する知識を広げ、インタビューでシステム設計の質問について考える能力を高めるために、汎用ジョブスケジューラを設計しようとしています。これまでのところ、私が思いついたのは以下のとおりです。この種の問題に取り組むための私のアプローチにおいて包括的になるためにどこに取り組むべきかを指摘できますか?

オンラインで多くのリソースを読みましたが、前進するための具体的なガイダンスが必要です。

X社(今日の大手テクノロジー企業の1つ)の汎用ジョブスケジューラを設計します。

使用例

ジョブの作成/読み取り/更新/削除

過去に実行されたジョブを調査する(ジョブのタイプ、費やされた時間、詳細)

制約

1秒間にシステムでいくつのジョブが実行されますか?

=ユーザーによる#ジョブ/時間+マシンによる#ジョブ/時間

= 1m * 0.5/day/24/3600 + 1m/50 * 20/24/3600

〜= 12ジョブ/秒

システムはどのくらいのデータを保存する必要がありますか?

理由:私はジョブの実行の詳細のみを保存しています。実際の作業(スクリプトの実行)は他のマシンで行われ、収集されたデータの一部は終了時間、成功/失敗のステータスなどです。これらはおそらく単なるテキストであり、おそらく説明のためにグラフ化されています。 >>データをジョブスケジューラを介してシステムで実行されるすべてのジョブを保存します(つまり、過去10年間)

=(ジョブの詳細が設定されているページのサイズ+ジョブについて収集されるデータのサイズ)*ジョブの数* 365>日* 10年= 1 MB * 900 000 * 365 * 10

〜= 3600 000 000 MB

= 3600 000 GB

= 3600 TB = 3.6 PB

抽象的なデザイン

上記の情報に基づいて、データを保持するために多くのマシンを用意する必要はありません。デザインを次のように分割します。

アプリケーション層:はリクエストを処理し、UIの詳細を表示します。

データストレージレイヤー:大きなハッシュテーブルのように機能します:キーと値のマッピングを保存します(キーは、実行されたdateTimeで整理されたジョブですが、値はこれらのジョブの詳細を示します)。これは、履歴および/またはスケジュールされたジョブを簡単に検索できるようにするためです。

ボトルネック:

トラフィック:12ジョブ/秒はそれほど難しくありません。これが急上昇した場合は、ロードバランサーを使用して、ジョブを異なるサーバーに分散して実行できます。

データ:3.6 TBでは、アプリケーションで実行されたジョブへの高速アクセスのために簡単にクエリできるハッシュテーブルが必要です。

抽象的なデザインのスケーリング

このジョブスケジューラの性質は、各ジョブがいくつかの状態(保留、失敗、成功、終了)の1つを持っていることです。ビジネスロジックなしデータをほとんど返しません。

トラフィックを処理するために、12リクエスト/秒を処​​理するアプリケーションサーバーと、これが失敗した場合のバックアップを用意できます。将来、ロードバランサーを使用して、各サーバーに送信される要求の数を減らすことができます(1つ以上のサーバーが稼働していると想定)。これの利点は、要求/サーバーの数を減らし、可用性を高めることです(1つのサーバーに障害が発生した場合、スパイクのようなトラフィックを適切に処理します)。

データストレージの場合は、3.6 TB=のデータを格納するために、データベースに保持するために数台のマシンが必要になります。noSQLdbまたはSQL dbを使用できます。後者の方がより広く普及し、コミュニティが問題のトラブルシューティングに役立ち、現在大企業で使用されているサポートでは、mySQL dbを選択します。

データが増えるにつれて、次の方法でデータを処理します。

1)ハッシュに一意のインデックスを作成する

2)メモリを追加してmySQL dbを垂直方向にスケーリングします

3)シャーディングによりデータを分割する

4)マスター/スレーブレプリケーションでマスター/スレーブレプリケーション戦略を使用して、データの冗長性を確保する

結論

したがって、これがジョブスケジューラのコンポーネントの設計になります。

15
stretchr

ほとんどの大規模なジョブスケジューラは、ドキュメントでカバーされていない側面を考慮します。

主な問題のいくつかは次のとおりです(順不同)。

  • キャンセル-多くの場合、長時間実行中のジョブを強制終了するか、ジョブを実行しないようにします。
  • 優先度-多くの場合、優先度の高いジョブを優先度の低いジョブよりも優先して実行します。しかし、多くのジョブが生成されるシステムで、優先度の低いジョブが永遠に待機しない方法でこれを実装することは「簡単ではない」
  • リソース-一部のジョブは、特定のリソースを持つシステムでのみスケジュール可能です。例えば。いくつかは、大量のメモリ、または高速のローカルディスク、または高速のネットワークアクセスを必要とします。これらを効率的に割り当てるのは注意が必要です。
  • 依存関係-一部のジョブは、他のジョブが完了して初めて実行可能になる可能性があるため、一定時間前にスケジュールすることができません。
  • 期限-一部のジョブは所定の時間までに完了する必要があります。 (または少なくとも所定の時間までに開始されます。)
  • 権限-一部のユーザーは、特定のリソースグループ、特定のプロパティ、または特定の数のジョブなどにのみジョブを送信できます。
  • 割り当て-一部のシステムでは、ユーザーに指定されたシステム時間を与え、ジョブを実行すると、それから差し引かれます。これにより、例の数値に大きな違いが生じる可能性があります。
  • 一時停止-一部のシステムでは、ジョブをチェックポイントして一時停止し、後で再開することができます。

まだまだヒープがあると思います-その他のアイデアについては、 slurm または grid-engine のドキュメントを参照してください。

さらに考慮すべきこと:

  1. あなたの抽象的なデザインは、おそらくこれらの高度な概念をサポートするために、より多くの詳細が必要です。
  2. その3.6 TBのデータのほとんどに頻繁にアクセスする必要はありません-最近のデータと古いデータに分割します。古いデータへのアクセスを遅くする(そしてディスクにヒットする)と、管理しやすいデータベースサイズになります。 。
  3. おそらく「admins」と「users」という異なるカテゴリのユーザーがいると思います。これは、アプリケーションの構造にとってどのような意味がありますか。
  4. 実際のジョブスケジューリングアプリケーションは、1秒あたりにより多くの要求を処理できます。スラームは、バーストがより高い33 /秒の持続を示唆していますが、私の理解では、これよりも大幅に高くなる可能性があります。
  5. Webページ以外のインターフェイスを介してジョブを送信したり、ジョブの状態を照会したりする必要があるのはよくあることです。これは、アプリケーションの構造にとって何を意味するのでしょうか。 (私はコアエンジンにシンプルな送信APIを使用し、それにWeb UIをダムトランスレータとして使用し、すべての追加メソッドで同じAPIを使用するか、REST API withそれへの単純なウェブフロントエンド))
  6. サーバーの障害をどのように検出しますか?これを確実に判断するには、2台のサーバーで十分ですか?これには定足数ベースの測定、または3番目のサーバーへの接続テストを使用するのが一般的です。障害が発生したサーバーがオンラインに戻った場合はどうしますか?
26

あなたが説明することの多くは、ジョブをスケジューリングして実行するためのさまざまなフレームワークによって実装されています。私が知っているもの- クオーツ 。私はQuartzでいくつか異なる方法で実装しますが、それは十分に文書化されており、仕事と彼らが通常直面する障害について多くのアイデアを提供します。

あなたが説明しているアプローチは良いですが、ドメイン固有の問題(並列処理、シャーディング、スケーリングなど)を排除します。ジョブが別のマシンで実行される場合、それは具体的なケース(例:金融銀行で実行されるジョブ)が1つのマシンに収まらないためです。ジョブエンジンの開発者として、あなたはそれについて心配する必要はないと思います。理由は、製品化されたアプリケーションではなくフレームワークを開発しているためです。

ジョブエンジン自体にシャーディングを導入する場合、ジョブエンジン自体の複雑さを過大評価していると思います。ジョブ実行(フレームワーク)部分自体に大きな不測の事態はありません。ただし、バンキングソフトウェアジョブなどの具体的な実装では、同じデータを処理する必要がある場合がありますが、そのデータセットは異なるため、シャーディングが発生します。つまり、要するに、スケーリングメカニズムを導入することは、あなたの能力の範囲外です。

そしてもう1つは、ジョブ実行とメッセージングバスの間に類似点がないため、その方向についてはコメントしていません。

4
Tengiz

この仕事のメッセージバスを調べることをお勧めします。または、そのようなバスが許可するアーキテクチャを学習したい場合は、NServiceBusを参照してください。

バスを使用している場合は、キューを簡単にスロットルできます。処理が遅くなる可能性があります。つまり、並行性を調べる必要があります。

そのようなサービスを書くのは簡単だとよく考えられています。そうではない。

他に考えるべきこと.

メッセージが失敗したときに何が起こったか。迷子になりますか?ロールバックしますか?アーキテクチャをどのように拡張しますか。新しいクライアント/消費者を簡単に追加できますか?

2
jcon45