Nous avons récemment migré nos instances de production de SQL 2008 R2 vers de nouveaux serveurs SQL 2014. Voici un scénario intéressant que nous avons découvert avec notre utilisation de Service Broker. Considérez une base de données avec Broker Enabled = true
avec MyService
et MyQueue
. La gestion des messages incohérents est désactivée dans cette file d'attente. Il y a au moins 2 conversations actives avec des messages dans la file d'attente.
Dans un processus (SPID 100), exécutez:
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
Notez que nous laissons la transaction ouverte. Imaginez que c'est un programme .NET qui attend longtemps sur une ressource externe. Via, sys.dm_tran_locks
nous voyons que ce SPID a obtenu un verrou IX sur la file d'attente.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
Dans un processus distinct (SPID 101), exécutez cinq fois :
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;
La clé ici est que nous annulons la transaction cinq fois . Cela déclenche la logique d'arrière-plan de gestion des messages antipoison intégrée . Bien que la file d'attente ne soit pas désactivée (car elle est configurée pour ne pas se désactiver), une tâche en arrière-plan essaie toujours de fonctionner et de déclencher un broker_queue_disabled
événement. Alors maintenant, si nous interrogeons à sys.dm_tran_locks
nouveau, nous verrons un SPID différent (associé à BRKR TASK
) en attente sur un verrou Sch-M.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
Jusqu'à présent, tout a du sens.
Enfin, sur un processus différent (SPID 102), essayez d'envoyer à un service en utilisant cette file d'attente:
BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');
La SEND
commande est bloquée. Si nous regardons à nouveau, sys.dm_tran_locks
nous voyons que ce processus attend sur un verrou Sch-S. En cours d'exécution, sp_who2
nous constatons que le SPID 102 est bloqué par le 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 |
Pourquoi un verrou Sch-S attend-il sur un verrou Sch-M qui attend également?
Ce comportement est complètement différent dans SQL 2008 R2! En utilisant exactement ce même scénario, exécuté sur nos instances 2008R2 non encore mises hors service, le lot final comprenant la SEND
commande n'est pas bloqué par le verrou Sch-M en attente.
Le comportement de verrouillage a-t-il changé dans SQL 2012 ou 2014? Y a-t-il peut-être un paramètre de base de données ou de serveur qui pourrait affecter ce comportement de verrouillage?
la source
SEND
blocs lors de la vérification de la file d'attente de l' initiateur .SEND
ne bloquerait pas la file d'attente cible , il rebondirait simplement et serait utilisésys.transmission_queue
pour la livraison. Si vous séparez les deux (toujours une bonne idée), vous n'auriez pas le problème.Réponses:
Le comportement a changé entre SQL Server 2008 R2 et SQL Server 2012. L'implémentation de 2008 R2 n'était pas cohérente avec la sémantique documentée «FIFO détendue» :
En 2008 R2, une nouvelle
Sch-S
demande de verrouillage a été accordée bien qu'elle soit incompatible avec l'union des demandes accordées et en attente, ce qui pourrait conduire à la famine de verrouillage. En 2012, laSch-S
demande de verrouillage est bloquée.Le script de reproduction ci-dessous utilise des tables régulières plutôt qu'une file d'attente Service Broker:
En résumé, 2008 R2 ne s'est pas comporté comme prévu. Le problème a été résolu dans SQL Server 2012.
la source