アーキテクチャに関する知識を広げ、インタビューでシステム設計の質問について考える能力を高めるために、汎用ジョブスケジューラを設計しようとしています。これまでのところ、私が思いついたのは以下のとおりです。この種の問題に取り組むための私のアプローチにおいて包括的になるためにどこに取り組むべきかを指摘できますか?
オンラインで多くのリソースを読みましたが、前進するための具体的なガイダンスが必要です。
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)マスター/スレーブレプリケーションでマスター/スレーブレプリケーション戦略を使用して、データの冗長性を確保する
結論
したがって、これがジョブスケジューラのコンポーネントの設計になります。
ほとんどの大規模なジョブスケジューラは、ドキュメントでカバーされていない側面を考慮します。
主な問題のいくつかは次のとおりです(順不同)。
まだまだヒープがあると思います-その他のアイデアについては、 slurm または grid-engine のドキュメントを参照してください。
さらに考慮すべきこと:
あなたが説明することの多くは、ジョブをスケジューリングして実行するためのさまざまなフレームワークによって実装されています。私が知っているもの- クオーツ 。私はQuartzでいくつか異なる方法で実装しますが、それは十分に文書化されており、仕事と彼らが通常直面する障害について多くのアイデアを提供します。
あなたが説明しているアプローチは良いですが、ドメイン固有の問題(並列処理、シャーディング、スケーリングなど)を排除します。ジョブが別のマシンで実行される場合、それは具体的なケース(例:金融銀行で実行されるジョブ)が1つのマシンに収まらないためです。ジョブエンジンの開発者として、あなたはそれについて心配する必要はないと思います。理由は、製品化されたアプリケーションではなくフレームワークを開発しているためです。
ジョブエンジン自体にシャーディングを導入する場合、ジョブエンジン自体の複雑さを過大評価していると思います。ジョブ実行(フレームワーク)部分自体に大きな不測の事態はありません。ただし、バンキングソフトウェアジョブなどの具体的な実装では、同じデータを処理する必要がある場合がありますが、そのデータセットは異なるため、シャーディングが発生します。つまり、要するに、スケーリングメカニズムを導入することは、あなたの能力の範囲外です。
そしてもう1つは、ジョブ実行とメッセージングバスの間に類似点がないため、その方向についてはコメントしていません。
この仕事のメッセージバスを調べることをお勧めします。または、そのようなバスが許可するアーキテクチャを学習したい場合は、NServiceBusを参照してください。
バスを使用している場合は、キューを簡単にスロットルできます。処理が遅くなる可能性があります。つまり、並行性を調べる必要があります。
そのようなサービスを書くのは簡単だとよく考えられています。そうではない。
他に考えるべきこと.
メッセージが失敗したときに何が起こったか。迷子になりますか?ロールバックしますか?アーキテクチャをどのように拡張しますか。新しいクライアント/消費者を簡単に追加できますか?