分析为什么WCF比WSE webservice慢得多

时间:2015-03-25 12:49:51

标签: c# performance web-services wcf wse

我们在.NET Framework 4.5上有一个包含WSE 3.0端点和较新WCF端点的Web服务。

WCF正在使用basicHttpBinding

问题是新的 WCF绑定似乎明显变慢(~3x)。它是否在引擎盖下使用相同的机制?

我已经阅读了很多关于启用WCF跟踪的内容。但是当我在制作时启用它时,我会获得大量信息并且不知道如何阅读,例如Microsoft Trace Viewer中的时间轴。

我将不胜感激任何帮助

  • 查找性能差异原因的提示
  • 理论观点的理念,例如WCF处理请求的方式是否存在主要差异
  • 任何有助于配置WCF服务器的工具
  

注意:

     
      
  • 生产中存在问题;一切都在测试服务器上   精细。起初我们怀疑负载均衡器可能是一个因素,   但禁用负载均衡器并不会改变性能

  •   
  • 缓慢可能是由于我们的应用程序/域层。   也许某些线程/连接池阻塞并且消息正在增加   因此而排队。

         

    在这种情况下,是否有人知道为什么行为如此   与WSE(在同一个应用程序池上运行)不同?有没有   队列大小/并发处理默认配置更改   在WSE3.0和WCF之间发生了很大的变化?

         

    有没有办法找出这种情况何时发生?例如。一些 perfmon计数器值得关注?在perfmon我只是在大量可用的性能计数器之间做出选择

  •   

更新

这是我们的服务Web.config的匿名版本:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
    <system.web>
        <httpRuntime executionTimeout="900" maxRequestLength="10240" />
        <webServices>
            <!--<wsdlHelpGenerator href="CustomizedWebServicePage.aspx" />-->
            <protocols>
                <add name="HttpGet" />
                <add name="HttpPost" />
            </protocols>
            <soapExtensionTypes>
                <add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
            </soapExtensionTypes>
        </webServices>
        <compilation defaultLanguage="cs" debug="true" targetFramework="4.5" />
        <customErrors mode="RemoteOnly" />
        <!-- dev only - application pool identity is configured on real environment -->
        <identity impersonate="true" userName="ServiceIdentity" password="********" />
        <authentication mode="Windows" />
        <authorization>
            <allow users="*" />
            <!-- Allow all users -->
        </authorization>
        <trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
        <sessionState mode="InProc" cookieless="false" timeout="20" sqlConnectionString="data source=127.0.0.1;user id=someuserid;password=********;port=42424" />
        <globalization requestEncoding="utf-8" responseEncoding="utf-8" />
        <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
    </system.web>
    <microsoft.web.services2>
        <diagnostics>
            <detailedErrors enabled="true" />
        </diagnostics>
        <policy>
            <cache name="policyCache.xml" />
        </policy>
        <security>
            <timeToleranceInSeconds>43200</timeToleranceInSeconds>
            <defaultTtlInSeconds>43200</defaultTtlInSeconds>
            <x509 storeLocation="LocalMachine" verifyTrust="false" />
            <securityTokenManager type="OurProduct.Business.Authentication.CustomUsernameTokenManager, OurProduct.Business, Version=5.0.2.11517, Culture=neutral" qname="wsse:UsernameToken" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" />
        </security>
        <messaging>
            <maxRequestLength>10240</maxRequestLength>
        </messaging>
    </microsoft.web.services2>
    <startup>
        <supportedRuntime version="v2.0.50727" />
    </startup>
    <system.serviceModel>
        <diagnostics wmiProviderEnabled="true">
            <messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true" />
        </diagnostics>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
        <services>
            <service behaviorConfiguration="OurServiceBehavior" name="OurProduct.Service.OurService">
                <endpoint address=""      binding="basicHttpBinding"  bindingConfiguration="BasicHttpBinding_IXXXOurService" bindingNamespace="http://localhost/XXXOurService" contract="OurProduct.ServiceContracts.XXXOurService.IXXXOurService" />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="OurServiceBehavior">
                    <dataContractSerializer maxItemsInObjectGraph="2147483647" />
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceCredentials>
                        <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="OurProduct.Service.Validation.CustomUserNamePasswordValidator, OurProduct.Service" />
                    </serviceCredentials>
                </behavior>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IXXXOurService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288000" maxBufferSize="524288000" transferMode="Buffered" maxReceivedMessageSize="524288000" messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
                    <readerQuotas maxDepth="524288000" maxStringContentLength="524288000" maxArrayLength="524288000" maxBytesPerRead="524288000" maxNameTableCharCount="524288000" />
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None"     />
                        <message   clientCredentialType="UserName" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
    </system.serviceModel>
    <runtime>
        <gcServer     enabled="true" />
        <gcConcurrent enabled="true" />
    </runtime>
    <system.webServer>
        <security>
            <requestFiltering>
                <requestLimits maxAllowedContentLength="10485761" /> <!-- 10 megabytes -->
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>

