1

主に教育目的で、タスクを作成しようとしています (タスクは open_port({spawn_executable, Command})) スケジューラです。

私は次のような木になってしまいます

        supervisor
        |        |
scheduler        receiver
gen_event        gen_event
                     |
                supervisor
                     |
                dispatcher
                gen_server
                     |
                supervisor
                |    |   |
             task1  ... taskN

言い換えると:

  1. トップスーパーバイザーはスケジューラーとレシーバーを開始し、それらが有効であることを確認します
  2. レシーバーは中間スーパーバイザーを開始します
  3. 中間スーパーバイザーがディスパッチャーを開始し、それが有効であることを確認します
  4. ディスパッチャが下部スーパーバイザを開始
  5. 最下層のスーパーバイザーは、要求に応じてタスクを開始し、エラーが発生した場合にタスクが再開されるようにします

  6. スケジューラーはいつでも、実行されるべきタイムスタンプを持つタスクを受け入れる準備ができています

  7. タイムスタンプが満たされると、いくつかの event_manager に通知します
  8. レシーバーは同じイベント マネージャーから通知を受け、中間スーパーバイザーを介してメッセージをディスパッチャーに渡します。
  9. ディスパッチャーには、ステートレスではないビジネス ロジックがあります。たとえば、ある種のタスクを同時に実行することはできません。
  10. すべての条件が満たされると、ディスパッチャーはタスクを下部のスーパーバイザーに渡します。これにより、通常の終了が得られるか、いくつかのしきい値がバイパスされるまで、タスクが確実に実行されます
  11. 一番下のスーパーバイザーがメッセージを返し、それがイベント マネージャーに上から下に渡されます
  12. スケジューラは最終的にこのメッセージを受け取り、タスクをキューから削除するか、キューに再登録します。

質問は次のとおりです。

  1. ビヘイビアーを正しく使用していますか?
  2. 構造が複雑すぎませんか?(ただし、将来的にはシステムは分散化される予定です。)
  3. 同時に4つの動作を実装する4つの代わりに、レシーバー+ミドルスーパーバイザーとディスパッチャー+ボトムスーパーバイザーを2つのモジュールに組み合わせる方法はありますか?
  4. または、レシーバー + ディスパッチャー + ボトム スーパーバイザーを 1 つのモジュールに組み合わせて、中間スーパーバイザーの必要性をなくし、gen_event + gen_server + スーパーバイザーの動作を同時に実装する方法はありますか?
  5. OO 言語のインターフェイスまたは多重継承としての振る舞いを間違って考えているのでしょうか? (それで私は質問 3 と 4 を尋ねます。)

前もって感謝します。

PS IMO、一方で、構造が複雑すぎます。一方、このような構造では、そのブロックを分散させることができます (たとえば、多くのスケジューラーを 1 つのレシーバーに、1 つのスケジューラーを多くのレシーバーに、多くのスケジューラーを多くのレシーバーに、多くのディスパッチャーを各レシーバーに、さらに多くのボトム スーパーバイザーを各ディスパッチャーに)。 - 独自の監督ポリシーを持つすべてのレイヤー)。複雑さと拡張性のバランス ポイントはどこにありますか?

4

1 に答える 1

1

私が提案するのは、次のように設計を単純化することです。

        supervisor
        |        |
 dispatcher      |
 +scheduler      |
                 |
            supervisor
            |    |   |
         task1  ... taskN

タスクなどを開始するディスパッチャーに別のスケジューラーがイベントを送信することによるメリットはあまりありません。分散の観点からでも。

ディスパッチャー・スケジューラーはおそらくタイマー・モジュールの助けを借りて非常に簡単に行うことができ、gen_server にすることができます。タイマーは、handle_info コールバックで処理できるメッセージを送信するか、gen_server の API 関数を呼び出すことができます。

新しい「タスク」を追加するときにタイマーをキャンセルすることを心配する必要がないため、タイムアウト機能を使用して、次の間隔の後に gen_server をウェイクアップすることもできます。

次に、ディスパッチャー/スケジューラーが呼び出しsupervisor:start_childて、作業タスクを追加します。

ディストリビューションは簡単に追加できます。ディスパッチャー/スケジューラーは、第 2 レベルのスーパーバイザーとは別のノードに配置できます。タスク開始機能は、さらに分散することができ、負荷分散のためにプールモジュールを使用することもできます。

5 つの質問に答えるには:

  1. 不要な場所で gen_event を使用していると思われますが、モジュール自体は必要ないため、モジュールを削除することで簡単に修正できます。gen_event は、1 つのイベント ソースに多くのハンドラーを登録できるようにする場合、1:1 で使用します。スーパーバイザー ツリーは通常、他のスーパーバイザーの直接の子であるスーパーバイザーで構築されます。

  2. はい、複雑すぎます。表現力の低いオブジェクト指向言語で行うように見えます。そして、多分配布を準備するだけでは必要ありません。Erlang のような関数型言語でのリファクタリングは、おそらく思っているよりもはるかに簡単です。したがって、必要に応じて、シンプルで分割された機能から始めてください。

3+4。私のまったく異なる提案を参照してください。

  1. それはver OOのようなものではありません。OTP の動作は、ジェネリック モジュールのプロセス メカニクスを隠しているコールバック モジュールにすぎません。

私が提案した単純な構造でも、十分な柔軟性があります (Erlang によってもたらされました)。複数のスケジューラーが必要な場合は、rpc を使用してスーパーバイザーを呼び出すことができるからです。プールを使用して、タスクの分散を自動的に負荷分散できます。また、ディスパッチャー部分はスケジューラーから簡単に分離できます (両方ともトップレベルのスーパーバイザーの下で) スケジューラーから分離されたより一般的な状態を持つことができます。

于 2011-03-24T11:04:16.130 に答える