零星异常调用负载平衡的Web服务

时间:2011-06-13 22:55:41

标签: c# web-services

我有一个Web服务,我在三台负载均衡的Web服务器上运行,而且我遇到了零星的错误。现在,我承认负载平衡部分可能有点红鲱鱼,但是当我只用1个Web服务器进行测试时,我无法重现错误。如果我测试所有三个Web服务器,我可以得到错误(但它不是100%的时间,更像是50%)。所有测试都是通过负载均衡器完成的,我们只告诉负载均衡器我们想要多少台服务器。

代码是简单的单一请求代码。也就是说,没有国家。发出请求并返回响应。 Web服务代码是在IIS 7.5上运行的c#.NET 4。客户端代码既是网站也是桌面应用程序。

我得到两个例外之一:

  

System.ServiceModel.Security.MessageSecurityException:   不安全或不正确的安全   从另一方收到了错误   派对。查看内部FaultException   用于故障代码和细节。 --->   System.ServiceModel.FaultException:   安全上下文令牌已过期   或无效。消息不是   处理。

或者我得到:

  

System.ServiceModel.Security.SecurityNegotiationException:   安全通道无法打开   因为与安全谈判   远程端点失败。这可能   由于缺席或不正确   指定的EndpointIdentity   用于创建的EndpointAddress   渠道。请验证   指定或暗示的EndpointIdentity   由EndpointAddress正确   标识远程端点。 --->   System.ServiceModel.FaultException:   安全令牌的请求有   无效或格式错误的元素。

从我的.config文件中可以看到以下剪辑,我没有使用安全性,因为这严格来说是一个内部Web服务。 (名称已被更改以保护无辜者 - 即我)。

服务器端:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Service Side web.config -->
...
  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <services>
      <service behaviorConfiguration="InternalUseOnly.InternalUseOnlyServiceBehavior" name="InternalUseOnly.InternalUseOnlyService">
        <endpoint address="" bindingNamespace="http://somecompany.com/webservices" binding="wsHttpBinding" contract="InternalUseOnly.IInternalUseOnlyService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="InternalUseOnly.InternalUseOnlyServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
...
</configuration>

客户端

<?xml version="1.0" encoding="UTF-8"?>
<!-- Client Side web.config -->
<configuration>
...
    <system.serviceModel>
      <bindings>
        <wsHttpBinding>
          <binding name="WSHttpBinding_IInternalUseOnlyService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
            <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
            <security mode="Message">
              <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
              <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" />
            </security>
          </binding>
        </wsHttpBinding>
      </bindings>
      <client>
        <endpoint address="http://intranet.somecompany.com/InternalUseOnly/InternalUseOnlyService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IInternalUseOnlyService" contract="InternalUseOnlyService.IInternalUseOnlyService" name="WSHttpBinding_IInternalUseOnlyService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
      </client>
    </system.serviceModel>
...
</configuration>

有人想到吗?


其他信息:在查看下面的答案后,我尝试了两件事,但都没有成功。

最明显的变化(我最初没有注意到)是更改客户端上的一个属性以允许cookie <system.serviceModel><bindings><wsHttpBinding><binding name="blah, blah, blah" ... other properties... allowCookies="true" />默认为false。此外,我们的负载均衡器使用cookie来保持亲和力。但是,它没有什么区别(不知道为什么)。

接下来,我在客户端app.config文件中尝试了各种安全选项。这包括<security mode="None" />和更详细的内容:

<security mode="None">
    <transport clientCredentialType="None" proxyCredentialType="None" />
    <message clientCredentialType="None" establishSecurityContext="false" negotiateServiceCredential="false"/>
</security>

尽管最后一个设置只是我的猜测。我没有对app.config进行任何服务器端更改,因为我不知道要改变什么,遗憾的是,我只能测试生产,因为我们只有1个开发Web服务器,而不是3个。

3 个答案:

答案 0 :(得分:4)

我将在这里走出困境并猜测所涉及的安全性是客户端指定的Message安全性:

<security mode="Message">
    <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
    <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" />
</security>

如果您正在创建客户端并进行连接,则可以缓存协商的Windows凭证令牌。如果您没有启用粘性会话,则令牌可能会传递回错误的服务器并将失败。我的猜测是它总是在第二次通话?

答案 1 :(得分:2)

使用没有粘性会话的负载均衡器导致NTLM问题。要纠正此问题,您需要配置会话关联(粘性会话)。如果不这样做,则会出现故障,因为部分NTLM握手发生在一台服务器上而另一部分发生在另一台服务器上。

答案 2 :(得分:1)

虽然克里斯和杰夫帮助让我顺利回答,但实际为我解决的是我在微软Load Balancing Web Services发现的这篇文章。简而言之,我们为Web场解决此问题所要做的就是从默认的wsHttpBinding切换到basicHttpBinding。这并不困难,但这是一个全有或全无的举动。主要的Web服务和每个客户端必须同时重新配置,否则它将会中断。

虽然wsHttpBinding确实具有allowCooikes属性可以设置为true,但是在建立连接之前它显然不会使用它们,此时请求可以在第一个请求上跳转服务器,从而失败