Di recente abbiamo migrato le nostre istanze di produzione da SQL 2008 R2 a nuovissimi server SQL 2014. Ecco uno scenario interessante che abbiamo scoperto con il nostro utilizzo di Service Broker. Considerare un database con Broker Enabled = true
con MyService
e MyQueue
. La gestione dei messaggi velenosi è disabilitata su questa coda. Ci sono almeno 2 conversazioni attive con messaggi nella coda.
In un processo (SPID 100) eseguire:
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
Si noti che lasciamo aperta la transazione. Immagina che si tratti di un programma .NET in attesa da tempo su alcune risorse esterne. Tramite sys.dm_tran_locks
vediamo che a questo SPID è stato concesso un blocco IX sulla coda.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
In un processo separato (SPID 101) eseguire cinque volte :
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;
La chiave qui è che stiamo eseguendo il rollback della transazione cinque volte . Ciò innesca la logica di background di gestione dei messaggi Poison integrata . Mentre la coda non viene disabilitata (perché è configurata per non disabilitarsi), un'attività in background sta ancora tentando di funzionare e generare un broker_queue_disabled
evento. Quindi ora se eseguiamo sys.dm_tran_locks
nuovamente una query vedremo un SPID diverso (associato BRKR TASK
) in attesa su un blocco Sch-M.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
Finora tutto ha un senso.
Infine, su un altro processo (SPID 102), prova a INVIARE a un servizio utilizzando quella coda:
BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');
Il SEND
comando è bloccato Se guardiamo di nuovo sys.dm_tran_locks
vediamo che questo processo è in attesa di un blocco Sch-S. In esecuzione sp_who2
troviamo che SPID 102 è bloccato da 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 |
Perché un lucchetto Sch-S attende un lucchetto Sch-M che sta aspettando?
Questo comportamento è completamente diverso in SQL 2008 R2! Utilizzando questo stesso identico scenario, in esecuzione sulle nostre istanze 2008R2 ancora da mettere fuori servizio, il batch finale incluso il SEND
comando non viene bloccato dal blocco Sch-M in attesa.
Il comportamento di blocco è cambiato in SQL 2012 o 2014? C'è forse qualche impostazione di database o server che potrebbe influenzare questo comportamento di blocco?
SEND
blocchi durante il controllo della coda dell'iniziatore . SEND
non si bloccherebbe sulla coda di destinazione , rimbalzerebbe e userebbe semplicemente sys.transmission_queue
per la consegna. Se separi i due (sempre una buona idea) non avresti il problema.