우리는 최근 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;
여기서 핵심은 트랜잭션을 5 번 롤백한다는 것 입니다. 내장 된 포이즌 메시지 처리 백그라운드 로직을 트리거합니다 . 대기열이 비활성화되지 않도록 구성되어 있지만 (비활성화되지 않도록 구성되어 있기 때문에) 백그라운드 작업이 여전히 작업을 수행하고 broker_queue_disabled
이벤트를 시작 하려고합니다 . 이제 sys.dm_tran_locks
다시 쿼리 BRKR TASK
하면 Sch-M 잠금을 기다리는 다른 SPID (와 관련됨 )가 표시됩니다.
| 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