Wir haben kürzlich unsere Produktionsinstanzen von SQL 2008 R2 auf brandneue SQL 2014-Server migriert. Hier ist ein interessantes Szenario, das wir bei der Verwendung von Service Broker entdeckt haben. Betrachten Sie eine Datenbank Broker Enabled = true
mit MyService
und MyQueue
. Die Behandlung von Giftnachrichten ist in dieser Warteschlange deaktiviert. Es gibt mindestens 2 aktive Konversationen mit Nachrichten in der Warteschlange.
In einem Prozess (SPID 100) ausführen:
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
Beachten Sie, dass wir die Transaktion offen lassen. Stellen Sie sich vor, es ist ein .NET-Programm, das lange auf eine externe Ressource wartet. Über sehen sys.dm_tran_locks
wir, dass dieser SPID eine IX-Sperre für die Warteschlange gewährt wurde.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
In einem separaten Prozess (SPID 101) fünfmal ausführen :
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;
Der Schlüssel hier ist, dass wir die Transaktion fünfmal zurücksetzen . Dies löst die integrierte Hintergrundlogik für die Behandlung von Giftnachrichten aus. Während die Warteschlange nicht deaktiviert wird (weil sie so konfiguriert ist, dass sie nicht deaktiviert wird), versucht eine Hintergrundaufgabe immer noch, Arbeit zu leisten und ein broker_queue_disabled
Ereignis auszulösen. Wenn wir jetzt sys.dm_tran_locks
erneut abfragen , sehen wir eine andere SPID (verbunden mit BRKR TASK
), die auf eine Sch-M-Sperre wartet.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
Bisher macht alles Sinn.
Versuchen Sie schließlich bei einem anderen Prozess (SPID 102), mithilfe dieser Warteschlange an einen Dienst zu senden:
BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');
Der SEND
Befehl ist blockiert. Wenn wir uns das noch einmal sys.dm_tran_locks
ansehen, sehen wir, dass dieser Prozess auf ein Sch-S-Schloss wartet. Bei der Ausführung stellen sp_who2
wir fest, dass SPID 102 durch SPID 36 blockiert ist.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
| OBJECT | 277576027 | Sch-S | WAIT | 102 |
Warum wartet eine Sch-S-Sperre auf eine Sch-M-Sperre, die ebenfalls wartet?
Dieses Verhalten ist in SQL 2008 R2 völlig anders! Unter Verwendung des gleichen Szenarios, das auf unseren noch nicht stillgelegten 2008R2-Instanzen ausgeführt wird, wird der letzte Stapel einschließlich des SEND
Befehls nicht durch die wartende Sch-M-Sperre blockiert.
Hat sich das Sperrverhalten in SQL 2012 oder 2014 geändert? Gibt es möglicherweise eine Datenbank- oder Servereinstellung, die dieses Sperrverhalten beeinflussen könnte?
quelle
SEND
Blöcke beim Überprüfen der Initiatorwarteschlange .SEND
würde nicht auf der Block Zielwarteschlange, wäre es einfach abprallen und Verwendungsys.transmission_queue
für die Lieferung. Wenn Sie die beiden trennen (immer eine gute Idee), hätten Sie das Problem nicht.Antworten:
Das Verhalten hat sich zwischen SQL Server 2008 R2 und SQL Server 2012 geändert. Die Implementierung von 2008 R2 stimmte nicht mit der überein dokumentierten "entspannten FIFO" -Semantik überein :
Im Jahr 2008 R2 eine neue
Sch-S
Sperranforderung gewährt, obwohl diese nicht mit der Vereinigung von erteilten und wartenden Anforderungen kompatibel ist, was zu einem Hungersnot führen kann. Im Jahr 2012 wird dieSch-S
Sperranforderung blockiert.Das folgende Reproduktionsskript verwendet reguläre Tabellen anstelle einer Service Broker-Warteschlange:
Zusammenfassend hat sich 2008 R2 nicht wie geplant verhalten. Das Problem wurde in SQL Server 2012 behoben.
quelle