【问题标题】:Latency in sending HTTP Web Service Request from C#.NET to Wireshark on same VM将 HTTP Web 服务请求从 C#.NET 发送到同一 VM 上的 Wireshark 的延迟
【发布时间】:2017-10-20 00:33:52
【问题描述】:

我们有一个 C# 编码的 Windows 服务,它通过向 Web 服务端点发送 HTTP 消息来处理事务。系统在负载下显示 C# 代码发送请求和 Wireshark 接收请求之间的延迟为 1 到 32+ 秒,两者都在同一个虚拟机 (VM) 上。由于 C# Windows 服务和 Wireshark 在同一个 VM 上,因此不涉及网络。当我们在 C# 代码中中止连接时,超时时间(32 秒)过去后,请求最终奇怪地发送到 Web 服务端点并由其接收。我们认为这个问题不是由硬件资源引起的,因为这种情况发生在多个环境中,包括功能强大的生产系统,其中延迟时间相对较低。

我们正在使用 .NET Framework v4.6.1。虚拟机是 Windows 2008 R2,SP1。

问题: 是什么导致了延迟?我们如何消除延迟?

技术细节: 这是 app.config 文件中用于通信的 ServiceModel 原始配置:

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="BasicHttpBinding_ITransaction">
      <security mode="Transport"/>
    </binding>
    <binding name="BasicHttpBinding_ITransaction1"/>
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="https://.../" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITransaction" contract="PaymentSwitchReference.ITransaction" name="BasicHttpBinding_ITransaction"/>    
</client>

在c#代码中,我们创建对象:

_client = new TransactionClient();       //TransactionClient class, proxy which contents the delegates and asynchronous calls to server
_client.ChargeAsync(req);                //Call to begin request sending

//In TransactionClient class:

public Plpm.Csp.PaymentService.PaymentSwitchReference.ResponseCharge Charge(Plpm.Csp.PaymentService.PaymentSwitchReference.Charge req) {
            return base.Channel.Charge(req);
}

 [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public System.IAsyncResult BeginCharge(Plpm.Csp.PaymentService.PaymentSwitchReference.Charge req, System.AsyncCallback callback, object asyncState) {             //Here is calling the service 
            return base.Channel.BeginCharge(req, callback, asyncState);
}

[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public Plpm.Csp.PaymentService.PaymentSwitchReference.ResponseCharge EndCharge(System.IAsyncResult result) {
            return base.Channel.EndCharge(result);
        }

private System.IAsyncResult OnBeginCharge(object[] inValues, System.AsyncCallback callback, object asyncState) {
            Plpm.Csp.PaymentService.PaymentSwitchReference.Charge req = ((Plpm.Csp.PaymentService.PaymentSwitchReference.Charge)(inValues[0]));
            return this.BeginCharge(req, callback, asyncState);
}

private object[] OnEndCharge(System.IAsyncResult result) {
            Plpm.Csp.PaymentService.PaymentSwitchReference.ResponseCharge retVal = this.EndCharge(result);
            return new object[] {
                    retVal};
}

private void OnChargeCompleted(object state) {
      if ((this.ChargeCompleted != null)) {
                InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
                this.ChargeCompleted(this, new ChargeCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
      }
}

public void ChargeAsync(Plpm.Csp.PaymentService.PaymentSwitchReference.Charge req) {
            this.ChargeAsync(req, null);
}

public void ChargeAsync(Plpm.Csp.PaymentService.PaymentSwitchReference.Charge req, object userState) { //Creates the delegates and invoke asynchronous communication.
      if ((this.onBeginChargeDelegate == null)) {
          this.onBeginChargeDelegate = new BeginOperationDelegate(this.OnBeginCharge);
      }
      if ((this.onEndChargeDelegate == null)) {
          this.onEndChargeDelegate = new EndOperationDelegate(this.OnEndCharge);
      }
      if ((this.onChargeCompletedDelegate == null)) {
          this.onChargeCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnChargeCompleted);
      }
      base.InvokeAsync(this.onBeginChargeDelegate, new object[] {
                 req}, this.onEndChargeDelegate, this.onChargeCompletedDelegate, userState);
}

当测试运行并且请求数量开始增长时,我们可以看到 BeginCharge 和通过同一 VM 上的 Wireshark 发送事务之间的时间延迟不断增加。我们最终中止了连接(32 秒后),并且我们从 OnChargeCompleted 委托收到了以下预期异常:

> e
> {Plpm.Csp.PaymentService.PaymentSwitchReference.ChargeCompletedEventArgs}
>     Cancelled: false
>     Error: {"An error (The request was aborted: The request was canceled.) occurred while transmitting data over the HTTP channel."}
>     Result: 'e.Result' threw an exception of type 'System.Reflection.TargetInvocationException'
>     UserState: null
>     cancelled: false
>     error: {"An error (The request was aborted: The request was canceled.) occurred while transmitting data over the HTTP channel."}
>     results: null
>     userState: null

此超时中止导致我们的服务完成并显示此异常消息。但是,在我们的服务中止连接的同时,请求却奇怪地成功发送到另一个 VM 上的 Web 服务端点。我们可以在 Wireshark 中看到它是如何在中止后发送和到达的。

我们尝试通过添加 system.web 配置以及 transferMode 和 Timeouts 参数来更改配置文件如下:

  <system.web>
    <httpRuntime maxRequestLength="10240"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ITransaction" transferMode="StreamedRequest" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00">
          <security mode="None"/>
        </binding>
        <binding name="BasicHttpBinding_ITransaction1"/>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://.../" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITransaction" contract="PaymentSwitchReference.ITransaction" name="BasicHttpBinding_ITransaction"/>    
    </client>
  </system.serviceModel>

在 C# 代码中,我们尝试添加以下 KeepAlive 参数:

var customBinding = new CustomBinding(_client.Endpoint.Binding);
var transportElement = customBinding.Elements.Find<HttpTransportBindingElement>();
transportElement.KeepAliveEnabled = false;
_client.Endpoint.Binding = customBinding;
_client.ChargeAsync(req);

但是,结果是一样的,我们继续看到延迟。

任何帮助将不胜感激。

【问题讨论】:

    标签: c# .net wcf network-programming tcp-ip


    【解决方案1】:

    事实证明,这是由于名为“ma​​xconnection”的 WCF 设置造成的。

    这是允许到服务器的最大并发传出 HTTP 连接数。在我们的应用程序中,我们没有明确设置它,因此使用了默认值“2”。此默认值的限制会导致流量在重负载时排队。这体现在此问题中描述的延迟问题中。 解决方案和 Microsoft 的建议是将处理器数量增加到 12 * 数量。如果更改此设置,Microsoft 还建议更改其他相关设置。您可以通过此链接了解更多信息(搜索“maxconnection”):Tuning .NET Application Performance

    根据微软的说法,“2”并发请求的默认值之所以如此之低,是因为这是官方 HTTP 规范所推荐的。如果连接的客户端是面向用户的应用程序(如 Web 浏览器),但对于充当代理的服务器端应用程序(如我们的示例)则不适用。有关为什么“2”是默认设置的更多信息,请访问此链接: Why Only Two Concurrent Requests for WCF Load Testing

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      相关资源
      最近更新 更多