隔離級別、SI 和 SSI

本文是我對最近讀的幾篇論文的總結(jié),沒有太多引用原文,純靠自己的理解和印象串聯(lián)起來。主要是為日后深入了解相關(guān)知識做個簡單“索引”。

本文描述得不是很嚴謹,也不保證完全正確,建議有興趣的同學(xué)去閱讀論文——根據(jù)論文名稱搜索就可以找到。

ACID

事務(wù)是關(guān)系數(shù)據(jù)庫操作的邏輯單位。
事務(wù)的存在,是為從數(shù)據(jù)庫層面保證數(shù)據(jù)的安全性,減輕應(yīng)用程序的負擔

說起“事務(wù)”,總會先想起 “ACID” 四個字母。

  • A:Atomicity,原子性。
  • C:Consistency,一致性。
  • I:Isolation,隔離性。
  • D:Durability,持久性。

原子性、一致性和持久性都比較好理解。

一個事務(wù)可能包含一個或多個操作,原子性保證這些操作要么全部被生效,要么全部不被生效
數(shù)據(jù)庫的一致性是指數(shù)據(jù)庫中的數(shù)據(jù)都滿足“完整性約束”,如主鍵的唯一約束。

事務(wù)提交后,要永久保存到數(shù)據(jù)庫中,這就是持久性。簡單地說就是數(shù)據(jù)要落盤。為了提高系統(tǒng)的可用性,數(shù)據(jù)還應(yīng)該通過某種算法復(fù)制到其它機器。

隔離性是這幾個特性里面比較不好理解的。單個事務(wù)的場景下,談隔離性是沒意義的——事務(wù)之間有并發(fā)才有隔離的必要。簡單地說,隔離性指的就是數(shù)據(jù)庫在并發(fā)事務(wù)下的表現(xiàn)。權(quán)衡安全和性能,數(shù)據(jù)庫一般會有多個隔離級別。

隔離級別

SQL 標準里定義了四個隔離級別:

  • 讀未提交(Read Uncommitted):會出現(xiàn)臟讀(Dirty Read)—— 一個事務(wù)會讀到另一個事務(wù)的中間狀態(tài)。
  • 讀已提交(Read Committed):會出現(xiàn)不可重復(fù)讀(Unrepeatable Read) —— 事務(wù)只會讀到已提交的數(shù)據(jù),但是一行數(shù)據(jù)讀取兩遍得到不同的結(jié)果。
  • 可重復(fù)讀(Repeatable Read):會出現(xiàn)幻讀(Phantom Read) —— 一個事務(wù)執(zhí)行兩個相同的查詢語句,得到的是兩個不同的結(jié)果集(數(shù)量不同)。
  • 可串行化(Serializable):可以找到一個事務(wù)串行執(zhí)行的序列,其結(jié)果與事務(wù)并發(fā)執(zhí)行的結(jié)果是一樣的。

SQL 標準定義的的這四個隔離級別,只適用于基于鎖的事務(wù)并發(fā)控制。后來有人寫了一篇論文 A Critique of ANSI SQL Isolation Levels 來批判 SQL 標準對隔離級別的定義,并在論文里提到了一種新的隔離級別 —— 快照隔離(Snapshot Isolation,簡稱 SI)。

Snapshot Isolation

在 Snapshot Isolation 下,不會出現(xiàn)臟讀、不可重復(fù)度和幻讀三種讀異常。并且讀操作不會被阻塞,對于讀多寫少的應(yīng)用 Snapshot Isolation 是非常好的選擇。并且,在很多應(yīng)用場景下,Snapshot Isolation 下的并發(fā)事務(wù)并不會導(dǎo)致數(shù)據(jù)異常。所以,主流數(shù)據(jù)庫都實現(xiàn)了 Snapshot Isolation,比如 Oracle、SQL Server、PostgreSQL、TiDB、CockroachDB(關(guān)于 MySQL 的隔離級別,可以參考這篇文章)。

雖然大部分應(yīng)用場景下,Snapshot Isolation 可以很好地運行,但是 Snapshot Isolation 依然沒有達到可串行化的隔離級別,因為它會出現(xiàn)寫偏序(write skew)。Write skew 本質(zhì)上是并發(fā)事務(wù)之間出現(xiàn)了讀寫沖突(讀寫沖突不一定會導(dǎo)致 write skew,但是發(fā)生 write skew 時肯定有讀寫沖突),但是 Snapshot Isolation 在事務(wù)提交時只檢查了寫寫沖突。

為了避免 write skew,應(yīng)用程序必須根據(jù)具體的情況去做適配,比如使用SELECT ... FOR UPDATE,或者在應(yīng)用層引入寫寫沖突。這樣做相當于把數(shù)據(jù)庫事務(wù)的一份工作扔給了應(yīng)用層。

Serializable Snapshot Isolation

后來,又有人提出了基于 Snapshot Isolation 的可串行化 —— Serializable Snapshot Isolation,簡稱 SSI(PostgreSQL 和 CockroachDB 已經(jīng)支持 SSI)。

為了分析 Snapshot Isolation 下的事務(wù)調(diào)度可串行化問題,有論文提出了一種叫做 Dependency Serialization Graph (DSG) 的方法(可以參考下面提到的論文,沒有深究原始出處)。通過分析事務(wù)之間的 rw、wr、ww 依賴關(guān)系,可以形成一個有向圖。如果圖中無環(huán),說明這種情況下的事務(wù)調(diào)度順序是可串行化的。這個算法理論上很完美,但是有一個很致命的缺點,就是復(fù)雜度比較高,難以用于工業(yè)生產(chǎn)環(huán)境。

Weak Consistency: A Generalized Theory and Optimistic Implementations for Distributed Transactions 證明在 Snapshot Isolation 下, DSG 形成的環(huán)肯定有兩條 rw-dependency 的邊。

Making snapshot isolation serializable 再進一步證明,這兩條 rw-dependency 的邊是“連續(xù)”的(一進一出)。

后來,Serializable Isolation for snapshot database 在 Berkeley DB 的 Snapshot Isolation 之上,增加對事務(wù) rw-dependency 的檢測,當發(fā)現(xiàn)有兩條“連續(xù)”的 rw-dependency 時,終止其中一個事務(wù),以此避免出現(xiàn)不可串行化的可能。但是這個算法會有誤判——不可以串行化的事務(wù)調(diào)用會出現(xiàn)兩條“連續(xù)”的 rw-dependency 的邊,但是出現(xiàn)兩條“連續(xù)”的 rw-dependency 不一定會導(dǎo)致不可串行化。

Serializable Snapshot Isolation in PostgreSQL 描述了上述算法在 PostgreSQL 中的實現(xiàn)。

上面提到的 Berkeley DB 和 PostgreSQL 的 SSI 實現(xiàn)都是單機的存儲。A Critique of Snapshot Isolation 描述了如何在分布式存儲系統(tǒng)上實現(xiàn) SSI,基本思想就是通過一個中心化的控制節(jié)點,對所有 rw-dependency 進行檢查,有興趣的可以參考論文。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容