闩锁和锁(Latches and Locks)

日常的开发中,经常听到闩锁和锁。可能我们对锁的了解要多一些(如数据库锁、线程锁、分布式锁等),但是对闩锁可能了解不多。本文将从锁和闩锁的分类出发,介绍下闩锁和锁的相同与不同,以及各自的应用场景。

锁的分类

锁支持多种划分方法。根据是否具有写权限,可以将锁划分为 S(Shared, 共享)锁 和 X(exclusive, 独占)锁。根据是否意图加锁,可以将锁划分为意图锁(IX(Intention exclusive, Intention Shared, 意图独占)、IS(Intention Shared, 意图共享)和 SIX(Shared Intention exclusive, 意图共享独占))和非意图锁( S 锁和 X 锁)。根据锁定对象的粒度(granularity),如行(记录,元组)锁、表锁和文件(表空间)锁。
(1) S 锁,也称共享锁读锁。S 锁提供读权限。
(2) X 锁,也称排他锁写锁。X 锁提供读取和写入权限。
(3) IS 锁,也称意向共享锁意向读锁。IS 锁表示意图获取 S 锁。
(4) IX 锁,也称意向排他锁意向写锁。IX 锁表示意图获取 X 锁。
(5) SIX 锁,也称意向共享排他锁意向读写锁。SIX 锁表示意图获取所有资源上的 S 锁和层次结构中较低某些资源的 IX 锁(如在表级加 S 锁,在行级加 X 锁)。
针对不同的锁模式(S/X/IS/IX/SIX),只有当给定对象的锁模式兼容时,这些锁才能让不同的事务同时持有。不同模式的锁,其兼容规则如下所示:

Lock modeSXISIXSIX
S✔️×✔️××
X×××××
IS✔️×✔️✔️✔️
IX××✔️✔️×
SIX××✔️××

上表中, “✔️” 表示兼容,"×"表示不兼容。可以看到:对于X锁,不与其他锁兼容;对于S锁,与S锁和IS锁兼容。对于IS锁,除了X锁,其他锁都兼容。对于IX锁,可以与IS锁和IX锁兼容;对于SIX锁,只与IS锁兼容。
从分层的角度来说,意向锁(IX、IS 和 SIX)通常在层次结构的较高级别(如,表)上获得,而 S 和 X 锁在较低级别(如,记录)上获得。非意向锁(S 和 X)被获取时,隐式授予该较高级别对象的较低级别对象的相应模式的锁。另一方面,意向锁仅授予在较低级别对象上请求的意向锁或非意向锁的权限。如,表上的 SIX 隐式授予该表的所有记录的 S,并允许在记录上显式请求 X。

闩锁的分类

与锁一样,闩锁也支持多种划分。这里记录下SQL Server对闩锁的划分(有兴趣的同学,可以阅读下原文),当然,也可将锁的划分应用到闩锁上。根据访问级别,SQL Server 将闩锁划分为:KP(Keep)闩锁、SH(Shared)闩锁、UP(Update)闩锁、EX(Exclusive)闩锁、DT(Destroy)闩锁。
(1) KP 锁,也称保持闩锁,确保引用的结构不会被破坏。
(2) SH 锁,也称共享闩锁,共同读取引用的结构(如读取数据页)所必需的。
(3) UP 锁,也称更新闩锁
(4) EX 锁,也称独占闩锁,用于阻止其他线程写入或读取引用的结构。
(5) DT 锁,也称销毁闩锁,在销毁引用结构的内容之前获取。
与锁一样,不同模式的闩锁也具有不同级别的兼容性。其兼容规则如下所示:

Latch modeKPSHUPEXDT
KP✔️✔️✔️✔️×
SH✔️✔️✔️××
UP✔️✔️×××
EX✔️××××
DT×××××

