2

私は Mircosoft Orleans をベースとしてワークフロー エンジンに取り組んでいます。これは、作業の自動分散やフェイルオーバーの処理など、多くの便利な機能を提供するためです。

私は3種類の穀物を持っています:

  • ワークフロー - ワークフロー内の情報と、作業ブロックを実行する順序を保持します
  • 作業ブロック - 実際に作業を行う部分
  • 実行 - ワークフローの 1 回の実行

私の問題は、多数の現在の実行を実行している場合、つまり > 1000 の場合、パフォーマンスが実際に低下することです。少しプロファイリングを行い、これを粒子間で発生する通信に絞り込みました。とにかくこれ以上改善できることはありますか?

これが私のコードの概要と穀物がどのように相互作用するかです

実行グレインはループ内にあり、ワークフローから次の作業ブロックを取得し、その作業ブロックで execute を呼び出します。テスト ワークフローの 1 つの実行時間が、1 回の実行で 10 秒、1000 回以上実行すると約 5 分になる原因となっているのは、グレイン間のこの絶え間ない呼び出しです。これを改善できるか、またはソリューションを再構築する必要があります。グレイン通信を削除するには?

[StorageProvider(ProviderName = "WorkflowStore")]
[Reentrant]
[StatelessWorker]
public class Workflow : Grain<WorkflowState>, IWorkflow
{
    public Task<BlockRef> GetNext(Guid currentBlockId, string connectionName)
    {
         //Lookup the next work block
    }
}

[Reentrant]
[StatelessWorker]
public class WorkBlock : Grain<WorkBlock State>, IWorkBlock 
{
    public Task<string> Execute(IExecution execution)
    {
         //Do some work
    }
}


[StorageProvider(ProviderName = "ExecutionStore")]
public class Execution : Grain<ExecutionState>, IExecution, IRemindable
{
    private async Task ExecuteNext(bool skipBreakpointCheck = false)
    {            
        if (State.NextBlock == null)
        {
            await FindAndSetNext(null, null);
        }

        ...

        var outputConnection = await workblock.Execute();

        if (!string.IsNullOrEmpty(outputConnection))
        {
            await FindAndSetNext(State.NextBlock.Id, outputConnection);
            ExecuteNext().Ignore();
        }
    }

    private async Task FindAndSetNext(Guid? currentId, string outputConnection)
    {
        var next = currentId.HasValue ? await _flow.GetNextBlock(currentId.Value, outputConnection) : await _flow.GetNextBlock();
        ...
    }
}
4

2 に答える 2

5

ここにいくつかの問題があります:

1) Workflow が StatelessWorker であり、かつ StorageProvider を使用するのは正しくないようです。StorageProvider は、あまりにも永続的であることを気にかけている状態があることを意味し、StatelessWorker は、状態がないことを意味します。代わりに、StatelessWorker 以外の通常のグレインを使用します。

2) モデリングを上から見てみましょう: ワークフローは、ワークフローに関するデータと実行するコードです。WorkBlock は、マルチ ブロック ワークフローの 1 つのブロック (マルチステップ ワークフローの 1 ステップ) ですよね? そのような場合、それらのどれも穀物であってはなりません。それらは単なる状態です。穀物である必要があるのは実行だけです。実行はワークフローを受け取り、ワークフローはそのデータ内で次のブロックをエンコードし、実行は単にブロックを実行します。

3) スケーラビリティの観点から、多くの実行グレインが必要です。ワークフローに ID がある場合、ワークフロー ID ごとに実行粒度を使用できます。同じワークフロー (同じ ID を持つ) を複数回並行して実行する場合は、依存します。並列処理が多すぎない場合は、1 つの実行グレインで十分でしょう。そうでない場合は、X 実行グレインのプールを使用できます (実行グレインの ID は「WorkflowId-NumberBetween0AndX になります)。

于 2016-06-02T05:58:59.260 に答える
1

私の意見では、これらの関数はスタンドアロンのグレインであってはなりません。それらを集約すると、高価なグレイン間通信が不要になります。

Work BlockActivityに、ExecutionWorkflowInstanceに名前変更すると、概念は Microsoft の Workflow Foundation と非常によく似たものになります。Orleans で WF4 ワークフローを実行するために、GitHub ( Orleans.Activities ) でプロジェクトを開始しました。本番環境には対応していませんが、パフォーマンス テストはありませんが、少なくとも動作します。試してみるといいかもしれません。

于 2016-05-23T04:31:03.150 に答える