【问题标题】:Why does my application wait for synchronization so much?为什么我的应用程序如此等待同步?
【发布时间】:2012-06-27 07:21:58
【问题描述】:

我正在进行一项性能测试,其中涉及多个客户端以尽可能快的速度轰炸服务器,每个客户端发出 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 服务器分析器查看了使用了多少并发进程,我发现只有大约 8 个进程正在使用。

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

为了深入了解它,我使用了性能分析器(确切地说是 ANTS),它显示大约 70% 的时间浪费在 “等待同步

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

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

我注意到 DB 连接服务使用了一个完全静态的 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 是一个问题,因为数据库服务中没有足够的请求,所以我认为它在服务中的某些东西或客户端中的某些东西...

第三次编辑:

这里是配置文件:

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>

数据库连接服务:

<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);
        }

【问题讨论】:

  • 你使用的是什么类型的实例和并发模式?
  • 看来我没有设置任何模式,所以应用默认设置...我记得我想添加 Per Session/Multiple,但可能不知何故错过了,我应该添加它吗?跨度>
  • persession/single 是默认的,尝试使用并发模式 multiple
  • 使用 PerCall/Single 不是更好吗?我需要每个请求都是唯一的,无论谁是客户。
  • 我不知道我做错了什么,但我把属性与 Multiple/PerSession 并没有什么区别

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


【解决方案1】:

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

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

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

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

一些不错的教程。请参阅第三个调整链接。

WCF Instancing, Concurrency, and Throttling – Part 1

WCF Instancing, Concurrency, and Throttling – Part 2

WCF Instancing, Concurrency, and Throttling – Part 3

【讨论】:

  • 感谢您的建议,两种方法我都试过了,但在发送到数据库服务时请求仍然排队
  • 只是了解一下您如何激活客户端进行测试。您是否可能在同一张表上使用排他锁?
  • 问题不会出现在实际的数据库上,而是出现在激活数据库的服务上。请求在进入该服务之前排队,甚至在表格成为问题之前。
  • 哇,你能把测试代码贴在你排队请求的地方吗?
  • 只是补充一点,当我运行性能测试时,在主服务和第二服务中打开了多个线程,但在数据库连接服务中只有几个线程。两个服务都向该数据库服务发送请求,所以我认为问题不在于测试代码,而可能在于这些服务代码。我认为这可能是因为这两个服务都是来自同一服务器的同一服务的客户端,它们在同一连接上竞争,这有意义吗?
【解决方案2】:

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

【讨论】:

  • 我真的不知道怎么回事...我在所有服务上将其设置为 PerCall 或 PerSession 多个,但似乎仍然没有关系,主要的 http wcf 服务打开了很多线程,但只有少数人使用数据库连接服务...
  • 是并发请求的问题,还是仅仅打开多个实例就变慢了?
  • 我已经添加了一些WCF服务的配置文件,希望对您有所帮助
【解决方案3】:

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

【讨论】:

  • 这实际上与您正在帮助解决的另一个问题有关,谢谢! :)
  • 我在问题中添加了一些配置文件。操作系统是windows server 2008。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-28
  • 2015-05-15
  • 2014-10-23
  • 2021-12-30
  • 1970-01-01
  • 2012-11-05
  • 2012-11-23
相关资源
最近更新 更多