Recientemente migramos nuestras instancias de producción de SQL 2008 R2 a nuevos servidores SQL 2014. Aquí hay un escenario interesante que descubrimos con nuestro uso de Service Broker. Considere una base de datos Broker Enabled = true
con MyService
y MyQueue
. El manejo de mensajes de veneno está deshabilitado en esta cola. Hay al menos 2 conversaciones activas con mensajes en la cola.
En un proceso (SPID 100) ejecute:
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
Tenga en cuenta que dejamos abierta la transacción. Imagine que es un programa .NET que espera mucho tiempo en algún recurso externo. A través de sys.dm_tran_locks
vemos que este SPID ha recibido un bloqueo IX en la cola.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
En un proceso separado (SPID 101) ejecute cinco veces :
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;
La clave aquí es que estamos retrasando la transacción cinco veces . Esto activa la lógica de fondo integrada de Manejo de mensajes de envenenamiento . Si bien la cola no se deshabilita (porque está configurada para no deshabilitar), una tarea en segundo plano todavía está tratando de funcionar y disparar un broker_queue_disabled
evento. Entonces, si volvemos a consultar sys.dm_tran_locks
, veremos un SPID diferente (asociado con BRKR TASK
) esperando en un bloqueo Sch-M.
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
Hasta ahora, todo tiene sentido.
Finalmente, en un proceso diferente (SPID 102), intente ENVIAR a un Servicio usando esa Cola:
BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');
El SEND
comando está bloqueado. Si volvemos a mirar sys.dm_tran_locks
, vemos que este proceso está esperando un bloqueo Sch-S. Al ejecutar sp_who2
, encontramos que SPID 102 está bloqueado por 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 |
¿Por qué una cerradura Sch-S espera en una cerradura Sch-M que también está esperando?
¡Este comportamiento es completamente diferente en SQL 2008 R2! Usando exactamente el mismo escenario, ejecutándose en nuestras instancias 2008R2 aún por desmantelar, el lote final que incluye el SEND
comando no se bloquea por el bloqueo Sch-M en espera.
¿Ha cambiado el comportamiento de bloqueo en SQL 2012 o 2014? ¿Existe alguna configuración de base de datos o servidor que pueda afectar este comportamiento de bloqueo?
fuente
SEND
bloques mientras se verifica la cola del iniciador .SEND
no se bloquearía en la cola de destino , simplemente rebotaría y se usaríasys.transmission_queue
para la entrega. Si separa los dos (siempre es una buena idea) no tendría el problema.Respuestas:
El comportamiento cambió entre SQL Server 2008 R2 y SQL Server 2012. La implementación de 2008 R2 fue inconsistente con la semántica documentada 'FIFO relajada' :
En 2008 R2,
Sch-S
se otorgó una nueva solicitud de bloqueo a pesar de ser incompatible con la unión de solicitudes otorgadas y en espera, lo que podría conducir a la inanición por bloqueo. En 2012, laSch-S
solicitud de bloqueo está bloqueada.El siguiente script de reproducción utiliza tablas regulares en lugar de una cola de Service Broker:
En resumen, 2008 R2 no se comportó como se diseñó. El problema se solucionó en SQL Server 2012.
fuente