私は、複数のクライアントがサーバーにそれぞれ 150 のリクエストをできるだけ早く送信するパフォーマンス テストに取り組んでいます。
サーバーは 3 つの WCF サービスから構成され、1 つは httpbinding で外部に公開され、net.pipe (IPC) を介して他の 2 つのサービスと通信します。サービスの 1 つが DB 接続を担当します (SQL Server 2008 R2)。
この DB 接続サービスは、次の接続文字列拡張機能を使用します。
Min Pool Size=20; Max Pool Size=1000; Connection Timeout=20;
WCF が調整されます (他のすべての WCF サービスと同様)。
1 つのクライアントをアクティブ化する場合は 3 秒かかる場合がありますが、3 つのクライアントをアクティブ化する場合は 8 ~ 9 秒またはそれ以上かかる場合があることに気付きました。
SQL サーバー プロファイラーで同時実行プロセスがいくつ使用されているかを確認したところ、約 8 プロセスしか使用されていないことがわかりました。
そのため、サーバーのどこかで、リクエストが同時に処理されるのではなく、キューに入れられることに気付きました。
その真相を突き止めるために、私はパフォーマンス プロファイラー (正確には ANTS) を使用しました。
コール グラフを開くと、奇妙に見える 2 つのことがわかりますが、その意味がわかりません。
- System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke はツリーの一番上で使用されていますが、並行処理でよろしいですか?
- すべての同期の問題には、ExecuteNonQuery、ExecuteReader などの SQL Server アクティビティが関係しています (コール ツリーの最下部に到達したとき)。
DB 接続サービスが完全に静的な DAL プロジェクト (残念ながら一部のレガシー コード) を使用していることに気付きました。
これを読んだ後、DAL のコードに問題があるかどうかはわかりません。ストアド プロシージャ呼び出しのサンプルを次に示します。
public static int PerformStoredProcedure(string storedP,string ext,out string msg)
{
msg = "";
SqlCommand command = GetSqlCommand(storedP,ext);
command.Connection.Open();
int result = (int)PerformStoredProcedure(command,out msg);
command.Connection.Close();
return result;
}
このメソッドは通常、DB 接続サービスから呼び出されます。
public static int PerformStoredProcedureWithParams(string storedP,string ext,out string msg, params object[] pars)
{
msg = "";
SqlCommand command = GetSqlCommand(storedP,ext);
UpdateCommandParams(command, pars);
command.Connection.Open();
int result = (int)PerformStoredProcedure(command,out msg);
command.Connection.Close();
return result;
}
それで、ここで何か問題がありますか?
それとも、どこか別の場所を見た方がいいのでしょうか?
編集:
Brijesh のコメントの後、私は WCF サービスのデフォルトの InstanceContextMode と ConcurrencyMode を変更していないことに気付きました...一種の初心者の間違いだと思います。
PerSession/Multiple または PerCall/ Single を使用する必要があるかどうかはまだわかりません。私が見たように、クライアントに関係なく、各サービスは各リクエストをオブジェクトとして処理する必要があります。
何を使えばいいですか?
2回目の編集:
PerCall と PerSession/Multiple を使用した後、(少なくとも DB サービスでは) まだ変化がないことに気付きました。私が見ているのは、メイン エントリ ポイント サービスが多数のスレッドを開く可能性があることですが、DB 接続サービスで開かれるのはごくわずか (まだ 8 ~ 10 スレッド程度) です。
これが起こる可能性がある他の理由はありますか?DBサービスに十分なリクエストが送信されないため、DALが問題になることを除外したため、サービス内の何かまたはクライアント内の何かを把握します...
3回目の編集:
構成ファイルは次のとおりです。
Manager の構成 wcf サービス セクション:
<services>
<service behaviorConfiguration="ServicesBehavior" name="Verifone.GenericPP.GPPManagerService.GPPManagerServiceImpl">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9090/GPPManagerService/"/>
</baseAddresses>
</host>
<endpoint contract="Verifone.GenericPP.GPPManagerService.IGPPManagerService" binding="basicHttpBinding" address="GPPManagerService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServicesBehavior">
<!--amith 13-05-2012-->
<serviceThrottling
maxConcurrentCalls="1000"
maxConcurrentSessions="1000"
maxConcurrentInstances="1000"
/>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding" maxBufferSize="10000000" maxReceivedMessageSize="10000000">
<readerQuotas maxStringContentLength="10000000" maxArrayLength="10000000"/>
<security mode="None">
<transport clientCredentialType="None"/>
</security>
</binding>
マネージャーのクライアント:
<endpoint name="endpoint1" contract="IDBConnectionContract" bindingConfiguration="basicHttpBinding" binding="basicHttpBinding" address="http://localhost:9010/DBConnectionService/DBService"></endpoint>
<endpoint name="endpoint2" contract="IGPPService" bindingConfiguration="basicHttpBinding" binding="basicHttpBinding" address="http://localhost:9095/GenericPPService/GenericPPService"></endpoint>
DB 接続サービス:
<service behaviorConfiguration="ServicesBehavior" name="Verifone.DBConnectionService.DBConnectionContracImpl">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9010/DBConnectionService/"/>
<add baseAddress="net.pipe://localhost/DBConnectionService/"/>
</baseAddresses>
</host>
<endpoint contract="Verifone.DBConnectionService.IDBConnectionContract" binding="basicHttpBinding" address="DBService"></endpoint>
<endpoint contract="Verifone.DBConnectionService.IDBConnectionContract" binding="netNamedPipeBinding" bindingConfiguration="NetNamedPipeBinding_Configuration" address="" name="pipeEndpoint"/>
</service>
ビジネス ロジック サービスのクライアントは、Manager のクライアントとほとんど同じです。
すべてのサービスは自己ホスト型であり、マネージャーの DBConnectionProxy クラスと、次のようにアクティブ化するビジネス コードがあります。
DBConnectionContractClient _dbConnectionContractClient = null;
try
{
objDBConnectionContractClient = new DBConnectionContractClient();
objDBConnectionContractClient.ExecuteStoredProcedure(input, out result);
}