为什么我的应用程序如此等待同步?

Mit*_*hir 9 .net c# concurrency wcf sql-server-2008

我正在进行一项性能测试,该测试涉及几个客户,每个客户尽可能快地轰炸服务器150个请求.

服务器由3个WCF服务构成,一个通过httpbinding向外部打开,它通过net.pipe(IPC)与另外两个服务进行通信.其中一项服务负责数据库连接(SQL server 2008 R2).

此DB连接服务使用以下连接字符串增强:

Min Pool Size=20; Max Pool Size=1000; Connection Timeout=20;
Run Code Online (Sandbox Code Playgroud)

并且受WCF限制(与所有其他WCF服务一样).

我注意到当我激活1个客户端时可能需要3秒钟,但是当我激活3个客户端时,它可能需要8到9个或更多.

我检查了SQL服务器分析器,看看有多少并发进程使用,我看到只使用了大约8个进程.

所以我意识到在服务器中的某个地方请求排队而不是同时处理.

为了找到它的底部,我使用了一个性能分析器(确切地说是ANTS),它向我展示了大约70%的时间浪费在"等待同步"

当我打开调用图时,我发现两件看起来很奇怪的东西,但我不确定它们是什么意思:

  1. System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke正在树的顶部使用,是否可以进行并发处理?
  2. 所有同步问题都涉及某种SQL Server活动,如ExecuteNonQuery,ExecuteReader等(当我到达调用树的底部时)

我注意到数据库连接服务使用的是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;
    }
Run Code Online (Sandbox Code Playgroud)

通常从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;
    }
Run Code Online (Sandbox Code Playgroud)

那么,这里有什么不对吗?

或许我应该看看别的地方?

编辑:

在Brijesh的评论之后,我意识到我没有更改WCF服务的默认InstanceContextMode和ConcurrencyMode ......我猜是初学者的错误.

我仍然不确定是否应该使用PerSession/Multiple或PerCall/Single.正如我所看到的,无论客户端如何,每个服务都应该像处理对象一样处理每个请求.

我该怎么用?

第二次编辑:

在使用PerCall和PerSession/Multiple之后,我注意到仍然没有变化(至少在数据库服务中).我看到的是主入口点服务可能会打开很多线程,但只有少数(仍然是大约8-10个线程)在数据库连接服务上打开.

还有其他原因导致这种情况发生吗?我排除了DAL是一个问题,因为没有足够的请求进入数据库服务,所以我在服务中找到它的东西或客户端中的某些东西......

第3次编辑:

以下是配置文件:

经理的配置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>
Run Code Online (Sandbox Code Playgroud)

经理的客户:

      <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>
Run Code Online (Sandbox Code Playgroud)

数据库连接服务:

<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>
Run Code Online (Sandbox Code Playgroud)

业务逻辑服务的客户端与Manager的几乎相同.

所有服务都是自托管的,我在Manager和Business代码中有一个DBConnectionProxy类,它们按如下方式激活:

 DBConnectionContractClient _dbConnectionContractClient = null;
        try
        {
            objDBConnectionContractClient = new DBConnectionContractClient();
            objDBConnectionContractClient.ExecuteStoredProcedure(input, out result);
        }
Run Code Online (Sandbox Code Playgroud)

pap*_*zzo 4

PerCall 在这些情况下您可以考虑使用这种实例化模式。

\n\n
    \n
  • 如果你的服务是无状态的

  • \n
  • 如果您的服务具有轻量级初始化代码(或者根本没有
    )。

  • \n
  • 如果您的服务是单线程的。

  • \n
\n\n

一些很好的教程。请参阅有关调整的第三个链接。

\n\n

WCF 实例、并发和限制 \xe2\x80\x93 第 1 部分

\n\n

WCF 实例、并发和限制 \xe2\x80\x93 第 2 部分

\n\n

WCF 实例、并发和限制 \xe2\x80\x93 第 3 部分

\n