9

私は、複数のクライアントがサーバーにそれぞれ 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 つのことがわかりますが、その意味がわかりません。

  1. System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke はツリーの一番上で使用されていますが、並行処理でよろしいですか?
  2. すべての同期の問題には、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);
        }
4

3 に答える 3

4

PerCallこのような状況では、このインスタンス化モードを検討できます。

  • サービスがステートレスの場合

  • サービスに軽量の初期化コードがある場合(またはまったくない場合
    )。

  • サービスがシングルスレッドの場合。

いくつかの良いチュートリアル。チューニングに関する3番目のリンクを参照してください。

WCFインスタンス化、同時実行、およびスロットリング–パート1

WCFインスタンス化、同時実行、およびスロットリング–パート2

WCFインスタンス化、同時実行、およびスロットリング–パート3

于 2012-06-27T13:17:58.087 に答える
2

通話ごとを希望します。セッションは、リソースを集中的に使用するオブジェクトの初期化や各リクエストの前処理ルーティングの実行を最小限に抑えたい場合、または状態を維持したい場合に役立ちます。セッションはパフォーマンスを向上させますが、呼び出しごとは常により適切にスケーリングします。呼び出しごとに、並行性について心配する必要はありません。persession/multiple の欠点は、コード内のスレッド セーフについて常に考えなければならないことです。

于 2012-06-27T10:18:26.383 に答える
1

サービスの状態を気にせず、初期化時に手間のかかる作業が行われない場合は、呼び出しごとに最適なオプションがあります。これがあなたのケースを説明していると思います。これらのDAL呼び出しを削除して、サービスがどのように動作するかを確認してください。こうすることで、それがボトルネックであるかどうかを識別できます。

于 2012-06-27T17:11:17.060 に答える