Dynamics CRM 2011 SDK 5.0.12 マルチスレッド環境でのサービスプロキシ生成

みなさん、こんにちは。

以前こちらの記事で、Web サービスのベストプラクティスを紹介し、
その中で プロキシクラスを保持することでパフォーマンスが向上
するという説明をしました。

ただし、OrganizationServiceProxy はスレッドセーフではないため、
マルチスレッドアプリケーションを利用する場合、各スレッドごとに
固有のプロキシを生成する必要があります。

OrganizationServiceProxy を生成する場合は、認証および各種
メタデータのダウンロードが伴いますが、同一アプリケーションで
利用する場合、これらは重複情報であり、オーバーヘッドとなります。

そこで SDK 5.0.12 では認証およびメタデータのダウンロード部分を
外だしにすることで、 OrganizationServiceProxy 生成時のオーバー
ヘッドを最小限にする手法が提供されています。

概要

まず以下のコードでメタデータの取得を行います。

IServiceManagement<IOrganizationService> orgServiceManagement =
ServiceConfigurationFactory.CreateManagement<IOrganizationService>( new Uri(organizationUrl))

そして以下のコードで認証を行います。

AuthenticationCredentials authCredentials = orgServiceManagement.Authenticate(credentials)

最後にこれらの情報を利用してプロキシを生成します。

// 設置型の場合
OrganizationServiceProxy (orgServiceManagement, authCredentials.ClientCredentials)
// IFD、オンラインの場合
OrganizationServiceProxy (orgServiceManagement, authCredentials.SecurityTokenResponse)

検証1 (設置型 マルチコア)

開発者は論より証拠ということで、いつも通り検証をしてみます。
検証環境は Hyper-V 上の Windows Server 2008 R2 で、CPU を
論理コアで 4 つ割り当てています。

またアプリケーションの処理は以下の通りです。

1. Parallel.For で 20 スレッド作成し、各スレッド内で 100 件ずつ取引先企業を作成。
レコード 1 件作成ごとに、ベストプラクティスにそって OrganizationServiceProxy 生成。

2. Parallel.For で 20 スレッド作成し、各スレッド内で 100 件ずつ取引先企業を作成。
レコード 1 件作成ごとに、ヘルパーコードを利用して OrganizationServiceProxy 生成。

3. Parallel.For で 20 スレッド作成し、各スレッド内で 100 件ずつ取引先企業を作成。
レコード 1 件作成ごとに、従来の方法で OrganizationServiceProxy 生成。

4. 最初に OrganizationServiceProxy を 1 度だけ生成し、ループ処理で 2000 件の
取引先企業レコードを作成。

5. Parallel.For で 2000 スレッドを作成し、各スレッド内で 1 件ずつ取引先企業を
作成。各スレッドごとに、ベストプラクティスにそって OrganizationServiceProxy 生成。

したがって 4 以外は OrganizationServiceProxy を 2000 回生成しています。

結果は以下の通りです。

image

この結果より、従来の方法よりベストプラクティスのパフォーマンスが
良いこと、またヘルパーコードでもベストプラクティスを利用している
ことがわかります。また従来の方法でもマルチスレッドにすることにより、
同じプロキシインスタンスを再利用する場合と変わらない数値が
出ています。

検証 2 (設置型 シングルコア)

次に同一の Hyper-V に論理 CPU を 1 コアのみ付与して検証します。
再起動後、Internet Explorer より手動で 1 件取引先企業を作成した後、
検証を行いました。

image

シングルコアの場合、今回のような処理ではマルチスレッドのメリットが
出にくいようですが、1、2 ともに一度しか OrganizationServiceProxy を
生成しない場合と比較しても良好な結果を出しています。その一方で
本来の手法で OrganizationServiceProxy を生成し続けた場合、結果は
2 分 17 秒と、一度しか生成しないパターンの倍かかっています。

検証 3 オンライン環境

全く同じアプリケーションを、今度はオンライン環境に対して実行します。
OrganizationServiceProxy 生成時の引数で authCredentials.SecurityTokenResponse
を利用する点と、生成するレコード数を 100 件に減らして検証しました。

マルチスレッドの箇所は 10 スレッド作成、各スレッドで 10 レコード作成。
5 つ目の結果は 2000 パラレルとありますが、実際は 100 です。

image

ここでもマルチスレッドの効果が見て取れるものの、ヘルパークラスを
利用している場合に、パフォーマンスの低下が見られます。また以前の
方法で OrganizationServiceProxy を作成する場合のパフォーマンスの
悪さが見て取れます。

ヘルパーコードを利用した場合に、パフォーマンスが低下する理由は
OrganizationServiceProxy を生成する場合、オンライン環境に対して接続
すると、毎回 IServiceManagement の再作成をするためで、ヘルパーコードの
該当箇所を変更して、一度作成した後はキャッシュを利用するようにすると、
以下の結果を得ることができます。

image

 

‐ Dynamics CRM サポート 中村 憲一郎