WCF Параллельные запросы нагромождения на сервере при использовании WSHttpBinding
У меня есть клиентское/серверное приложение WCF, которое обменивается HTTP через WSHttpBinding.
Настройка сервера: самостоятельный хостинг, используя стандартный WCF ServiceHost
.
Мой фактический класс обслуживания присваивается как:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false)]
Настройка клиента: используя созданный визуально-студийный клиентский прокси-сервер с использованием синхронных вызовов службы (proxy.call_server_method
блокирует до тех пор, пока сервер не ответит полностью.)
Сценарий:
У меня есть один конкретный вызов метода, который занимает 20 секунд для выполнения на сервере. Клиент вызывает этот метод в отдельном потоке, поэтому он не удерживается, а ConcurrencyMode.Multiple
означает, что WCF должен выполнять его в отдельном потоке на сервере.
Эта теория подтверждается тем фактом, что при настройке моего приложения на использование NetTcpBinding
все работает нормально.
Проблема:
Если я настрою приложение на использование WSHttpBinding
, то этот длинный вызов метода заставит HTTP-запросы "резервную копию". Я проверил это поведение как от проверки моих журналов, так и от отладки HTTP-запросов с помощью скрипача.
Пример:
- Клиент инициирует 20-секундный длинный запрос в фоновом потоке
- Клиент инициирует запрос B и C на переднем плане
- Запросы B и C отправляются на сервер, который не обрабатывает их до тех пор, пока он не будет выполнен с 20-секундным длинным запросом
Но иногда:
- Запросы B и C не отправляются (они даже не появляются в скрипачках), пока не возвращается 20-секундный запрос (это редко).
- Примечание: установка
<add address="*" maxconnection="100"/>
в клиенте app.config сделала это (кажется) прекратить.
- Запрос B отправляется и сразу получает ответ, в то время как запрос C удерживается до завершения 20-секундного завершения (это редко)
Здесь показана временная шкала от скрипача, демонстрирующая проблему: (нажмите для увеличения)
![3510636841_18f9b2b0a1.jpg]()
Как вы можете видеть, все запросы выполняются на сервере. Как только 20-секундный запрос завершается, все ответы наступают, но обратите внимание, что есть некоторые запросы, которые не получают поддержки...
Итак, Вопросы:
- Что, черт возьми, происходит здесь? Почему он работает нормально, используя
NetTcpBinding
и не работает с помощью WSHttpBinding
?
- Почему несовместимое поведение?
- Что я могу сделать, чтобы исправить это?
Примечания:
- Он не блокируется на сервере. Я установил точки останова и использовал
!syncblk
, и он постоянно сообщает, что блокировки не хранятся.
- Это не моя нить (NetTcpBinding не должно работать иначе)
- У меня
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000" />
установлен на сервере app.config
- 20-секундный вызов просто ждет таймера, он не разбивает процессор, диск или сеть.
- Я бы предпочел решение, которое не включало бы повторное архивирование приложения для использования асинхронных вызовов... это большая группа устаревшего кода, и я действительно не хочу возиться с вещами, которые я не понимаю.
Ответы
Ответ 1
[Self-answer, чтобы показать другим пользователям, какое было наше возможное решение]
В конце концов, мне так и не удалось это решить.
Наше окончательное решение заключалось в том, чтобы отключить наше приложение от WSHttpBinding
и на NetTcpBinding
в производстве - мы планировали сделать это в конечном итоге в любом случае по соображениям производительности.
Это довольно неудачно, поскольку он оставляет черную метку на WSHttpBinding
, которая может быть или не быть оправданной. Если кто-нибудь когда-нибудь придумает решение, которое не связано с канавкой WSHttpBinding
, я хотел бы узнать об этом
Ответ 2
Существует некоторая дроссельная заслонка вне WCF (объект .Net или Windows), которая по умолчанию позволяет не более двух одновременных исходящих HTTP-соединений. К сожалению, я не могу вспомнить, что жизнь меня - это имя вещи (и то, что вы добавили бы в app.config или ваше приложение, чтобы переопределить его). Учитывая, что вы не видите, что запросы покидают клиент, и что это только HTTP, я думаю, что вы нажимаете "это". Я буду продолжать искать его имя.
Обновление: Найденное - попробуйте это на клиенте (но измените "2" на большее число):
<configuration>
<system.net>
<connectionManagement>
<add address = "*" maxconnection = "2" />
</connectionManagement>
</system.net>
</configuration>
Ответ 3
Мы видели точно такие же симптомы с сервисом JSON, размещенным в IIS/ASP.NET.
Основная причина в том, что ASP.NET синхронизирует запросы, а не WCF. Нам пришлось отключить состояние сеанса (на уровне приложения), чтобы получить совпадающие методы WCF.
Web.config:
<system.web> <sessionState mode="Off" /> </system.web>
Обратите внимание, что наша служба использует webHttpBinding, а не wsHttpBinding. Итак, я не уверен, что это также решает проблему Ориона.
Ответ 4
Я думаю, что вы попали в предел протокола и для его работы вам нужно изменить стандартные настройки на клиентской машине:
http://support.microsoft.com/kb/183110
http://support.microsoft.com/kb/282402
Я предполагаю, что WSHttpBinding использует настройки WinINET при выдаче запросов.
Ответ 5
Если вы переходите на BasicHttpBinding, это работает?
Это так, это звучит как это твоя проблема, дросселирование сеанса, что-то, что укусило меня в заднице.
Ответ 6
Рассмотрим использование ConcurrencyMode.Multiple для сервисов для каждого вызова, чтобы разрешить одновременную
вызовы.
Ответ 7
Я забыл - может ли это быть заказ? Я думаю, возможно, RM поверх http сохраняет заказ, но, возможно, сеансы Tcp не (если вы явно не запросите его)? Есть ли атрибут в контракте на обслуживание, описывающий упорядоченные/неупорядоченные сеансы (я забыл).
Ответ 8
Не уверен, но иногда проблема с одновременными вызовами приложения silverlight связана с управлением соединениями с браузером. Для меня решение заключалось в том, чтобы поместить это в наш метод App.xaml.cs, Application_Startup как описано здесь: http://weblogs.asp.net/olakarlsson/simultaneously-calling-multiple-methods-on-a-wcf-service-from-silverlight
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);