iT邦幫忙

2021 iThome 鐵人賽

DAY 6
1
AI & Data

資料工程師修煉之路 Part II系列 第 6

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 小節看到資料庫是怎麼用鎖去避免 Dirty 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) 項就明天再講啦!


上一篇
Transactions (4) - Concurrent Write
下一篇
Transactions (5-2) - Serializability Isolation - SSI & Summary
系列文
資料工程師修煉之路 Part II30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言