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

标签 c# .net wcf sql-server-2008 concurrency

我正在进行一项性能测试,其中涉及多个客户端以尽可能快的速度分别向服务器发送 150 个请求。

服务器由 3 个 WCF 服务构建,一个通过 httpbinding 对外开放,它通过 net.pipe (IPC) 与其他 2 个服务通信。其中一项服务负责数据库连接(SQL Server 2008 R2)。

此数据库连接服务使用以下连接字符串增强功能:

Min Pool Size=20; Max Pool Size=1000; Connection Timeout=20;

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

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

我检查了 SQL Server 分析器以查看使用了多少个并发进程,结果发现只使用了大约 8 个进程。

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

为了追根究底,我使用了性能分析器(确切地说是 ANTS),它告诉我大约 70% 的时间浪费在了“等待同步”

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

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

我注意到数据库连接服务使用了一个完全静态的 DAL 项目(不幸的是一些遗留代码)。

看完this我不确定 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;
    }

通常从数据库连接服务调用此方法:

    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 的问题,因为没有足够的请求进入数据库服务,所以我认为它是服务中的某些东西或客户端中的某些东西......

第三次编辑:

配置文件如下:

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

数据库连接服务:

<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>

业务逻辑服务的客户端与管理器的客户端非常相似。

所有服务都是自托管的,我在经理和业务代码中有一个 DBConnectionProxy 类,它们是这样激活的:

 DBConnectionContractClient _dbConnectionContractClient = null;
        try
        {
            objDBConnectionContractClient = new DBConnectionContractClient();
            objDBConnectionContractClient.ExecuteStoredProcedure(input, out result);
        }

最佳答案

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

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

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

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

一些很好的教程。调参见第三个链接。

WCF Instancing, Concurrency, and Throttling – Part 1

WCF Instancing, Concurrency, and Throttling – Part 2

WCF Instancing, Concurrency, and Throttling – Part 3

关于c# - 为什么我的应用程序如此等待同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11221236/

相关文章:

c# - 计算缩放级别以使图像适合面板

.net - VB.NET:具有公共(public) getter 和 protected setter 的属性

.net - Mono真的跨平台吗?

sql - 从 C# 中的 SQL CLR 过程调用 WCF 服务

c# - 如何为具有共享类型的多个 WCF 服务生成客户端代码

c# - Unity2D - 如何在 2D 游戏中围绕圆移动和旋转游戏对象?

c# - 从后面的代码设置 UWP NavigationViewItem 图标

.net - 如何检查 ldap 连接是否安全?

C#、WCF 和 DateTime.MinValue() 与空日期

c# - InvokeRequired 在新创建的 Dialog 上