Параллельные запросы WCF накапливаются на сервере при использовании WSHttpBinding
У меня есть приложение клиент / сервер WCF, которое общается по HTTP с помощью WSHttpBinding.
Настройка сервера: сам хостинг, с использованием стандартного WCF ServiceHost
, Мой фактический класс обслуживания приписывается как:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false)]
Настройка клиента: использование клиентского прокси-сервера, сгенерированного Visual-Studio, с использованием синхронных вызовов службы (proxy.call_server_method
блокирует до тех пор, пока сервер не ответит полностью.)
Сценарий: у меня есть один конкретный вызов метода, выполнение которого на сервере занимает 20 секунд. Клиент вызывает этот метод в отдельном потоке, поэтому он не задерживается, и ConcurrencyMode.Multiple
означает, что WCF должен выполнять его также в отдельном потоке на сервере.
Эта теория подтверждается тем фактом, что при настройке приложения NetTcpBinding
все работает нормально.
Проблема:
Если я настрою приложение для использования WSHttpBinding
, затем этот длинный вызов метода заставляет http-запросы "резервировать". Я проверил это поведение как путем проверки моих журналов, так и путем отладки HTTP-запросов с использованием fiddler.
Пример:
- Клиент инициирует 20-секундный длинный запрос в фоновом потоке
- Клиент инициирует запрос B и C в основном потоке
- Запросы B и C отправляются на сервер, который не обрабатывает их, пока не выполнит 20-секундный длинный запрос.
Но иногда:
- Запросы B и C не отправляются (они даже не появляются в fiddler), пока не вернется 20-секундный запрос (это редко).
- Примечание: настройка
<add address="*" maxconnection="100"/>
в app.config клиента это перестало происходить.
- Примечание: настройка
- Запрос B отправляется и получает ответ немедленно, в то время как запрос C задерживается до завершения 20-секундного (это редко)
Вот график от Fiddler, демонстрирующий проблему: (нажмите для увеличения)
http://farm4.static.flickr.com/3311/3510636841_2a27435eec_o.png
Как вы можете видеть, все запросы сохраняются на сервере. Когда 20-секундный запрос завершается, все ответы поступают, но обратите внимание, что есть некоторые запросы, которые не задерживаются...
Итак, вопросы:
- Какого черта здесь происходит? Почему это работает нормально, используя
NetTcpBinding
и не работать с помощьюWSHttpBinding
? - Почему противоречивое поведение?
- Что я могу сделать, чтобы это исправить?
Заметки:
- Это не блокировка на сервере. Я установил точки останова и использовал
!syncblk
и это последовательно сообщает, что никакие замки не удерживаются. - Это не моя нить (иначе NetTcpBinding не должен работать)
- я имею
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000" />
установить в app.config сервера - 20-секундный вызов просто ждет по таймеру, он не перебивает процессор, диск или сеть
- Я бы предпочел решение, которое не включало бы повторную архитектуру приложения для использования асинхронных вызовов... это большая куча устаревшего кода, и я действительно не хочу возиться с вещами, которые я не понимаю.
8 ответов
[Само-ответ, чтобы показать другим пользователям, каким было наше возможное решение]
В конце концов мне так и не удалось решить это.
Нашим окончательным решением было переключить наше приложение с WSHttpBinding
и на NetTcpBinding
в производстве - мы планировали сделать это в конце концов по соображениям производительности.
Это довольно прискорбно, так как оставляет черную метку на WSHttpBinding
что может или не может быть оправдано. Если кто-нибудь когда-нибудь придумает решение, которое не включает в себя угробление WSHttpBinding
Я хотел бы знать об этом
За пределами WCF есть некоторый дроссель (.Net или Windows), который по умолчанию разрешает использовать не более двух одновременных исходящих HTTP-соединений. К сожалению, я не могу вспомнить на всю жизнь название этой вещи (и что бы вы положили в app.config или ваше приложение, чтобы переопределить это). Учитывая, что вы не видите, что запросы покидают клиент, и что это только HTTP, я думаю, что вы нажимаете "эту вещь". Я буду продолжать искать его имя.
Обновление: нашел - попробуйте это на клиенте (но измените '2' на большее число):
<configuration>
<system.net>
<connectionManagement>
<add address = "*" maxconnection = "2" />
</connectionManagement>
</system.net>
</configuration>
Мы видели точно такие же симптомы со службой JSON, размещенной в IIS/ASP.NET.
Основная причина в том, что ASP.NET синхронизирует запросы, а не WCF. Нам пришлось отключить состояние сеанса (на уровне приложения), чтобы получить параллельные методы WCF.
Web.config:<system.web> <sessionState mode="Off" /> </system.web>
Обратите внимание, что наш сервис использует webHttpBinding, а не wsHttpBinding. Так что я не уверен, что это также решит проблему Ориона.
Я думаю, что вы достигли лимита протокола, и чтобы обойти его, вам нужно изменить стандартные настройки на клиентском компьютере:
http://support.microsoft.com/kb/183110
http://support.microsoft.com/kb/282402
Я думаю, WSHttpBinding использует настройки WinINET при выдаче запросов.
Рассмотрите возможность использования ConcurrencyMode.Multiple в службах для каждого вызова, чтобы разрешить одновременные вызовы.
Если вы измените на BasicHttpBinding, это работает?
Это так, похоже, это твоя проблема, душит сессия, что-то, что укусило меня в задницу.
Я забыл - это может быть заказ? Я думаю, что, возможно, RM поверх http сохраняет порядок, но, возможно, сеансы Tcp нет (если вы явно не запрашиваете это)? Есть ли в договоре на обслуживание атрибут, описывающий заказанные / неупорядоченные сеансы (я забыл).
Не уверен, но иногда проблема с одновременными вызовами из приложения 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);