我有一个客户端-服务器应用程序。我的场景:
- .Net框架4.6.1
- 启用超线程的四核i7机器
- 服务器CPU负载从20-70%
- 网络负载<5%(GBit NIC)
- 100个用户
- 运行30个服务(有些是管理服务,有些是每个数据类型的通用服务),每个用户都连接到所有服务
- NetTcpBinding(启用压缩)
- 已启用ReliableSession
- 每秒钟我都会触发(服务器端)一个更新通知,所有客户端从服务器加载大约100kB
- 另外,一个心跳正在运行(用于测试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)
我确实调整了设置,似乎情况有所缓解——现在客户的失误减少了。我的设置:
- 可靠会话。不活动超时:01:30:00
- ReliableSession.Enabled:True
- ReliableSession。有序:False
- ReliableSession.FlowControlEnabled:False
- ReliableSession.MaxTransferWindowSize:4096
- ReliableSession.MaxPendingChannels:16384
- 最大接收消息大小:1073741824
- ReaderQuotas.MaxStringContentLength:838808
- 读卡器配额最大排列长度:1073741824
我被卡住了。为什么所有呼叫都试图在TransmissionStrategy
中等待某个WaitQueue
?我不在乎信息发送不正常(我自己会处理的)。我已经在考虑禁用可靠的消息传递,但该应用程序已在全球范围内的公司网络中使用。我需要知道我的信息已经送达。
有什么想法可以教WCF只发送消息,而不关心其他任何事情吗?
编辑
服务限制的值设置为Int32.MaxValue
。
我还尝试将MaxConnections
和ListenBackLog
(在NetTcpBinding
上)设置为它们的最大值。据我所知,这并没有改变任何事情。
编辑2
检查WCF跟踪它告诉我(德语消息,因此是一个粗略的翻译),在可靠的消息传输窗口中没有可用的空间-然后我得到的只是超时,因为不再发送消息。
那里发生了什么事?可靠的消息传递可能会混淆自己吗?
等待队列可以与节流行为中内置的wcf相关https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/servicethrottling故障排除的最佳方法是启用wcf跟踪https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/servicethrottling并且确切地知道的根本原因是什么
您是否使用connectionManagement来设置客户端的最大连接?(如果您的会话是双工的)https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-network-settings
您的MaxPendingChannels设置为16384,这将使太多客户端在队列中等待,如果服务器不能及时处理客户端,则通道可能会变为故障状态。
FlowControlEnabled表示当服务器没有空间保存消息时,是否继续向服务器端发送消息。你最好把它设为真。
InactivityTimeout表示在一定时间段内没有消息交换时是否关闭会话。你最好把它设置成一个合适的值。
此外,您是否设置了绑定的超时?
<netTcpBinding>
<binding closeTimeout="" openTimeout="" receiveTimeout="" sendTimeout="" ></binding>
</netTcpBinding>
长话短说:
事实证明,我的WCF设置很好。
ThreadPool是一个限制因素。在高流量(因此高负载)的情况下,我确实会生成太多必须发送到客户端的消息。由于没有足够的工作线程来发送消息,这些线程已排队。在某个时刻,队列已经满了——你就在那里。
要了解更多详细信息,请查看此问题&拉斯·毕晓普的回答。
有趣的细节:这甚至降低了高流量情况下的CPU负载。从30%到80%的疯狂峰值到30%左右的(n)(几乎)稳定值。我只能假设这是因为线程池线程生成和清理。
编辑
我做了以下事情:
ThreadPool.SetMinThreads(1000, 500)
这种价值观可能就像用大锤敲坚果一样,但它是有效的。