Как быстро закрыть все элементы Microsoft SQL Server Service Broker? - PullRequest
2 голосов
/ 03 августа 2011

У нас есть приложение, которое создает очереди и службы в SQL Server, используя Service Broker для обработки связи с БД. Приложение использует эти службы и правильно отправляет / получает сообщения, но теперь я хочу проверить фазу инициализации этого приложения (оно создает посредника, а также хранимые процедуры, которые работают за кулисами). По сути, мне нужно отбрасывать элементы брокера с некоторой частотой, и сейчас это действительно очень медленно.

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

Код, который я использую для выключения брокера:

receive * from [dbo].[notify_initiator_queue]
alter queue [dbo].[notify_initiator_queue] with status = OFF
drop service [//DBNotifyService-Initiator]
drop queue [dbo].[notify_initiator_queue]
drop message types, contacts, etc...

Это некоторое время зависает при 'отбрасывании службы [// XF / DBNotifyService-Initiator]'. Есть ли более быстрый способ закрыть и удалить все или некоторые элементы компонента Service Broker?

Спасибо!

== Обновление ==

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

Мое приложение правильно отключило все службы, очереди, контракты и сообщения. Закрытие сервисов заняло целую вечность, потому что в приложении было множество открытых разговоров об ошибке. Эти разговоры создавались, использовались для отправки сообщения, а затем закрывались:

END CONVERSATION @conversation with cleanup

Бит 'with cleanup' закрывает только локальный конец диалога (возможно, он позволяет серверу очистить любые разговоры, которые могли быть допущены с ошибкой на другом конце). Он не закрывает другой конец службы отправки, поэтому разговоры оставались открытыми. Обычные разговоры должны быть закончены:

END CONVERSATION @conversation

Это исправило ошибку приложения. Тем не менее, у меня было несколько миллионов прерванных разговоров в БД. Я мог бы бросить БД, как нормальный человек, или я мог бы попытаться выяснить, как их закрыть. Чтобы закрыть их всех по одному требуется:

declare @conversation uniqueidentifier 
while exists (select top 1 conversation_handle from sys.transmission_queue ) 
begin 
  set @conversation = (select top 1 conversation_handle from sys.transmission_queue )
  end conversation @conversation with cleanup 
end

Это занимает несколько мс на соединение (очень медленно для миллионов). Если я хочу закрыть их все очень быстро, используйте ответ ниже и выполните измененную команду:

ALTER DATABASE [" + target.getTargetDbName() + "] SET NEW_BROKER WITH ROLLBACK IMMEDIATE;

Немедленный откат приводит к разрыву всех соединений, не позволяя им гарантировать фиксацию. В документации говорится: «Все незавершенные транзакции будут отменены, а любые другие подключения к образцу базы данных AdventureWorks2008R2 будут немедленно отключены». http://msdn.microsoft.com/en-us/library/bb522682.aspx

Сервисы теперь очень быстро отключаются, ошибка и открытые соединения исчезли.

1 Ответ

5 голосов
/ 03 августа 2011

Причина медленная, вероятно, потому, что эти элементы заблокированы блокировкой SCH-S, потому что они используются, что предотвращает ваши операторы отбрасывания.Типичным виновником являются активированные процедуры, которые выполняются в фоновом режиме.Это можно быстро выяснить, проверив причину (и) блокировки Activity Monitor или просмотрев sys.dm_exec_requests.Запуск активированных процедур можно увидеть в sys.dm_broker_activated_tasks.

В качестве обходного пути вы можете попробовать ALTER DATABASE SET NEW_BROKER, он отбросит все существующие диалоги, но не очереди / услуги / контракты / типы сообщений,Это также изменит текущую базу данных service_broker_instance_id (важно, если вы использовали ее в маршрутах).Отбрасывая все разговоры, активированные процедуры должны сами закрываться (если они правильно написаны).

Но я бы рекомендовал другой подход.Вместо того, чтобы ваш тест снова и снова использовал одну и ту же базу данных и обрабатывал все ложные сбои на этапе «выключения», вы всегда должны начинать с чистой базы данных и запускать сценарий развертывания на чистой базе данных.Таким образом, вам не нужен код «удаления».См. Контроль версий и ваша база данных .Мы должны создать резервную копию чистой базы данных и всегда начинать с нее, восстанавливать ее и развертывать приложение, а затем запускать проверочные тесты.

...