Недавно мы перенесли наши производственные экземпляры с SQL 2008 R2 на новые серверы SQL 2014. Вот интересный сценарий, который мы раскрыли при использовании Service Broker. Рассмотрим базу данных с Broker Enabled = true
помощью MyService
и MyQueue
. Обработка ядовитых сообщений отключена в этой очереди. В очереди минимум 2 активных разговора с сообщениями.
В одном процессе (SPID 100) выполните:
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
Обратите внимание, что мы оставляем транзакцию открытой. Представьте, что это .NET-программа, которая долго ожидает какого-то внешнего ресурса. Посредством этого sys.dm_tran_locks
мы видим, что этому SPID была предоставлена блокировка IX в очереди.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
В отдельном процессе (SPID 101) выполнить пять раз :
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;
Ключевым моментом здесь является то, что мы откатываем транзакцию пять раз . Это запускает встроенную фоновую логику обработки сообщений отравления . Хотя очередь не отключается (поскольку она настроена на отключение), фоновая задача все еще пытается выполнить работу и запустить broker_queue_disabled
событие. Так что теперь, если мы сделаем запрос sys.dm_tran_locks
снова, мы увидим другой SPID (связанный с BRKR TASK
), ожидающий блокировки Sch-M.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
Пока что все имеет смысл.
Наконец, в другом процессе (SPID 102) попытайтесь ОТПРАВИТЬ Сервису, используя эту Очередь:
BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');
Команда SEND
заблокирована. Если мы снова посмотрим на это, sys.dm_tran_locks
то увидим, что этот процесс ожидает блокировки Sch-S. Выполняя sp_who2
мы обнаруживаем, что SPID 102 заблокирован SPID 36.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
| OBJECT | 277576027 | Sch-S | WAIT | 102 |
Почему блокировка Sch-S ожидает блокировки Sch-M, которая также ожидает?
Это поведение совершенно другое в SQL 2008 R2! При использовании точно такого же сценария на наших экземплярах 2008R2, которые еще не списаны, окончательный пакет, включая SEND
команду , не блокируется ожидающей блокировкой Sch-M.
Изменилось ли поведение блокировки в SQL 2012 или 2014? Возможно, есть какие-то настройки базы данных или сервера, которые могут повлиять на это поведение блокировки?
SEND
блоки при проверке инициатора очереди. SEND
не будет блокировать целевую очередь, он будет просто отказов и использовать sys.transmission_queue
для доставки. Если вы разделите два (всегда хорошая идея), у вас не будет проблемы.