NetTcpBinding (WCF) 中 ReliableSession 的意外错误
Unexpected fault on ReliableSession in NetTcpBinding (WCF)
我有一个客户端服务器应用程序。我的场景:
- .Net Framework 4.6.1
- 启用超线程的四核 i7 机器
- 服务器 CPU 负载从 20 - 70 %
- 网络负载 < 5%(千兆网卡)
- 100 位用户
- 30 项服务(一些管理服务,一些针对每种数据类型的通用服务)运行 并且每个用户都连接到所有服务
- NetTcpBinding(启用压缩)
- 已启用 ReliableSession
- 每一秒我都会触发(服务器端)更新通知,并且所有客户端大约从服务器加载。 100 KB
- 此外,心跳是 运行(用于测试 15 秒间隔),它只是 returns 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
我卡住了。为什么所有调用都尝试等待 TransmissionStrategy
中的某些 WaitQueue
?我不关心消息被乱序发送(我自己会处理)。我已经在考虑禁用可靠的消息传递,但该应用程序在全球范围内的公司网络中使用。我需要知道我的消息是否已送达。
有什么想法可以教 WCF 只发送消息而不关心其他任何事情吗?
编辑
服务节流的值设置为Int32.MaxValue
。
我也曾尝试将 MaxConnections
和 ListenBackLog
(在 NetTcpBinding
上)设置为最大值。它没有改变任何东西——据我所知。
编辑 2
检查 WCF Traces 它告诉我(德语消息,因此是一个粗略的翻译)在可靠的消息传输 window 中没有可用的 space - 然后我得到的只是超时,因为不再发送消息。
那里发生了什么事?可靠的消息传递是否可能混淆了自己?
等待队列可能与 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
并确切知道根本原因是什么
您是否使用 connectionManagement 来设置客户端的最大连接数?(如果您的会话是双工的)
https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-network-settings
你的MaxPendingChannels设置为16384,这会导致过多的客户端在队列中等待,如果服务器不能及时处理客户端,通道可能会进入故障状态。
FlowControlEnabled表示当服务器没有space保存消息时是否继续向服务器端发送消息。你最好设置为真。
InactivityTimeout表示在一定时间内没有消息交互时是否关闭session。你最好设置一个合适的值。
此外,您是否设置了绑定的超时时间?
<netTcpBinding>
<binding closeTimeout="" openTimeout="" receiveTimeout="" sendTimeout="" ></binding>
</netTcpBinding>
长话短说:
原来我的WCF设置没问题
ThreadPool 是限制因素。在高流量(因此高负载)的情况下,我确实会生成很多必须发送给客户端的消息。由于没有足够的工作线程来发送消息,因此它们会排队。在某个时候队列已满 - 而你就在那里。
有关更多详细信息,请查看来自 Russ Bishop 的 question & answer。
有趣的细节:这甚至在高流量情况下减少了 CPU 负载。从 30% 到 80% 之间的疯狂飙升到 30% 左右的(n)(几乎)稳定值。我只能假设这是因为线程池线程生成和清理。
编辑
我做了以下事情:
ThreadPool.SetMinThreads(1000, 500)
该值可能就像使用大锤敲螺母一样 - 但它确实有效。
我有一个客户端服务器应用程序。我的场景:
- .Net Framework 4.6.1
- 启用超线程的四核 i7 机器
- 服务器 CPU 负载从 20 - 70 %
- 网络负载 < 5%(千兆网卡)
- 100 位用户
- 30 项服务(一些管理服务,一些针对每种数据类型的通用服务)运行 并且每个用户都连接到所有服务
- NetTcpBinding(启用压缩)
- 已启用 ReliableSession
- 每一秒我都会触发(服务器端)更新通知,并且所有客户端大约从服务器加载。 100 KB
- 此外,心跳是 运行(用于测试 15 秒间隔),它只是 returns 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
我卡住了。为什么所有调用都尝试等待 TransmissionStrategy
中的某些 WaitQueue
?我不关心消息被乱序发送(我自己会处理)。我已经在考虑禁用可靠的消息传递,但该应用程序在全球范围内的公司网络中使用。我需要知道我的消息是否已送达。
有什么想法可以教 WCF 只发送消息而不关心其他任何事情吗?
编辑
服务节流的值设置为Int32.MaxValue
。
我也曾尝试将 MaxConnections
和 ListenBackLog
(在 NetTcpBinding
上)设置为最大值。它没有改变任何东西——据我所知。
编辑 2
检查 WCF Traces 它告诉我(德语消息,因此是一个粗略的翻译)在可靠的消息传输 window 中没有可用的 space - 然后我得到的只是超时,因为不再发送消息。
那里发生了什么事?可靠的消息传递是否可能混淆了自己?
等待队列可能与 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 并确切知道根本原因是什么
您是否使用 connectionManagement 来设置客户端的最大连接数?(如果您的会话是双工的) https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-network-settings
你的MaxPendingChannels设置为16384,这会导致过多的客户端在队列中等待,如果服务器不能及时处理客户端,通道可能会进入故障状态。
FlowControlEnabled表示当服务器没有space保存消息时是否继续向服务器端发送消息。你最好设置为真。
InactivityTimeout表示在一定时间内没有消息交互时是否关闭session。你最好设置一个合适的值。
此外,您是否设置了绑定的超时时间?
<netTcpBinding>
<binding closeTimeout="" openTimeout="" receiveTimeout="" sendTimeout="" ></binding>
</netTcpBinding>
长话短说:
原来我的WCF设置没问题
ThreadPool 是限制因素。在高流量(因此高负载)的情况下,我确实会生成很多必须发送给客户端的消息。由于没有足够的工作线程来发送消息,因此它们会排队。在某个时候队列已满 - 而你就在那里。
有关更多详细信息,请查看来自 Russ Bishop 的 question & answer。
有趣的细节:这甚至在高流量情况下减少了 CPU 负载。从 30% 到 80% 之间的疯狂飙升到 30% 左右的(n)(几乎)稳定值。我只能假设这是因为线程池线程生成和清理。
编辑
我做了以下事情:
ThreadPool.SetMinThreads(1000, 500)
该值可能就像使用大锤敲螺母一样 - 但它确实有效。