Возможны ли проблемы параллелизма при использовании атрибута поведения службы WCF, установленного в ConcurrencyMode.Множественный и InstanceContextMode.Значение percall?
У нас есть служба WCF, которая делает много транзакционных вызовов NHibernate. Иногда мы наблюдали тайм-ауты SQL, хотя вызовы обновляли разные строки, а таблицы были настроены на блокировку уровня строк.
После копания в логах, похоже, что разные потоки вводили одну и ту же точку в коде (наша транзакция с использованием блока), и обновление зависало на фиксации. Однако это не имело смысла, потому что мы считали, что следующий класс обслуживания атрибут заставлял уникальный поток выполнения на вызов службы:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
Мы недавно изменили режим параллелизма на ConcurrencyMode.Single и пока не сталкивались с какими-либо проблемами, но ошибка была очень трудной для воспроизведения (если у кого-то есть какие-либо мысли о том, чтобы смыть такую ошибку, дайте мне знать!).
Как бы то ни было, все это подводит меня к моему вопросу: не должен ли InstanceContextMode PerCall обеспечивать потокобезопасность в Службе, даже если ConcurrencyMode имеет значение multiple? Как бы это было? возможно ли, чтобы два вызова обслуживались одним и тем же экземпляром службы?
Спасибо!
4 ответов:
Единственный способ иметь два разных клиента WCF, то есть прокси, ссылающиеся на один и тот же экземпляр службы WCF, - это использовать
InstanceContextMode=InstanceContextMode.Single. Это плохой выбор, если масштабирование является проблемой, поэтому вы хотите использоватьPerCall, Если можете.Когда вы используете
PerCall, каждый вызов службы WCF получает собственный экземпляр службы WCF . Экземпляр службы не используется совместно, но это не означает, что они не используют одно и то же внутреннее хранилище (например, базу данных, память, файл и т. д.). Просто помните,PerCallпозволяет каждому звоните для одновременного доступа к службе WCF.
ConcurrencyModeнастройка управляет потоковой моделью самой службы. ПараметрSingleограничивает выполнение всех экземпляров службы WCF в одном потоке. Таким образом, если у вас есть несколько клиентов, подключающихся одновременно, они будут выполняться только по одному на стороне службы WCF. В этом случае вы используете WCF для обеспечения синхронизации. Это сработает. прекрасно, как вы уже видели, но думайте об этом, как о том, чтобы иметь только макроуровень контроля над синхронизацией-каждый вызов службы WCF будет выполняться полностью, прежде чем следующий вызов может выполняться.Установка
ConcurrencyModeвMultiple, однако, позволит всем экземплярам службы WCF выполняться одновременно. В этом случае Вы несете ответственность за обеспечение необходимой синхронизации. Думайте об этом, как о микроуровне контроля над синхронизацией, так как вы можете синхронизировать только те части каждого вызова, которые необходимо синхронизировать.Я надеюсь, что объяснил это достаточно хорошо, но вот фрагмент документации MSDN для
ConcurrencyModeна всякий случай:Установка ConcurrencyMode в Single указывает системе на ограничение экземпляры службы для одного потока исполнения в то время, которое освобождает вы от работы с потоками проблемы. Значение кратно означает, что сервисные объекты могут быть выполнены с помощью несколько потоков в любой из них время. В в этом случае вы должны обеспечить поток безопасность.
EDIT
Вы спросили
Есть ли какое-либо увеличение производительности, тогда, используя PerCall против Single при использовании ConcurrencyMode.Одинок? Или верно обратное?
Это, скорее всего, будет зависеть от сервиса.
С помощью
InstanceContextMode.PerCallсоздается новый экземпляр службы для каждого вызова через прокси-сервер, так что у вас есть накладные расходы на создание экземпляра. Предполагая, что ваш конструктор службы не делает много, это не будет проблемой.С помощью
InstanceContextMode.Singleсуществует только один экземпляр службы в течение всего времени существования приложения, поэтому практически нет накладных расходов, связанных с созданием экземпляра. Однако этот режим позволяет только одному экземпляру службы обрабатывать каждый вызов, который когда-либо будет выполнен. Таким образом, если у вас есть несколько вызовов, выполняемых одновременно, каждый вызов должен будет ждать завершения других вызовов, прежде чем он может быть выполнен.Для чего это стоит того, вот как я это сделал. Используйте контекст экземпляра
PerCallс параллелизмомMultiple. Внутри класса службы WCF создайте статические члены для управления внутренним хранилищем данных и при необходимости синхронизируйте доступ к этим статическим членам с помощью оператораlock, полейvolatileи т. д. Это позволяет вашей службе хорошо масштабироваться, сохраняя при этом безопасность потока.
Я полагаю, что ответ заключается в том, что существует несколько потоков (на стороне клиента), использующих один и тот же экземпляр прокси, что потенциально позволяет выполнять несколько вызовов в один и тот же экземпляр. Это сообщение имеет более подробное объяснение.
InstanceContextMode.PerCallиConcurrencyMode.Singleдолжно быть нормально, если вы не используете двухсторонние обратные вызовы на сервере. В этом случае вам нужно будет использоватьConcurrencyMode.Reentrant, иначе обратный вызов не сможет получить доступ к заблокированному экземпляру службы и произойдет взаимоблокировка.Так как это создание экземпляра службы per call, другие потоки или вызовы не могут получить к нему доступ. Как указано в статье, упомянутой в других ответах Статья такая комбинация все еще может быть проблемой, если сессия создается на уровне привязки И вы используете тот же объект прокси-службы.
Поэтому, если вы не используете один и тот же прокси-объект или не имеете сессионной привязки и не используете двухсторонние обратные вызовы клиенту ( скорее всего, они должны быть односторонними в любом случае)
InstanceContextMode.PerCallиConcurrencyMode.Singleдолжны быть хорошими.
Я думаю, что все зависит от требования. Если мы собираемся звонить в одну и ту же службу так много раз, то лучше мы можем использовать InstanceContextMode-один, а concurrencymode-несколько.
Comments