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

C# 为什么我的应用程序如此等待同步?,c#,.net,wcf,sql-server-2008,concurrency,C#,.net,Wcf,Sql Server 2008,Concurrency,我正在进行一项性能测试,其中包括几个客户端以150个请求的速度轰炸服务器 该服务器由3个WCF服务构成,其中一个通过httpbinding对外开放,它通过net.pipe(IPC)与其他2个服务进行通信。其中一个服务负责数据库连接(SQLServer2008R2) 此DB连接服务使用以下连接字符串增强: Min Pool Size=20; Max Pool Size=1000; Connection Timeout=20; 并且WCF被限制(与所有其他WCF服务一样) 我注意到,当我激活一个客

我正在进行一项性能测试,其中包括几个客户端以150个请求的速度轰炸服务器

该服务器由3个WCF服务构成,其中一个通过httpbinding对外开放,它通过net.pipe(IPC)与其他2个服务进行通信。其中一个服务负责数据库连接(SQLServer2008R2)

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

Min Pool Size=20; Max Pool Size=1000; Connection Timeout=20;
并且WCF被限制(与所有其他WCF服务一样)

我注意到,当我激活一个客户端时,可能需要3秒钟,但当我激活三个客户端时,可能需要8-9秒或更长时间

我使用SQL server profiler查看了有多少并发进程被使用,我发现只有大约8个进程被使用

所以我意识到,在服务器的某个地方,请求被排队,而不是并发处理

为了弄清真相,我使用了一个性能分析器(确切地说是ANTS),它告诉我大约70%的时间浪费在等待同步上

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

  • 正在树的顶部使用System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke,是否可以进行并发处理
  • 所有同步问题都涉及某种SQL Server活动,如ExecuteOnQuery、ExecuteReader等(当我到达调用树的底部时)
  • 我注意到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。在我看来,每个服务都应该将每个请求作为一个对象来处理,而不管客户端是什么

    我应该用什么

    第二次编辑:

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

    有没有其他原因导致这种情况发生?我排除了DAL是一个问题,因为DB服务中没有足够的请求,所以我认为这是服务中的某些内容或客户端中的某些内容

    第三次编辑:

    以下是配置文件:

    经理的配置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>
    

    更喜欢每次调用。如果您希望最小化初始化资源密集型对象或为每个请求运行一些预处理路由,或希望维护状态,则会话将非常有用。会话可以提供更好的性能,但每次调用的可扩展性总是更好。在每次调用中,您不必担心并发性。而会话的缺点是H/Surviv/Mulk是你必须始终考虑代码中的线程安全性的问题。

    PyLead,在这种情况下你可以考虑这个实例模式。

    • 如果您的服务是无状态的

    • 如果您的服务具有轻量级初始化代码(或在
      全部)

    • 如果您的服务是单线程的

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


    如果您不关心服务状态,并且在初始化时没有执行繁重的操作,那么最好的选择是每次调用。我假设这描述了您的情况。尝试删除这些DAL调用,看看您的服务如何运行,这样您就能够确定这是否是您的瓶颈。

    什么类型的实例和并发模式是y你在使用?看起来我没有设置任何模式,所以默认设置适用…我记得我想添加每个会话/多个,但可能不知何故错过了它,我应该添加它吗?persession/single是默认模式,尝试使用concurrency mode multiplew不是更好吗?我需要每个请求都是唯一的,不管谁是唯一的请求客户端。我不知道我做错了什么,但我将属性设置为Multiple/PerSession,它似乎没有任何区别。我真的不知道是什么问题……我在所有服务上都将其设置为PerCall或PerSession Multiple,但这似乎仍然无关紧要,主http wcf服务打开了很多线程,但只有少数线程可以访问DB con连接服务…ConcureNet请求有问题吗,还是仅仅打开多个实例就减慢了doen的速度?我添加了一些WCF服务的配置文件,希望能有所帮助谢谢你的建议,我尝试了这两种方法,但在发送到db服务时请求仍然排队只是一个范围,也许可以看看你是如何激活客户端测试。你可能在同一个表上使用独占锁吗?问题不是发生在实际的数据库上,而是发生在激活数据库的服务上。请求在进入该服务之前排队,甚至在表成为问题之前。哇,你能在排队请求的地方发布测试代码吗?只是为了补充一点,当我运行性能测试时测试在主服务和第二个服务中打开了多个线程,但在db连接服务中只打开了几个线程。两个服务都向该db服务发送请求,因此我认为问题不在测试代码中,而可能在这些服务代码中。我想这可能是因为两个服务都是来自s的同一服务的客户端ame服务器他们在同一个连接上竞争,有意义吗?这实际上与您所关心的另一个问题有关
          <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>
    
    <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>
    
     DBConnectionContractClient _dbConnectionContractClient = null;
            try
            {
                objDBConnectionContractClient = new DBConnectionContractClient();
                objDBConnectionContractClient.ExecuteStoredProcedure(input, out result);
            }