.NET Framework 4 には、パフォーマンスに大きな投資を行う Windows Workflow Foundation (WF) のメジャー リビジョンが含まれています。 この新しいリビジョンでは、.NET Framework 3.0 および .NET Framework 3.5 の一部として出荷された WF の以前のバージョンからの大幅な設計変更が導入されています。 これは、パフォーマンスと使いやすさを大幅に向上させるために、プログラミング モデル、ランタイム、およびツールのコアから再設計されています。 このトピックでは、これらのリビジョンの重要なパフォーマンス特性を示し、以前のバージョンと比較します。
個々のワークフロー コンポーネントのパフォーマンスは、WF3 と WF4 の間で桁違いに増加しています。 これにより、手でコード化された Windows Communication Foundation (WCF) サービスと WCF ワークフロー サービスの間のギャップは非常に小さくなります。 WF4 ではワークフローの待機時間が大幅に短縮されました。 永続化のパフォーマンスは、2.5 から 3.0 の係数で増加しました。 ワークフロー追跡による正常性の監視のオーバーヘッドが大幅に少なくなります。 これらは、アプリケーションで WF4 に移行したり、WF4 を導入したりする魅力的な理由です。
用語
.NET Framework 4 で導入された WF のバージョンは、このトピックの残りの部分では WF4 と呼ばれます。 WF は .NET Framework 3.0 で導入され、.NET Framework 3.5 SP1 を通じていくつかのマイナー リビジョンが行われました。 このトピックの残りの部分では、.NET Framework 3.5 バージョンの Workflow Foundation を WF3 と呼びます。 WF3 は、WF4 と並べて .NET Framework 4 に付属しています。 WF3 成果物を WF4 に移行する方法の詳細については、「 Windows Workflow Foundation 4 移行ガイド」を参照してください。
Windows Communication Foundation (WCF) は、サービス指向アプリケーションを構築するための Microsoft の統合プログラミング モデルです。 これは、WF3 と共に .NET Framework 3.0 の一部として最初に導入され、現在は .NET Framework の主要なコンポーネントの 1 つです。
Windows Server AppFabric は、IIS で実行される Web アプリケーションと複合アプリケーションの構築、スケーリング、管理を容易にする一連の統合テクノロジです。 サービスとワークフローを監視および管理するためのツールが用意されています。 詳細については、「 Windows Server AppFabric 1.0」を参照してください。
目標
このトピックの目的は、さまざまなシナリオで測定されたデータを含む WF4 のパフォーマンス特性を示することです。 また、WF4 と WF3 の詳細な比較も提供するため、この新しいリビジョンで行われた大幅な改善が示されます。 この記事で紹介するシナリオとデータは、WF4 と WF3 のさまざまな側面の基になるコストを定量化します。 このデータは WF4 のパフォーマンス特性を理解するのに役立ち、WF3 から WF4 への移行を計画したり、アプリケーション開発で WF4 を使用したりする場合に役立ちます。 ただし、この記事に記載されているデータから得られた結論には注意が必要です。 複合ワークフロー アプリケーションのパフォーマンスは、ワークフローの実装方法と、さまざまなコンポーネントの統合方法に大きく依存します。 各アプリケーションを測定して、そのアプリケーションのパフォーマンス特性を判断する必要があります。
WF4 パフォーマンスの機能強化の概要
WF4 は、次のセクションで説明する高パフォーマンスとスケーラビリティで慎重に設計および実装されました。
WF ランタイム
WF ランタイムの中核となるのは、ワークフロー内のアクティビティの実行を駆動する非同期スケジューラです。 これは、アクティビティに対してパフォーマンスの高い予測可能な実行環境を提供します。 環境には、実行、継続、完了、キャンセル、例外、および予測可能なスレッド モデルの明確に定義されたコントラクトがあります。
WF3 と比較して、WF4 ランタイムにはより効率的なスケジューラがあります。 WCF に使用されるのと同じ I/O スレッド プールが利用されます。これは、バッチ処理された作業項目の実行に非常に効率的です。 内部作業項目スケジューラー・キューは、最も一般的な使用パターン用に最適化されています。 WF4 ランタイムは、最小限の同期とイベント処理ロジックを使用して実行状態を非常に軽量な方法で管理しますが、WF3 は重いイベントの登録と呼び出しに依存して、状態遷移の複雑な同期を実行します。
データストレージとフロー
WF3 では、アクティビティに関連付けられたデータは、 DependencyProperty型によって実装される依存関係プロパティを使用してモデル化されます。 依存関係プロパティ パターンは、Windows Presentation Foundation (WPF) で導入されました。 一般に、このパターンは、簡単なデータ バインディングやその他の UI 機能をサポートするために非常に柔軟です。 ただし、このパターンでは、プロパティをワークフロー定義の静的フィールドとして定義する必要があります。 WF ランタイムがプロパティ値を設定または取得するたびに、重み付けされた検索ロジックが含まれます。
WF4 では、クリア データ スコープ ロジックを使用して、ワークフローでのデータの処理方法を大幅に改善します。 これは、変数と引数という 2 つの異なる概念を使用して、アクティビティに格納されているデータと、アクティビティの境界を越えて流れるデータを分離します。 変数と "In/Out/InOut" 引数に明確な階層スコープを使用することで、アクティビティのデータ使用の複雑さが大幅に軽減され、データの有効期間も自動的にスコープ設定されます。 アクティビティには、引数によって明確に定義されたシグネチャがあります。 アクティビティを検査するだけで、受け取ると予想されるデータと、その実行の結果として生成されるデータを決定できます。
WF3 では、ワークフローの作成時にアクティビティが初期化されました。 WF 4 では、アクティビティは、対応するアクティビティが実行されている場合にのみ初期化されます。 これにより、新しいワークフロー インスタンスの作成時に初期化/初期化解除操作を実行することなく、より簡単なアクティビティ のライフサイクルが可能になるため、より効率的になります。
制御フロー
WF は、任意のプログラミング言語と同様に、シーケンス処理、ループ、分岐、およびその他のパターンに対して一連の制御フロー アクティビティを導入することで、ワークフロー定義の制御フローをサポートします。 WF3 では、同じアクティビティを再実行する必要がある場合、新しい ActivityExecutionContext が作成され、 BinaryFormatterに基づく重いシリアル化および逆シリアル化ロジックによってアクティビティが複製されます。 通常、反復制御フローのパフォーマンスは、一連のアクティビティの実行よりもはるかに遅くなります。
WF4 はこれをまったく異なる方法で処理します。 アクティビティ テンプレートを受け取り、新しい ActivityInstance オブジェクトを作成し、スケジューラ キューに追加します。 このプロセス全体には、明示的なオブジェクトの作成のみが含まれており、非常に軽量です。
非同期プログラミング
通常、アプリケーションは、I/O や分散コンピューティング操作などの長時間実行されるブロック操作の非同期プログラミングにより、パフォーマンスとスケーラビリティが向上します。 WF4 では、基本アクティビティの種類AsyncCodeActivityAsyncCodeActivity<TResult>を介して非同期サポートが提供されます。 ランタイムは非同期アクティビティをネイティブに認識するため、非同期処理が未処理の間はインスタンスを非永続化ゾーンに自動的に配置できます。 カスタム アクティビティは、これらの型から派生して、ワークフロー スケジューラ スレッドを保持したり、並列で実行できるアクティビティをブロックしたりすることなく、非同期作業を実行できます。
メッセージング
当初 WF3 では、外部イベントまたは Web サービスの呼び出しによるメッセージングのサポートが非常に制限されていました。 .NET Framework 3.5 では、ワークフローを WCF クライアントとして実装したり、 SendActivity や ReceiveActivityを介して WCF サービスとして公開したりできます。 WF4 では、WCF メッセージング ロジックを WF に緊密に統合することで、ワークフロー ベースのメッセージング プログラミングの概念がさらに強化されました。
.NET 4 の WCF で提供される統合メッセージ処理パイプラインは、WF4 サービスのパフォーマンスとスケーラビリティが WF3 よりも大幅に向上するのに役立ちます。 WF4 には、複雑な Message Exchange パターン (MEP) をモデル化できる、より豊富なメッセージング プログラミング サポートも用意されています。 開発者は、型指定されたサービス コントラクトを使用して、簡単なプログラミングまたは型指定されていないサービス コントラクトを実現し、シリアル化コストを支払わずにパフォーマンスを向上させることができます。 WF4 の SendMessageChannelCache クラスを介したクライアント側チャネル キャッシュのサポートは、開発者が最小限の労力で高速なアプリケーションを構築するのに役立ちます。 詳細については、「 送信アクティビティのキャッシュ共有レベルの変更」を参照してください。
宣言型プログラミング
WF4 は、ビジネス プロセスとサービスをモデル化するためのクリーンでシンプルな宣言型プログラミング フレームワークを提供します。 プログラミング モデルでは、コードを使用しないアクティビティの完全な宣言型構成がサポートされ、ワークフローの作成が大幅に簡略化されます。 .NET Framework 4 では、XAML ベースの宣言型プログラミング フレームワークは、WPF と WF の両方をサポートするために、単一アセンブリ System.Xaml.dll に統合されています。
WF4 では、XAML は真に宣言型のエクスペリエンスを提供し、ワークフローの定義全体を XML マークアップで定義し、.NET を使用して構築されたアクティビティと型を参照できるようにします。 これは、カスタムの分離コード ロジックを含まない XOML 形式の WF3 では困難でした。 .NET 4 の新しい XAML スタックでは、ワークフロー成果物のシリアル化/逆シリアル化のパフォーマンスが大幅に向上し、宣言型プログラミングがより魅力的で堅牢になります。
ワークフロー デザイナー
WF4 の完全宣言型プログラミング サポートでは、大規模なワークフローの設計時のパフォーマンスに対してより高い要件が明示的に課されます。 WF4 のワークフロー デザイナーは、WF3 よりも大規模なワークフローのスケーラビリティが大幅に向上しています。 UI 仮想化のサポートにより、デザイナーは数秒で 1,000 アクティビティの大規模なワークフローを簡単に読み込むことができますが、WF3 デザイナーで数百のアクティビティのワークフローを読み込むのはほとんど不可能です。
コンポーネント レベルのパフォーマンス比較
このセクションでは、WF3 ワークフローと WF4 ワークフローの個々のアクティビティの直接的な比較に関するデータについて説明します。 永続化などの重要な領域は、個々のアクティビティ コンポーネントよりもパフォーマンスに大きな影響を与えます。 WF4 の個々のコンポーネントのパフォーマンスの向上は重要ですが、コンポーネントは手でコーディングされたオーケストレーション ロジックと比較するのに十分な速さになりました。 その例については、次のセクション「サービス構成シナリオ」で説明します。
環境のセットアップ
上の図は、コンポーネント レベルのパフォーマンス測定に使用されるマシン構成を示しています。 1 つの 1 Gbps イーサネット ネットワーク インターフェイス経由で接続された 1 台のサーバーと 5 つのクライアント。 簡単に測定できるように、サーバーは、Windows Server 2008 x86 を実行するデュアルプロセス/クアッド コア サーバーの単一コアを使用するように構成されています。 システムの CPU 使用率は、ほぼ 100%で維持されます。
テストの詳細
WF3 CodeActivity は、WF3 ワークフローで使用できる最も簡単なアクティビティである可能性があります。 このアクティビティは、ワークフロー プログラマがカスタム コードを配置できる分離コード内のメソッドを呼び出します。 WF4 では、同じ機能を提供する WF3 CodeActivity に直接アナログはありません。 WF4 には、WF3 CodeActivityに関連しないCodeActivity基底クラスがあることに注意してください。 ワークフロー作成者は、カスタム アクティビティを作成し、XAML 専用ワークフローを構築することをお勧めします。 次のテストでは、WF4 ワークフローの空のCodeActivityの代わりに Comment
というアクティビティが使用されています。
Comment
アクティビティのコードは次のとおりです。
[ContentProperty("Body")]
public sealed class Comment : CodeActivity
{
public Comment()
: base()
{
}
[DefaultValue(null)]
public Activity Body
{
get;
set;
}
protected override void Execute(CodeActivityContext context)
{
}
}
空のワークフロー
このテストでは、子アクティビティのないシーケンス ワークフローを使用します。
単一アクティビティ
ワークフローは、1 つの子アクティビティを含むシーケンス ワークフローです。 アクティビティは、WF3 の場合はコードのない CodeActivity で、WF4 の場合は Comment
アクティビティです。
While with 1000 Iterations
シーケンス ワークフローには、1 つの While アクティビティが含まれています。ループ内に 1 つの子アクティビティが含まれています。このアクティビティは、処理を実行しません。
Replicator と ParallelForEach の比較
ReplicatorActivity WF3 では、順次実行モードと並列実行モードがあります。 シーケンシャル モードでは、アクティビティのパフォーマンスは WhileActivityに似ています。 ReplicatorActivityは、並列実行に最も役立ちます。 これに対する WF4 アナログは、 ParallelForEach<T> アクティビティです。
次の図は、このテストに使用されるワークフローを示しています。 WF3 ワークフローは左側にあり、WF4 ワークフローは右側にあります。
5 つのアクティビティを含むシーケンシャル ワークフロー
このテストは、複数のアクティビティを順番に実行する効果を示します。 シーケンスには 5 つのアクティビティがあります。
トランザクション スコープ
トランザクション スコープ テストは、イテレーションごとに新しいワークフロー インスタンスが作成されるわけではないという点で、他のテストとは若干異なります。 代わりに、ワークフローは、作業を行わない 1 つのアクティビティを含む TransactionScope アクティビティを含む while ループで構成されます。 while ループを介した 50 回の反復のバッチの各実行は、1 回の操作としてカウントされます。
報酬
WF3 ワークフローには、 WorkScope
という名前の 1 つの補正可能なアクティビティがあります。 アクティビティは、 ICompensatableActivity インターフェイスを実装するだけです。
class WorkScope :
CompositeActivity, ICompensatableActivity
{
public WorkScope() : base() { }
public WorkScope(string name)
{
this.Name = name;
}
public ActivityExecutionStatus Compensate(
ActivityExecutionContext executionContext)
{
return ActivityExecutionStatus.Closed;
}
}
エラー ハンドラーは、 WorkScope
アクティビティを対象とします。 WF4 ワークフローも同様に単純です。
CompensableActivityには、本文と補正ハンドラーがあります。 明示的な補正は、シーケンス内で次に行われます。 本文アクティビティと補正ハンドラー アクティビティはどちらも空の実装です。
public sealed class CompensableActivityEmptyCompensation : CodeActivity
{
public CompensableActivityEmptyCompensation()
: base() { }
public Activity Body { get; set; }
protected override void Execute(CodeActivityContext context) { }
}
public sealed class CompensableActivityEmptyBody : CodeActivity
{
public CompensableActivityEmptyBody()
: base() { }
public Activity Body { get; set; }
protected override void Execute(CodeActivityContext context) { }
}
次の図は、基本的な補正ワークフローを示しています。 WF3 ワークフローは左側にあり、WF4 ワークフローは右側にあります。
パフォーマンス テストの結果
すべてのテストは、トランザクション スコープ テストを除き、1 秒あたりのワークフローで測定されます。 前述のように、WF ランタイムのパフォーマンスは、特に while ループのような同じアクティビティの複数の実行を必要とする領域で、ボード全体で向上しています。
サービス構成シナリオ
前のセクション「コンポーネント レベルのパフォーマンス比較」で示したように、WF3 と WF4 の間でオーバーヘッドが大幅に削減されています。 WCF ワークフロー サービスは、手でコード化された WCF サービスのパフォーマンスとほぼ一致するようになりましたが、WF ランタイムのすべての利点が引き続き得られます。 このテスト シナリオでは、WCF サービスと WF4 の WCF ワークフロー サービスを比較します。
オンライン ストア サービス
Windows Workflow Foundation の長所の 1 つは、複数のサービスを使用してプロセスを作成できることです。 この例では、2 つのサービス呼び出しを調整して注文を購入するオンライン ストア サービスがあります。 最初の手順では、注文検証サービスを使用して注文を検証します。 2 番目の手順は、倉庫サービスを使用して注文を入力することです。
2 つのバックエンド サービスである Order Validating Service と Warehouse Service は、両方のテストで同じままです。 変更する部分は、オーケストレーションを実行するオンライン ストア サービスです。 1 つのケースでは、サービスは WCF サービスとして手動でコード化されます。 もう 1 つのケースでは、サービスは WF4 の WCF ワークフロー サービスとして記述されます。 このテストでは、追跡や永続化などの WF 固有の機能がオフになっています。
環境
クライアント要求は、複数のコンピューターから HTTP 経由でオンライン ストア サービスに対して行われます。 1 台のコンピューターが 3 つのサービスをすべてホストします。 オンライン ストア サービスとバックエンド サービスの間のトランスポート層は TCP または HTTP です。 1 秒あたりの操作の測定は、オンライン ストア サービスに対して行われた完了した PurchaseOrder
呼び出しの数に基づいています。 チャネル プーリングは WF4 で使用できる新機能です。 このテスト チャネル プールの WCF 部分では、すぐには提供されないため、オンライン ストア サービスでは、単純なプーリング手法の手動でコード化された実装が使用されました。
[パフォーマンス]
チャネル プールなしでバックエンド TCP サービスに接続すると、WF サービスはスループットに 17.2% 影響を与えます。 チャネルプーリングでは、ペナルティは約23.8%です。 HTTP の場合、影響ははるかに少なくなります。プールなしの% は 4.3、プーリングでは 8.1%。 また、HTTP を使用する場合、チャネル プールの利点はほとんど得られていないことに注意することも重要です。
このテストでは、手動でコード化された WCF サービスと比較して WF4 ランタイムからのオーバーヘッドがありますが、最悪のシナリオと見なされる可能性があります。 このテストの 2 つのバックエンド サービスはほとんど動作しません。 実際のエンド ツー エンドのシナリオでは、これらのサービスはデータベース呼び出しなどのコストの高い操作を実行するため、トランスポート層のパフォーマンスへの影響はあまり重要ではありません。 WF4 で利用できる機能の利点に加えて、Workflow Foundation はオーケストレーション サービスを作成するための実行可能な選択肢となります。
パフォーマンスに関する主な考慮事項
このセクションの機能領域は、相互運用を除き、WF3 と WF4 の間で大幅に変更されています。 これは、ワークフロー アプリケーションの設計とパフォーマンスに影響します。
ワークフローのアクティブ化の待機時間
WCF ワークフロー サービス アプリケーションでは、新しいワークフローを開始したり、既存のワークフローを読み込んだりするための待機時間が重要です。これはブロックされる可能性があるためです。 このテスト ケースでは、一般的なシナリオで WF4 XAMLX ホストに対して WF3 XOML ホストを測定します。
環境のセットアップ
テストセットアップ
このシナリオでは、クライアント コンピューターがコンテキストベースの相関関係を使用して WCF ワークフロー サービスにアクセスします。 コンテキストの関連付けには特別なコンテキスト バインディングが必要であり、コンテキスト ヘッダーまたは Cookie を使用してメッセージを正しいワークフロー インスタンスに関連付けます。 メッセージ本文を解析する必要がないように、関連付け ID がメッセージ ヘッダーに配置されているという点でパフォーマンス上の利点があります。
サービスは要求を含む新しいワークフローを作成し、待機時間の測定にワークフローの実行に費やされた時間を含めないように、即時応答を送信します。 WF3 ワークフローは分離コードを持つ XOML であり、WF4 ワークフローは完全に XAML です。 WF4 ワークフローは次のようになります。
Receive アクティビティによってワークフロー インスタンスが作成されます。 受信したメッセージで渡された値が応答メッセージにエコーされます。 応答の後のシーケンスには、ワークフローの残りの部分が含まれています。 上記の場合、コメント アクティビティは 1 つだけ表示されます。 ワークフローの複雑さをシミュレートするために、コメント アクティビティの数が変更されます。 コメント アクティビティは、作業を実行しない WF3 CodeActivity に相当します。 コメント アクティビティの詳細については、この記事の「コンポーネント レベルのパフォーマンス比較」セクションを参照してください。
実験値
WCF ワークフロー サービスのコールド待機時間とウォーム待機時間:
前のグラフでは、コールドとは、特定のワークフローに既存の WorkflowServiceHost がない場合を指します。 つまり、コールド 待機時間は、ワークフローが初めて使用され、XOML または XAML をコンパイルする必要がある場合です。 ウォーム待機時間は、ワークフローの種類が既にコンパイルされている場合に、新しいワークフロー インスタンスを作成する時間です。 ワークフローの複雑さは WF4 のケースにはほとんど違いはありませんが、WF3 の場合は直線的に進行します。
相関関係のスループット
WF4 では、新しいコンテンツ ベースの関連付け機能が導入されています。 WF3 では、コンテキストベースの相関関係のみが提供されます。 コンテキストベースの関連付けは、特定の WCF チャネル バインドに対してのみ実行できます。 これらのバインドを使用すると、ワークフロー ID がメッセージ ヘッダーに挿入されます。 WF3 ランタイムは、その ID によってのみワークフローを識別できました。コンテンツ ベースの関連付けでは、ワークフロー作成者は、アカウント番号や顧客 ID などの関連するデータから関連付けキーを作成できます。
コンテキストベースの関連付けには、関連付けキーがメッセージ ヘッダーに配置されるという点でパフォーマンス上の利点があります。 キーは、シリアル化解除/メッセージ コピーなしでメッセージから読み取ることができます。 コンテンツ ベースの関連付けでは、関連付けキーはメッセージ本文に格納されます。 XPath 式を使用してキーを検索します。 この追加処理のコストは、メッセージのサイズ、本文内のキーの深さ、キーの数によって異なります。 このテストでは、コンテキストベースとコンテンツベースの相関関係を比較し、複数のキーを使用する場合のパフォーマンスの低下も示します。
環境のセットアップ
テストセットアップ
前のワークフローは、 永続化 セクションで使用されたものと同じです。 永続化のない関連付けテストの場合、ランタイムに永続化プロバイダーはインストールされません。 相関関係は、CreateOrder と CompleteOrder の 2 つの場所で発生します。
実験値
このグラフは、コンテンツ ベースの相関関係で使用されるキーの数が増えるにつれて、パフォーマンスが低下している状態を示しています。 TCP と HTTP の間の曲線の類似性は、これらのプロトコルに関連するオーバーヘッドを示します。
永続化との相関関係
永続化されたワークフローでは、コンテンツ ベースの相関関係からの CPU 負荷がワークフロー ランタイムから SQL データベースにシフトします。 SQL 永続化プロバイダーのストアド プロシージャは、キーを照合して適切なワークフローを見つける作業を行います。
コンテキストベースの相関関係は、コンテンツベースの相関関係よりも高速です。 ただし、永続化が相関関係よりもパフォーマンスに影響を与えるので、この違いはあまり顕著ではありません。
複雑なワークフロー スループット
ワークフローの複雑さは、アクティビティの数によってのみ測定されるわけではありません。 複合アクティビティには多くの子を含めることができます。また、それらの子を複合アクティビティにすることもできます。 入れ子のレベルの数が増えるにつれて、現在実行中の状態にできるアクティビティの数と、状態にできる変数の数も増加します。 このテストでは、複雑なワークフローを実行するときに WF3 と WF4 の間のスループットを比較します。
テストセットアップ
これらのテストは、Windows Server 2008 x64 を実行する 4 GB RAM を搭載した Intel Xeon X5355 @ 2.66GHz 4 方向コンピューターで実行されました。 テスト コードは、コアごとに 1 つのスレッドで 1 つのプロセスで実行され、CPU 使用率が 100% に達します。
このテスト用に生成されたワークフローには、各シーケンスのアクティビティの深さと数という 2 つの主な変数があります。 各深度レベルには並列アクティビティが含まれますが、ループ、決定、割り当て、シーケンスが含まれます。 次に示す WF4 デザイナーでは、最上位のフロー チャートが表示されます。 各フローチャート アクティビティは、メイン フローチャートに似ています。 深度がテストのパラメーターに制限されているこのワークフローを描くときに、フラクタルを考えると役に立つ場合があります。
特定のテストのアクティビティの数は、シーケンスごとのアクティビティの深さと数によって決まります。 次の式は、WF4 テストのアクティビティの数を計算します。
WF3 テストのアクティビティ数は、追加のシーケンスにより、少し異なる式で計算できます。
d は深度で、a はシーケンスごとのアクティビティの数です。 これらの数式の背後にあるロジックは、最初の定数に a を乗算したシーケンスの数、2 番目の定数は現在のレベルのアクティビティの静的な数です。 各フローチャートには、3 つのフローチャート子アクティビティがあります。 下部の深度レベルでは、これらのフローチャートは空ですが、他のレベルではメイン フローチャートのコピーです。 各テスト バリエーションのワークフロー定義内のアクティビティの数を次の表に示します。
ワークフロー定義内のアクティビティの数は、深さのレベルごとに急激に増加します。 ただし、特定のワークフロー インスタンスでは、決定ポイントごとに 1 つのパスのみが実行されるため、実際のアクティビティのごく一部のみが実行されます。
WF3 用に同等のワークフローが作成されました。 WF3 デザイナーは、入れ子ではなくデザイン領域にワークフロー全体を表示するため、このトピックでは表示するには大きすぎます。 ワークフローのスニペットを次に示します。
極端なケースで入れ子を実行するために、このテストの一部である別のワークフローでは 100 個の入れ子になったシーケンスが使用されます。 最も内側のシーケンスでは、単一の Comment
または CodeActivityです。
追跡と永続化は、このテストの一部として使用されません。
実験値
深さが多く、アクティビティの数が多い複雑なワークフローでも、パフォーマンスの結果は、この記事で前に示した他のスループット番号と一致します。 WF4 のスループットは桁違いに速く、対数スケールで比較する必要があります。
記憶
Windows Workflow Foundation のメモリ オーバーヘッドは、ワークフローの複雑さとワークフロー定義の数という 2 つの重要な領域で測定されます。 メモリ測定は、Windows 7 64 ビット ワークステーションで行われました。 パフォーマンス カウンターの監視、Environment.WorkingSet のポーリング、 VMMap から使用可能な VMMap などのツールの使用など、ワーキング セット サイズの測定を取得する方法は多数あります。 各テストの結果を取得して検証するために、メソッドの組み合わせを使用しました。
ワークフローの複雑さのテスト
ワークフローの複雑さのテストは、ワークフローの複雑さに基づいてワーキング セットの差を測定します。 前のセクションで使用した複雑なワークフローに加えて、2 つの基本的なケース (1 つのアクティビティ ワークフローと 1000 個のアクティビティを含むシーケンス) に対応する新しいバリエーションが追加されました。 これらのテストでは、ワークフローは初期化され、1 分間の 1 つのシリアル ループで完了するように実行されます。 各テスト バリエーションは 3 回実行され、記録されるデータはこれら 3 回の実行の平均です。
2 つの新しい基本テストには、次のようなワークフローがあります。
上記の WF3 ワークフローでは、空の CodeActivity アクティビティが使用されます。 上記の WF4 ワークフローでは、 Comment
アクティビティが使用されます。
Comment
アクティビティについては、この記事の「コンポーネント レベルのパフォーマンス比較」セクションで説明しました。
このグラフで注目する明確な傾向の 1 つは、入れ子が WF3 と WF4 の両方のメモリ使用量に対する影響を比較的最小限に抑えるということです。 メモリへの影響が最も大きいのは、特定のワークフロー内のアクティビティの数です。 シーケンス1000からのデータ、複雑な深さ5シーケンス5、および複雑な深さ7シーケンス1のバリエーションを考えると、アクティビティの数が数千に入ると、メモリ使用量がより顕著になることは明らかです。 最大 29K アクティビティがある極端なケース (深度 7 シーケンス 1) では、WF4 は WF3 よりもほぼ 79% 少ないメモリを使用しています。
複数のワークフロー定義テスト
WF3 と WF4 でワークフローをホストするための使用可能なオプションがあるため、ワークフロー定義ごとのメモリの測定は 2 つの異なるテストに分かれています。 テストは、特定のワークフローがインスタンス化され、定義ごとに 1 回だけ実行されるという点で、ワークフローの複雑さのテストとは異なる方法で実行されます。 これは、ワークフロー定義とそのホストが AppDomain の有効期間中メモリに残っているためです。 特定のワークフロー インスタンスを実行して使用されるメモリは、ガベージ コレクション中にクリーンアップする必要があります。 WF4 の移行ガイダンスには、ホスティング オプションに関する詳細情報が含まれています。 詳細については、「 WF 移行クックブック: ワークフロー ホスティング」を参照してください。
ワークフロー定義テスト用に多数のワークフロー定義を作成するには、いくつかの方法があります。 たとえば、コード生成を使用して、名前以外は同じ 1000 個のワークフローのセットを作成し、それらの各ワークフローを個別のファイルに保存できます。 このアプローチは、コンソールでホストされるテストに対して行われました。 WF3 では、 WorkflowRuntime クラスを使用してワークフロー定義を実行しました。 WF4 では、 WorkflowApplication を使用して 1 つのワークフロー インスタンスを作成するか、 WorkflowInvoker を直接使用して、メソッド呼び出しであるかのようにアクティビティを実行できます。 WorkflowApplication は単一のワークフロー インスタンスのホストであり、このテストで使用された機能パリティが WorkflowRuntime に近い。
IIS でワークフローをホストする場合、すべての XAMLX または XOML ファイルを生成する代わりに、 VirtualPathProvider を使用して新しい WorkflowServiceHost を作成できます。 VirtualPathProviderは受信要求を処理し、データベースから読み込むことができる "仮想ファイル" で応答します。この場合は、その場で生成されます。 そのため、1,000 個の物理ファイルを作成する必要があります。
コンソール テストで使用されるワークフロー定義は、1 つのアクティビティを含む単純なシーケンシャル ワークフローでした。 1 つのアクティビティは、WF3 ケースの空の CodeActivity と WF4 ケースの Comment
アクティビティでした。 IIS でホストされるケースでは、メッセージの受信を開始し、応答の送信を終了するワークフローを使用しました。
次の図は、ReceiveActivity を含む WF3 ワークフローと、要求/応答パターンを持つ WF4 ワークフローを示しています。
次の表は、1 つのワークフロー定義と 1001 定義の間のワーキング セット内の差分を示しています。
ホスティング オプション | WF3 ワーキング セットデルタ | WF4 ワーキング セットデルタ |
---|---|---|
コンソール アプリケーションでホストされるワークフロー | 18 MB | 9 MB |
IIS でホストされるワークフロー サービス | 446 MB | 364 MB |
IIS でワークフロー定義をホストすると、 WorkflowServiceHost、詳細な WCF サービス成果物、およびホストに関連付けられているメッセージ処理ロジックにより、はるかに多くのメモリが消費されます。
WF3 でのコンソール ホスティングの場合、ワークフローは XOML ではなくコードで実装されました。 WF4 では、既定では XAML が使用されます。 XAML はアセンブリに埋め込みリソースとして格納され、ワークフローの実装を提供するために実行時にコンパイルされます。 このプロセスにはいくつかのオーバーヘッドが伴います。 WF3 と WF4 を公平に比較するために、XAML の代わりにコード化されたワークフローが使用されました。 WF4 ワークフローの 1 つの例を次に示します。
public class Workflow1 : Activity
{
protected override Func<Activity> Implementation
{
get
{
return new Func<Activity>(() =>
{
return new Sequence
{
Activities = {
new Comment()
}
};
});
}
set
{
base.Implementation = value;
}
}
}
メモリ使用量に影響を与える可能性があるその他の多くの要因があります。 すべてのマネージド プログラムに対して同じアドバイスが引き続き適用されます。 IIS でホストされる環境では、ワークフロー定義用に作成された WorkflowServiceHost オブジェクトは、アプリケーション プールがリサイクルされるまでメモリ内に保持されます。 拡張機能を記述するときは、この点に留意する必要があります。 また、"グローバル" 変数 (ワークフロー全体を対象とする変数) を回避し、可能な限り変数のスコープを制限することをお勧めします。
ワークフロー ランタイム サービス
固執
WF3 と WF4 はどちらも SQL 永続化プロバイダーに付属しています。 WF3 SQL 永続化プロバイダーは、ワークフロー インスタンスをシリアル化して BLOB に格納する単純な実装です。 このため、このプロバイダーのパフォーマンスは、ワークフロー インスタンスのサイズによって大きく異なります。 WF3 では、このホワイト ペーパーで既に説明したように、多くの理由でインスタンス サイズが増加する可能性があります。 多くのお客様は、シリアル化されたインスタンスをデータベースに格納してもワークフローの状態を把握できないため、既定の SQL 永続化プロバイダーを使用しないことを選択しています。 ワークフロー ID を知らずに特定のワークフローを見つけるには、永続化された各インスタンスを逆シリアル化し、内容を調べる必要があります。 多くの開発者は、この障害を克服するために独自の永続化プロバイダーを記述することを好みます。
WF4 SQL 永続化プロバイダーは、これらの問題の一部に対処しようとしました。 永続化テーブルは、アクティブなブックマークや昇格可能なプロパティなどの特定の情報を公開します。 WF4 の新しいコンテンツ ベースの関連付け機能は、WF3 SQL 永続化アプローチを使用してうまく機能しません。これは、永続化されたワークフロー インスタンスの組織に何らかの変更を加えました。 これにより、永続化プロバイダーのジョブがより複雑になり、データベースに余分な負荷がかかります。
環境のセットアップ
テストセットアップ
機能セットが改善され、コンカレンシー処理が向上した場合でも、WF4 の SQL 永続化プロバイダーは WF3 のプロバイダーよりも高速です。 これを示すために、WF3 と WF4 で基本的に同じ操作を実行する 2 つのワークフローを次に示します。
2 つのワークフローは、どちらも受信したメッセージによって作成されます。 最初の応答を送信すると、ワークフローは永続化されます。 WF3 の場合、永続化を開始するために空の TransactionScopeActivity が使用されます。 WF3 でも、アクティビティを "閉じても保持する" とマークすることで、同じことを実現できます。2 つ目の相関メッセージがワークフローを完了します。 ワークフローは永続化されますが、アンロードされません。
実験値
クライアントと中間層の間のトランスポートが HTTP の場合、WF4 での永続化は 2.6 倍の向上を示します。 TCP トランスポートでは、その係数が 3.0 倍に増加します。 いずれの場合も、中間層での CPU 使用率は 98% 以上です。 WF4 のスループットが大きいのは、ワークフロー の実行時間が短縮されるためです。 シリアル化されたインスタンスのサイズはどちらの場合も小さく、この状況では重要な要素ではありません。
このテストの WF3 ワークフローと WF4 ワークフローの両方で、アクティビティを使用して、永続化がいつ発生するかを明示的に示します。 これには、ワークフローをアンロードせずに永続化する利点があります。 WF3 では、 TimeToUnload 機能を使用して永続化することもできますが、これによりワークフロー インスタンスがメモリからアンロードされます。 WF3 を使用している開発者がワークフローが特定の時点で保持されるようにする場合は、ワークフロー定義を変更するか、ワークフロー インスタンスのアンロードと再読み込みのコストを支払う必要があります。 WF4 の新機能により、アンロードせずに永続化できます: TimeToPersist。 この機能を使用すると、ワークフロー インスタンスはアイドル状態で永続化されますが、 TimeToUnload しきい値に達するか実行が再開されるまでメモリに保持されます。
WF4 SQL 永続化プロバイダーは、データベース層でより多くの作業を実行します。 SQL データベースはボトルネックになる可能性があるため、そこで CPU とディスクの使用状況を監視することが重要です。 パフォーマンス テスト ワークフロー アプリケーションの場合は、SQL データベースから次のパフォーマンス カウンターを必ず含めるようにしてください。
PhysicalDisk\%Disk 読み取り時間
PhysicalDisk\% ディスク時間
PhysicalDisk\% ディスク書き込み時間
PhysicalDisk\% 平均ディスク キューの長さ
PhysicalDisk\Avg. Disk Read Queue Length
PhysicalDisk\Avg. Disk Write Queue Length
PhysicalDisk\Current Disk Queue Length
プロセッサ情報\% プロセッサ時間
SQLServer:Latches\Average Latch Wait Time (ms)
SQLServer:Latches\Latch Waits/sec
トラッキング
ワークフロー追跡を使用して、ワークフローの進行状況を追跡できます。 追跡イベントに含まれる情報は、追跡プロファイルによって決定されます。 追跡プロファイルが複雑になるほど、追跡コストが高くなります。
WF3 には、SQL ベースの追跡サービスが付属しています。 このサービスは、バッチモードと非バッチモードで動作する可能性があります。 非バッチ モードでは、追跡イベントはデータベースに直接書き込まれます。 バッチ モードでは、追跡イベントはワークフロー インスタンスの状態と同じバッチに収集されます。 バッチ モードは、最も広い範囲のワークフロー設計に最適なパフォーマンスを備えています。 ただし、ワークフローが永続化せずに多数のアクティビティを実行し、それらのアクティビティが追跡される場合、バッチ処理はパフォーマンスに悪影響を及ぼす可能性があります。 これは一般的にループで発生します。このシナリオを回避する最善の方法は、永続化ポイントを含むように大きなループを設計することです。 ループに永続化ポイントを導入するとパフォーマンスにも悪影響を及ぼす可能性があるため、それぞれのコストを測定し、バランスを考え出す必要があります。
WF4 は SQL 追跡サービスに付属していません。 SQL データベースへの追跡情報の記録は、.NET Framework に組み込まれるのではなく、アプリケーション サーバーからより適切に処理できます。 そのため、SQL 追跡は AppFabric によって処理されるようになりました。 WF4 の既定の追跡プロバイダーは、Event Tracing for Windows (ETW) に基づいています。
ETW は、Windows に組み込まれているカーネル レベルの低待機時間のイベント システムです。 プロバイダー/コンシューマー モデルを使用します。これにより、実際にコンシューマーが存在する場合にのみ、イベント トレースのペナルティが発生します。 プロセッサ、ディスク、メモリ、ネットワーク使用量などのカーネル イベントに加えて、多くのアプリケーションも ETW を利用します。 ETW イベントは、イベントをアプリケーションに合わせてカスタマイズできるという点で、パフォーマンス カウンターよりも強力です。 イベントには、ワークフロー ID や情報メッセージなどのテキストを含めることができます。 また、イベントはビットマスクで分類されるため、イベントの特定のサブセットを使用すると、すべてのイベントをキャプチャするよりもパフォーマンスへの影響が少なくなります。
SQL ではなく追跡に ETW を使用する方法の利点は次のとおりです。
追跡イベントのコレクションは、別のプロセスに分離できます。 これにより、イベントの記録方法の柔軟性が向上します。
ETW 追跡イベントは、WCF ETW イベントまたは SQL Server やカーネル プロバイダーなどの他の ETW プロバイダーと簡単に組み合わせることができます。
ワークフロー作成者は、WF3 SQL 追跡サービスのバッチ モードなど、特定の追跡実装でより適切に動作するようにワークフローを変更する必要はありません。
管理者は、ホスト プロセスをリサイクルすることなく、追跡のオンとオフを切り替えることができます。
ETW 追跡のパフォーマンス上の利点には欠点があります。 ETW イベントは、システムのリソース負荷が高い場合に失われる可能性があります。 イベントの処理は、通常のプログラム実行をブロックするためのものではありません。したがって、すべての ETW イベントがサブスクライバーにブロードキャストされるとは限りません。 これにより、ETW の追跡は正常性の監視には適していますが、監査には適していません。
WF4 には SQL 追跡プロバイダーはありませんが、AppFabric には対応しています。 AppFabric の SQL 追跡アプローチは、イベントをバッチ処理し、すばやく挿入できるように設計された SQL テーブルに書き込む Windows サービスを使用して ETW イベントをサブスクライブすることです。 別のジョブによって、このテーブルからデータがドレインされ、AppFabric ダッシュボードで表示できるレポート テーブルに変換されます。 つまり、追跡イベントのバッチは、元のワークフローとは無関係に処理されるため、記録される前に永続化ポイントを待機する必要はありません。
ETW イベントは、logman や xperf などのツールを使用して記録できます。 コンパクトな ETL ファイルは、xperfview などのツールを使用して表示したり、tracerpt を使用して XML などのより読みやすい形式に変換したりできます。 WF3 では、SQL データベースなしで追跡イベントを取得する唯一のオプションは、カスタム追跡サービスを作成することです。 ETW の詳細については、「 WCF Services と Event Tracing for Windows and Event Tracing- Windows アプリケーション」を参照してください。
ワークフロー追跡を有効にすると、さまざまな程度のパフォーマンスに影響します。 次のベンチマークでは、logman ツールを使用して ETW 追跡イベントを使用し、ETL ファイルに記録します。 AppFabric での SQL 追跡のコストは、この記事の範囲外です。 このベンチマークでは、AppFabric でも使用される基本的な追跡プロファイルを示します。 正常性監視イベントのみを追跡するコストも含まれます。 これらのイベントは、問題のトラブルシューティングやシステムの平均スループットの決定に役立ちます。
環境のセットアップ
実験値
正常性の監視は、スループットに約 3% 影響します。 基本プロファイルのコストは約 8%です。
相互運用機能
WF4 は WF のほぼ完全な書き換えであるため、WF3 ワークフローとアクティビティは WF4 と直接互換性がありません。 Windows Workflow Foundation を早期に採用した多くのお客様には、WF3 の社内またはサードパーティのワークフロー定義とカスタム アクティビティがあります。 WF4 への移行を容易にする 1 つの方法は、WF4 ワークフロー内から WF3 アクティビティを実行できる相互運用アクティビティを使用することです。 Interop アクティビティは、必要な場合にのみ使用することをお勧めします。 WF4 への移行の詳細については、 WF4 移行ガイダンスを参照してください。
環境のセットアップ
実験値
次の表は、さまざまな構成で 5 つのアクティビティをシーケンスで含むワークフローを実行した結果を示しています。
テスト | スループット (ワークフロー/秒) |
---|---|
WF3 ランタイムの WF3 シーケンス | 1,576 |
相互運用機能を使用した WF4 ランタイムの WF3 シーケンス | 2,745 |
WF4 シーケンス | 153,582 |
直接 WF3 で相互運用機能を使用すると、パフォーマンスが大幅に向上します。 ただし、WF4 アクティビティと比較すると、増加はごくわずかです。
概要
WF4 のパフォーマンスへの多大な投資は、多くの重要な分野で成果を上げてきた。 個々のワークフロー コンポーネントのパフォーマンスは、WF 4 では WF3 よりも数百倍高速な場合があります。これは、WF ランタイムが無駄がないためです。 待機時間の数値も大幅に向上します。 これは、WF を使用する利点を考慮すると、WCF オーケストレーション サービスを手動でコーディングするのではなく、WF を使用する場合のパフォーマンスの低下が非常に小さいということです。 永続化のパフォーマンスは、2.5 から 3.0 の係数で増加しました。 ワークフロー追跡による正常性の監視でオーバーヘッドが非常に少なくなっています。 WF3 から WF4 への移行を検討している場合は、包括的な移行ガイドのセットを使用できます。 このすべてが、WF4 を複雑なアプリケーションを記述するための魅力的なオプションにする必要があります。
.NET