Transactions (5-1) - Serializability Isolation - Serial & 2PL

昨天谈到 write skew 和 phantoms ,是 2 种特别难重现的 竞争条件 (race condition) 情况,也就代表无法针对这些情况做测试,这些只有在你衰小要找奇怪的 bug 时才会遇到,这是个老问题了,而这一切的解法也就显而易见,使用 序列化隔离 (serializable isolation)

序列化隔离是最强的隔离等级,尽管 transaction 能并发执行,但它保证了最终的执行结果等同一次只执行一个 transaction,重点是 连续 (serially) 这个字,表示无并发性 (without concurrency),所以它就能避免所有的竞争条件。

序列化隔离的实现方法有 3 种:

​ (1) 字面上的,连续 (serially) 执行 transactions。

​ (2) 二阶段锁 (Two-Phase Locking 2PL),主宰数十年的实作方式。

​ (3) 优化并发控制技术,就像有了序列化能力的快照隔离。

(1) 连续执行 (Serial Execution) transaction

最简单暴力直觉的实作方法,每一个时间点只会有一个 transaction 执行在单一执行绪上。

为什麽这方法变的可行了呢?归功於越来越便宜和越来越强的 RAM,让一切在 RAM 上执行变的可行;再加上 OLTP transaction 都是短小精干的读取跟写入,长时间写的读取要用 OLAP + 快照隔离来区分。

但是!这就代表了这个实作方法的吞吐量很吃单一 CPU 核心效能,为了让单一执行绪用的更有效率,书中建议我们可以将数个 transaction 会做的事合并成一个 预存程序 (stored procedures) 来执行,就是要减少网路 IO,尽量避免 交互式多语句 (interactive multi-statement) transaction。使用 Day 5 图 7-8 医生排班案例

所以 连续执行 (serial execution) 要可行,最好还是不要违反以下几点的限制:

  • 每个 transaction 必须短小精干,因为只要有一个慢的 transaction 就会拖延其他 transaction 处理。
  • 资料集必须能符合 RAM 的大小。
  • 写入吞吐量必须小於单一 CPU 核心能处理的数量。

(2) 二阶段锁-2PL (Two-Phase Locking)

主宰了序列化隔离 30 几年的实作算法,其实我们在 Day 3 - No Dirty Write 小节看到资料库是怎麽用锁去避免 Drity Write,二阶段锁 (Two-Phase Locking) 也是类似的概念,但锁更强大,当没有 transaction 正在写入时,多个 transaction 允许并发读取同一个物件,一旦有 transaction 想写入物件,它会:

  • 如果 transaction A 想读取物件,而 transaction B 想写入物件,B 必须等待 A commmit 或中断 (abort)。
  • 如果 transaction A 想写入物件,而 transaction B 想读取物件,B 也是必须等待 A commit 或中断 (abort)。

在二阶段锁中,写入只会阻档读取,反之亦然,这跟快照隔离 (Day 4) 的写入跟读取不会互相影响 的核心精神很不同,所以二阶段锁能避免所有的竞争条件写入、昨天提的更新遗失 (lost update) 和 write skew。

实作二阶段锁 (Two-Phase Locking)

为了实现这个写入跟读取互相阻档的资料库 全物件锁,锁的状态可以是 共享模式 (shared mode) 或者是 互斥模式 (exclusive mode),该锁跟随以下规则:

  • 当一个 transaction 想要读取物件,它必须先获取 共享模式 锁,多个 transaction 被允许同时拥有 共享模式 锁,但是一旦有另一个 transaction 有 互斥模式 锁,其他 transaction 必须等待。
  • 当一个 transaction 想要写入物件,它必须获取 互斥模式 锁,该锁一次只能被一个 transaction 所拥有。
  • 当一个 transaction 是先读取资料然後在写入,它的锁必须从 共享模式 升级成 互斥模式 ,这跟你直接获取 互斥模式 锁的意思一样。
  • 当一个 transactino 获取锁之後,它必须持有该锁直到该 transaction commit 或 abort,这也是二阶段锁的由来,获取锁,然後释放。

用这麽多锁免不了可能会发生 死结 (deadlock),也就是 2 个 transaction 彼此等待互相释放锁,幸运的是现在的资料库会自动侦测死结,然後 abort,之後靠应用程序做重试。

二阶段锁 (Two-Phase Locking) 的效能

二阶段锁最大的缺点就是效能啦,transaction 的吞吐量和回应时间比起 弱等级隔离 (Weak Isolation Levels) 要糟上许多,其最大的原因就是要等待 互斥模式 锁的释放,如果你的 transcation 又执行的稍稍久一点,回应时间就烂掉了,所以 2PL 会有非常不稳定的延迟 (lantency),会有非常慢或非常快的回应时间百分位 (2020 Day 3) 发生,还有刚刚讲的死结问题也需要时间解决。


第 (3) 项就明天再讲啦!


<<:  IOS、Python自学心得30天 Day-3 TensorFlow 模组

>>:  Day 6:常见的CSS tag+应用

Day11# Pointer

终於跨入第 11 天,今天要来了解在 Go 里面我很不理解的一个型别 -- Pointer。 话不多...

Soundcloud artists can distribute music to other services

New Soundcloud function: artists from the streamin...

Javascript 执行环境、作用域 - 执行绪与同步、非同步

function eatBreakfast () { console.log('吃早餐'); } f...

Day5 - 关於订阅报价、订阅数上限及计算方式

在设定完帐户後,我们就可以实际收取报价资料以及下单了。 如果要收取商品报价资料,我们会使用subsc...