4 个答案:

答案 0 :(得分:2)

您的WCF服务配置文件似乎没有显式设置限制值。您可能希望使用性能监视器来跟踪WCF资源和/或调整默认值以确保您没有达到默认的限制值。

服务限制(serviceThrottling)允许您平衡后端WCF服务器上的负载并强制执行资源分配。通过修改WCF服务的配置文件中maxConcurrentCallsmaxConcurrentSessionsmaxConcurrentInstances参数的值来配置后端WCF服务的serviceThrottling行为。

<serviceThrottling
maxConcurrentCalls="200"
maxConcurrentSessions="200"
maxConcurrentInstances="200" />

https://msdn.microsoft.com/en-us/library/ee377061%28v=bts.70%29.aspx

答案 1 :(得分:1)

使用WCF诊断非常好,但据我所知,您将无法从Web服务获得类似的诊断信息,因此您无需进行任何比较。但是,您在答案中准备的诊断程序将指示您在服务呼叫的每个阶段所花费的相对时间。

我会提出一个非常简单的替代方法,因为你在两种情况下都使用http / text。只需使用Fiddler或您最喜欢的代理工具捕获这两个响应并进行比较。而且关键 - 确保你看看http标题,而不仅仅是身体。 Fiddler会告诉你往返时间和响应的大小,这应该足够了。

这可能是什么?显而易见的事情:

  • 使用Windows身份验证和WCF时,我遇到了巨大的性能开销(是的,大约3倍)。我已经看到使用Windows身份验证时消息大小爆炸,因为标头中的大型加密blob(来自内存)。仅在传输方面花费了大量时间。
  • 同样在安全方面,WCF请求是否已加密?如果您使用消息安全性,那么它将打包在服务器端并在客户端解压缩。这也不是免费的。
  • 多个服务实例。您应该为多个实例设置服务,这意味着每个操作都将创建自己的服务实例。这是默认行为。配置为服务类本身的属性,如[System.ServiceModel.ServiceBehavior(ConcurrencyMode = System.ServiceModel.ConcurrencyMode.Multiple)]

你是对的,因为WCF有很多性能计数器。它们按服务,端点和操作分组。您可能需要服务计数器,因为它们有更多信息。查看ServiceModelService 4.0类别,然后查看

  • 致电(显然)
  • 每秒通话数
  • 实例
  • 每秒创建的实例

答案 2 :(得分:1)

我建议按以下方式调试:

  1. 暂时从两项服务中删除所有身份验证和安全逻辑,并查看问题是否仍然存在

  2. 暂时禁用任何业务逻辑,并可能将架构简化为单个变量

  3. 当你说性能较慢时,你的意思是单个用户性能还是负载测试?当你检查一个用户时,你确定服务器是暖的吗?

  4. 如果你计算逻辑的执行时间(例如从服务器方法实现的开始到结束) - 它是否相同?

  5. 记得在基准测试时取消任何记录/跟踪

  6. 您可以尝试将wcf恢复为use XmlSerializer而不是DataContract

答案 3 :(得分:0)

很抱歉回答,我没有足够的评论声誉。 您希望看到哪些具体信息(痕迹)?如果您在设置跟踪时遇到困难,我建议您使用名为SvcConfigEditor.exe的工具。在其中,您可以打开WCF服务的App.Config文件,在“诊断”下,您可以启用跟踪。之后,您可以选择是否要跟踪特定信息 - 所谓的“跟踪级别”(更多关于特定级别的信息 - Configuring tracing)。查看该工具的屏幕截图: Configuration

在您跟踪所需信息后,您可以在Microsoft Trace Viewer中打开日志 - 在其中,您可以查看每个活动的持续时间:例如,考虑这个(抱歉 - 某些标签是捷克语):

很抱歉,图片无法阅读,这里有更大的链接:Trace viewer

在左侧,您可以选择特定的活动 - 如果您拉伸面板,您甚至可以看到开始和结束时间。此外,您还可以看到该活动的总持续时间。选择它后,在左上方的面板中,您可以看到属于该活动的所有呼叫,您还可以看到,哪个呼叫花费了最多的时间来解析(在“时间”列中)。