Неожиданная ошибка в ReliableSession в NetTcpBinding (WCF) - PullRequest
0 голосов
/ 11 января 2019

У меня есть клиент-серверное приложение. Мой сценарий:

  • .Net Framework 4.6.1
  • Quad Core i7 с поддержкой гиперпоточности
  • загрузка ЦП сервера от 20 до 70%
  • Загрузка сети <5% (сетевой адаптер GBit) </li>
  • 100 пользователей
  • 30 служб (некоторые административные, некоторые общие для каждого типа данных) работают, и каждый пользователь подключен ко всем службам
  • NetTcpBinding (сжатие включено)
  • ReliableSession включен
  • каждую секунду я запускаю (на стороне сервера) уведомление об обновлении, и все клиенты загружаются с сервера прибл. 100 кБ
  • дополнительно работает сердцебиение (для проверки интервала 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: True
  • ReliableSession.Ordered: False
  • ReliableSession.FlowControlEnabled: False
  • ReliableSession.MaxTransferWindowSize: 4096
  • ReliableSession.MaxPendingChannels: 16384
  • MaxReceivedMessageSize: 1073741824
  • ReaderQuotas.MaxStringContentLength: 8388608
  • ReaderQuotas.MaxArrayLength: 1073741824

Я застрял. Почему все звонки пытаются ждать WaitQueue в TransmissionStrategy? Меня не волнуют сообщения, отправленные не по порядку (я сам об этом позабочусь). Я уже думал об отключении надежного обмена сообщениями, но приложение используется в сети компании по всему миру. Мне нужно знать, что мои сообщения были доставлены.

Есть идеи, как научить WCF просто отправлять сообщения и больше ни о чем не беспокоиться?

EDIT

Значения для регулирования работы установлены на Int32.MaxValue.

Я также пытался установить MaxConnections и ListenBackLog (на NetTcpBinding) на их максимальные значения. Это ничего не изменило - насколько я могу судить.

РЕДАКТИРОВАТЬ 2

Проверка трассировок WCF говорит мне (немецкое сообщение, следовательно, грубый перевод), что в окне надежной передачи сообщений нет свободного места - и тогда все, что я получаю, это тайм-ауты, потому что больше сообщений не отправляется.

Что там происходит? Возможно ли, что надежный обмен сообщениями смущает себя?

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Используете ли вы connectionManagement для установки maxconnection вашего клиента? (Если ваша сессия дуплексная) https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-network-settings

Ваш MaxPendingChannels установлен в 16384, что заставит слишком много клиентов ждать в очереди, если сервер не сможет вовремя обработать клиентов, канал может перейти в состояние отказа.

FlowControlEnabled означает, следует ли продолжить отправку сообщения на серверную сторону, когда на сервере не осталось места для сохранения сообщения. Тебе лучше установить его на true.

InactivityTimeout означает, закрывать ли сеанс, если обмен сообщениями не происходит в течение определенного периода времени. Вам лучше установить подходящее значение.

Кроме того, вы установили время ожидания привязки?

  <netTcpBinding>
    <binding  closeTimeout="" openTimeout="" receiveTimeout="" sendTimeout="" ></binding>
  </netTcpBinding>
0 голосов
/ 17 января 2019

Короче говоря:

Оказывается, мои настройки WCF просто хороши.

ThreadPool является ограничивающим фактором. В ситуациях с большим трафиком (и, следовательно, с высокой нагрузкой) я генерирую много сообщений, которые должны быть отправлены клиентам. Они помещаются в очередь, так как для отправки сообщений не хватает рабочих потоков. В какой-то момент очередь переполнена - и вот вы здесь.

Для более подробной информации, проверьте вопрос и ответ от Русского Епископа.

Интересная деталь: это даже уменьшило нагрузку на процессор в условиях интенсивного трафика. От сумасшедшего скачка между 30 и 80 процентами до (n) (почти) устойчивого значения около 30 процентов. Я могу только предположить, что это из-за генерации и очистки потоков пула потоков.

EDIT

Я сделал следующее:

ThreadPool.SetMinThreads(1000, 500)

Эти значения могут быть похожи на использование кувалды, чтобы сломать орех - но это работает.

0 голосов
/ 11 января 2019

Очередь ожидания может быть связана со встроенным поведением 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 И точно знать, в чем причина

...