【问题标题】:Insufficient winsock resourceswinsock资源不足
【发布时间】:2014-08-02 11:48:43
【问题描述】:

我们有一个 c# Web 服务和客户端,它们都是在 Visual Studio 2008 中创建的(新项目 -> ASP.Net Web 服务应用程序)。服务托管在 Windows server 2012 R2、IIS 8.5 上。

当客户端将数据发送到我们的服务时,我们将其转发给第 3 方服务,将结果保存到数据库并返回给客户端。

问题是,在极少数情况下,当我们的服务负载过重(每秒有很多请求)时,它开始抛出“Insufficient winsock resources available to complete socket connectioninitiation”。

我们发现我们的 Web 服务正在打开许多与 3rd 方服务的 TCP 连接,并使它们处于 TIME_WAIT 状态。当此类连接的数量达到很高的数量(大约 17000)时,整个服务器将失去建立任何新连接的能力。从远程桌面到互联网浏览器的一切都停止工作。这会持续几分钟,然后,当 Windows 开始关闭这些连接时,它会正常恢复。

对于与第 3 方服务的通信,我们的服务在其整个生命周期中仅使用一个 SoapClient 实例。它是在初始化时创建的,永远不会关闭或销毁;永远不会创建新实例。

BLIND.BLINDSoapClient client = new BLIND.BLINDSoapClient(base.binding, base.address);

当将数据发送到第 3 方服务时,我们只需调用它的 web 方法,并保持原样,无需关闭、处置或进行任何清理:

BLIND.Answer answer = client.Search(...);
..save to database
return answer;

我们可以做些什么来避免这种 time_wait 连接的建立?

有没有更好的方法来管理 SoapClient(s)?我们应该为每个请求打开一个新的soap客户端并手动关闭它们吗?

如果相关,下面是我们的绑定设置:

      binding = new BasicHttpBinding();
      binding.Name = "SLTDSoap";
      binding.CloseTimeout = TimeSpan.FromSeconds(Timeout);
      binding.OpenTimeout = TimeSpan.FromSeconds(Timeout);
      binding.ReceiveTimeout = TimeSpan.FromSeconds(Timeout);
      binding.SendTimeout = TimeSpan.FromSeconds(Timeout);
      binding.AllowCookies = false;
      binding.BypassProxyOnLocal = false;
      binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
      binding.MaxBufferSize = 65536;
      binding.MaxBufferPoolSize = 524288;
      binding.MessageEncoding = WSMessageEncoding.Text;
      binding.TextEncoding = System.Text.Encoding.UTF8;
      binding.TransferMode = TransferMode.Buffered;
      binding.UseDefaultWebProxy = true;

      binding.ReaderQuotas.MaxDepth = 32;
      binding.ReaderQuotas.MaxStringContentLength = 8192;
      binding.ReaderQuotas.MaxArrayLength = 16384;
      binding.ReaderQuotas.MaxBytesPerRead = 4096;
      binding.ReaderQuotas.MaxNameTableCharCount = 16384;

      binding.Security.Mode = (_url.StartsWith("https:")) ? BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.None;
      binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
      binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
      binding.Security.Transport.Realm = "";
      binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
      binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;

System.Net.ServicePointManager.DefaultConnectionLimit = 500;

谢谢!

【问题讨论】:

  • 这是Visual Studio在我们添加对第三方Web服务的引用时创建的一个类。右键单击服务引用 -> 添加服务引用

标签: c# asp.net web-services time-wait


【解决方案1】:

根据您的推荐,BLIND.BLINDSoapClient 继承自 System.ServiceModel.ClientBase。这个类是IDisposable,这意味着当你完成它时你应该总是处理它(在后台它调用 Close - 这会在后台关闭通信对象)。

即:

using(var client = new BLIND.BLINDSoapClient(base.binding, base.address)) {
  // enjoy client
}

最终可能会有一些限制导致您的服务器停机。你可以:

  1. 在 iis 上设置对您的站点/webservice 的请求数量限制 - 请参阅 http://www.iis.net/configreference/system.applicationhost/sites/sitedefaults/limits,在重负载下,您调用 webservice 偶尔会失败 - 但在客户端
  2. 将您的 Web 服务从单机解决方案转移到网络农场解决方案(一个机充当负载平衡器,根据当前负载将请求委托给多个机)
  3. 将您的 Web 服务迁移到云端 - 例如 Amazon 或 Azure(同样是 2.,只是您不必关心负载均衡器)

【讨论】:

  • 我们无法处理 BLIND.BLINDSoapClient,因为我们使用同一个对象进行与第 3 方服务的所有通信。如果我处理它,下一个请求将失败,因为客户端将被关闭。在这种情况下,我们必须为每个请求创建此类的新实例。这是更好的做法吗?
  • 附带说明,我们计划在某个时候将服务迁移到云端,但我们现在的首要任务是消除可能由不良设计引起的所有问题。
  • @user3733031 - 更好的做法是在需要时创建新实例并在完成后处理它。否则,连接会在整个 Web 请求期间保持打开状态,而不是在您需要时才打开。
【解决方案2】:

我认为我们可能已经解决了“winsock 资源不足”的问题。

我们设置了以下注册表值: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\MaxUserPort = 60000 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\TcpTimedWaitDelay = 30

我们在窥视时间对生产环境的最大预期负载是每秒 150 个请求。 这意味着我们将在 Windows 开始释放它们之前的 30 秒内创建 4500 个连接。 这远低于 60000,应确保此问题不再发生。

使用这些设置,我们让系统在 3 天内以每秒 150 个请求的速度运行,但问题没有发生。

【讨论】:

    猜你喜欢
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-17
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    相关资源
    最近更新 更多