只要闩锁兼容,就可以在同一结构上同时获取多个闩锁。如 KP 闩锁可以与除DT闩锁之外的所有其他闩锁兼容。因此 KP 闩锁被认为是“轻量级”的,这意味着使用它时对性能的影响很小。由于 KP 闩锁与 DT 闩锁不兼容,它将防止任何其他操作破坏引用结构。如线程查看缓冲区结构时使用。SH 闩锁与更新UP闩锁或KP闩锁兼容,但与EX闩锁、DT闩锁不兼容。SH 锁在多个线程同时访问资源时使用,以便在SH闩锁下读取。UP 锁,与SH 闩锁 和KP兼容,与其他闩锁不兼容。EX闩锁,仅与KP闩锁兼容,用于阻止其他线程写入或读取引用的结构。DT闩锁与所有闩锁都不兼容,用于销毁引用结构。

闩锁和锁的比较

闩锁和锁均用于控制对共享信息的访问。闩锁就像信号量(Semaphore)。通常,闩锁用于保证数据的物理一致性(physical consistency,如内存中数据一致性),而锁用于保证数据的逻辑一致性(logical consistency,如涉及多个操作的事务一致性)。在多处理器、多线程环境下,需要保证物理一致性。闩锁的持有时间通常比锁短得多(闩锁要比锁高效)。此外,死锁检测器(Deadlock Detector)不会收到有关闩锁等待的通知。闩锁是避免死锁的一种实现方式。
获取和释放闩锁比获取和释放锁廉价的多。在无冲突的场景下,如果闩锁的开销相当于 10 条指令,那么锁的开销就相当于 100 条指令。
相比锁,闩锁的获取更廉价。锁通常保存在锁表中,并通过哈希表定位。而闩锁控制信息(latch control information)始终位于虚拟存储器的固定位置,并且可以通过给定的闩锁名称直接寻址到闩锁信息。有数据显示,每个数据库事务最多同时持有两个或三个闩锁。因此,闩锁请求块(latch request block)可以永久分配给每个事务,并在该事务开始时使用事务 ID 等进行初始化。另一方面,必须动态获取、格式化和释放单个锁的存储空间。这也导致需要执行更多指令来获取和释放锁。这是可取的,因为在大多数系统中,可使用锁的对象的数量比可使用闩锁的对象的数量大多个数量级。
允许锁产生死锁,并通过事务重启来检测和解决锁死锁。必须避免闩锁死锁,一旦出现闩锁死锁,则表示代码中存在错误。锁管理器跟踪事务持有的所有锁,并在事务引发异常时自动释放锁,但操作闩锁的内部程序必须仔细跟踪它们,并将手动清理作为其异常处理的一部分。闩锁不会被跟踪,因此如果任务出现故障,则无法自动释放。

总结

闩锁和锁均用于控制对共享信息的访问。根据读写权限、访问意图,可将锁划分为 S锁 、X锁、意图独占锁、意图共享锁、意图共享独占锁。同时,也可根据锁定对象的粒度,将其划分为行锁、、表锁、数据库锁等。根据访问级别,可将闩锁划分为:KP闩锁、SH闩锁、UP闩锁、EX闩锁、DT闩锁。不同级别的锁之间存在兼容性,要根据兼容规则和业务场景,选择合适的加锁级别。闩锁主要用于保证数据的物理一致性,锁主要用于保证数据的逻辑一致性。相比锁作用于高层次结构数据,闩锁则作用于低层次数据结构。

参考

https://cs.stanford.edu/people/chrismre/cs345/rl/aries.pdf ARIES: A Transaction Recovery Method Supporting Fine-Granularity Locking and Partial Rollbacks Using Write-Ahead Logging
https://datacadamia.com/data/concurrency/latches Concurrency - Latches (System Lock)
https://learn.microsoft.com/en-us/sql/relational-databases/diagnose-resolve-latch-contention?view=sql-server-ver16 Diagnose and resolve latch contention on SQL Server
https://www.cnblogs.com/panxuejun/p/8874321.html 共享锁(S锁)和排它锁(X锁)
https://progress-supportcommunity.force.com/s/article/P6854 What are IS IX SIX locks?
https://progress-supportcommunity.force.com/s/article/21639 Explanation of the Lock Table flags in promon
https://dbafix.com/understanding-six-lock-in-microsoft-sql-server/ Understanding SIX lock in Microsoft SQL-Server
https://cn.bing.com/translator 必应翻译

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值