1

我有一个客户端服务器应用程序。我的场景:

  • .Net 框架 4.6.1
  • 启用超线程的四核 i7 机器
  • 服务器 CPU 负载 20 - 70 %
  • 网络负载 < 5% (GBit NIC)
  • 100 个用户
  • 30 个服务(一些管理服务,每种数据类型的一些通用服务)正在运行,每个用户都连接到所有服务
  • NetTcpBinding(启用压缩)
  • 已启用 ReliableSession
  • 每秒我都会触发(服务器端)一个更新通知,并且所有客户端大约从服务器加载。100 KB
  • 另外一个心跳正在运行(用于测试 15 秒间隔),它只是以 UTC 格式返回服务器时间

有时 WCF 连接会更改为故障状态。通常,当这种情况发生时,服务器根本没有上游网络。我确实写了一个内存转储,并且能够看到很多 WCF 线程正在等待一些WaitQueue. 调用栈是:

Server stack trace: 
   at System.ServiceModel.Channels.TransmissionStrategy.WaitQueueAdder.Wait(TimeSpan timeout)
   at System.ServiceModel.Channels.TransmissionStrategy.InternalAdd(Message message, Boolean isLast, TimeSpan timeout, Object state, MessageAttemptInfo& attemptInfo)
   at System.ServiceModel.Channels.ReliableOutputConnection.InternalAddMessage(Message message, TimeSpan timeout, Object state, Boolean isLast)
   at System.ServiceModel.Channels.ReliableDuplexSessionChannel.OnSend(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.DuplexChannel.Send(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.DuplexChannelBinder.Send(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

我确实调整了设置,似乎情况有所缓解 - 现在出现故障的客户更少了。我的设置:

  • ReliableSession.InactivityTimeout: 01:30:00
  • ReliableSession.Enabled:真
  • ReliableSession.Ordered:假
  • ReliableSession.FlowControlEnabled: 假
  • ReliableSession.MaxTransferWindowSize: 4096
  • ReliableSession.MaxPendingChannels:16384
  • MaxReceivedMessageSize: 1073741824
  • ReaderQuotas.MaxStringContentLength:8388608
  • ReaderQuotas.MaxArrayLength: 1073741824

我被困住了。为什么所有呼叫都试图在 中等待WaitQueue一些TransmissionStrategy?我不关心消息被乱序发送(我自己会处理)。我已经在考虑禁用可靠消息传递,但该应用程序已在全球公司网络中使用。我需要知道我的消息已送达。

有什么想法可以教 WCF 只发送消息而不关心其他任何事情吗?

编辑

服务限制的值设置为Int32.MaxValue

我也尝试将MaxConnectionsand ListenBackLog(on NetTcpBinding) 设置为它们的最大值。它没有改变任何东西——据我所知。

编辑 2

检查 WCF 跟踪它告诉我(德语消息,因此是粗略的翻译)可靠消息传输窗口中没有可用空间 - 然后我得到的只是超时,因为不再发送消息。

那里发生了什么事?可靠的消息传递是否有可能使自己感到困惑?

4

3 回答 3

2

等待队列可能与 wcf 内置的限制行为有关https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/servicethrottling 最好的故障排除方法是启用 wcf跟踪 https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/servicethrottling 并确切知道根本原因是什么

于 2019-01-11T15:51:41.647 回答
1

您是否使用 connectionManagement 设置客户端的最大连接?(如果您的会话是双工的) https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-网络设置

您的 MaxPendingChannels 设置为 16384,这会导致过多的客户端在队列中等待,如果服务器无法及时处理客户端,通道可能会转为故障状态。

FlowControlEnabled 表示当服务器没有剩余空间保存消息时是否继续向服务器端发送消息。你最好把它设置为真。

InactivityTimeout 表示在一定时间内没有消息交换时是否关闭会话。您最好将其设置为合适的值。

另外,你设置绑定的超时时间了吗?

  <netTcpBinding>
    <binding  closeTimeout="" openTimeout="" receiveTimeout="" sendTimeout="" ></binding>
  </netTcpBinding>
于 2019-01-14T06:43:12.630 回答
1

长话短说:

事实证明,我的 WCF 设置很好。

ThreadPool 是限制因素。在高流量(因此是高负载)情况下,我确实会生成大量必须发送给客户端的消息。由于没有足够的工作线程来发送消息,因此这些已排队。在某些时候,队列已满 - 你就在那里。

有关更多详细信息,请查看 Russ Bishop 的这个问题和答案

有趣的细节:这甚至减少了高流量情况下的 CPU 负载。从 30% 到 80% 之间的疯狂飙升到 30% 左右的(几乎)稳定值。我只能假设这是因为线程池线程生成和清理。

编辑

我做了以下事情:

ThreadPool.SetMinThreads(1000, 500)

这种价值观可能就像用大锤敲碎坚果一样——但它确实有效。

于 2019-01-17T12:17:07.313 回答