Jos*_*gle 11 sql-server service-broker locking
我们最近将生产实例从 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;
Run Code Online (Sandbox Code Playgroud)
请注意,我们将事务保持打开状态。假设它是一个 .NET 程序,它在某些外部资源上等待了很长时间。通过sys.dm_tran_locks我们看到该 SPID 已被授予对队列的 IX 锁。
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
Run Code Online (Sandbox Code Playgroud)
在单独的进程 (SPID 101) 中执行五次:
BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;
Run Code Online (Sandbox Code Playgroud)
这里的关键是我们将事务回滚五次。这会触发内置的中毒消息处理后台逻辑。虽然队列没有被禁用(因为它被配置为不禁用),但后台任务仍在尝试执行工作并触发broker_queue_disabled事件。所以现在如果我们sys.dm_tran_locks再次查询,我们将看到一个不同的 SPID(与 相关联BRKR TASK)等待 Sch-M 锁。
| type | resource_id | mode | status | spid |
| OBJECT | 277576027 | IX | GRANT | 100 |
| OBJECT | 277576027 | Sch-M | WAIT | 36 |
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都说得通。
最后,在不同的进程 (SPID 102) 上,尝试使用该队列发送到服务:
BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');
Run Code Online (Sandbox Code Playgroud)
该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 |
Run Code Online (Sandbox Code Playgroud)
为什么 Sch-S 锁等待同时也在等待的 Sch-M 锁?
这种行为在 SQL 2008 R2 中完全不同!使用完全相同的场景,在我们尚未退役的 2008R2 实例上运行,包含SEND命令的最后一批不会被等待的 Sch-M 锁阻塞。
SQL 2012 或 2014 中的锁定行为是否发生了变化?是否有一些数据库或服务器设置可能会影响这种锁定行为?
Pau*_*ite 17
SQL Server 2008 R2 和 SQL Server 2012 之间的行为确实发生了变化。 2008 R2 实现与记录的“宽松 FIFO”语义不一致:
锁定以宽松的先进先出 (FIFO) 方式授予。尽管顺序不是严格的 FIFO,但它保留了所需的特性,例如避免饥饿并减少不必要的死锁和阻塞。
如果请求的模式与授权请求的联合和挂起请求的模式不兼容,则请求者尚未拥有资源锁的新锁请求将被阻止。
仅当请求的模式与所有授予的模式的并集不兼容时,转换请求才会被阻止,但转换请求本身最初被授予的模式除外。
在 2008 R2 中,新的Sch-S锁请求被授予,尽管它与授予和等待请求的联合不兼容,这可能会导致锁饥饿。2012年,Sch-S锁请求被阻塞。
下面的复制脚本使用常规表而不是 Service Broker 队列:
-- Session 1
CREATE TABLE dbo.LockTest (col1 integer NULL);
INSERT dbo.LockTest (col1) VALUES (1);
BEGIN TRANSACTION;
-- Will hold row-X, Pag-IX, and Tab-IX
INSERT dbo.LockTest (col1) VALUES (2);
-- Session 2
-- Blocked waiting on Sch-M
TRUNCATE TABLE dbo.LockTest;
-- Session 3
-- Takes Sch-S only
-- Not blocked in 2008 R2
SELECT * FROM dbo.LockTest AS LT WITH (READUNCOMMITTED);
Run Code Online (Sandbox Code Playgroud)
总而言之,2008 R2 没有按照设计运行。该问题已在 SQL Server 2012 中修复。
| 归档时间: |
|
| 查看次数: |
2810 次 |
| 最近记录: |