ACID
事務(Transaction)是由一系列對系統(tǒng)中數(shù)據(jù)進行訪問與更新的操作所組成的一個程序執(zhí)行邏輯單元。事務具有四個特征:
- 原子性 (Atomicity)
只有所有的操作全部成功,整個事務才算是成功。任何一項操作失敗都將導致整個事務失敗,已經(jīng)執(zhí)行的操作將被撤銷并回滾
- 一致性 (Consistency)
事務的執(zhí)行結(jié)果必須是使數(shù)據(jù)庫從一個一致性狀態(tài)轉(zhuǎn)變到另一個一致性狀態(tài)。指對數(shù)據(jù)的更改必須滿足對數(shù)據(jù)的狀態(tài)約束。比如對于一個賬單系統(tǒng),賬戶的貸款余額應和借款余額保持平衡。
這種一致性本質(zhì)上要求應用層來維護狀態(tài)一致。而原子性、隔離性和持久性是數(shù)據(jù)庫自身的屬性。
- 隔離性 (Isolation)
數(shù)據(jù)庫多個客戶端同時訪問相同的記錄,可能會遇到并發(fā)問題。隔離性意味著并發(fā)執(zhí)行的各個事務相互隔離,不能相互交叉。這意味著對于并發(fā)事務,其運行結(jié)果與串行執(zhí)行完全相同。
SQL規(guī)范中,根據(jù)事務滿足隔離性的程度將事務分為4個隔離級別:
- 未授權(quán)讀 (Read Uncommitted)
隔離級別最低。允許臟讀,即允許事務訪問另一個事務還沒有提交的數(shù)據(jù)。
允許臟寫,即無法保證寫入的順序,允許后寫入的操作覆蓋較早的寫入。
- 讀-提交 (Read Committed)
不允許臟讀和臟寫。但允許不可重復讀,即一個事務范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值。這是由于在查詢間隔,被另一個事務修改并提交了。允許更新丟失,即兩個事務同時在一個對象上完成“讀-修改-寫”,可能導致第一個事務的更改值丟失。如兩個事務分別將計數(shù)值加一。
數(shù)據(jù)庫通常采用行級鎖來防止臟寫。當事務想修改某個對象時,它必須首先獲得該對象的鎖,然后一直持有鎖直到事務提交或中止。給定時刻,只有一個事務可以拿到特定對象的鎖,如果有另一個事務嘗試更新同一個對象,必須等到前面的事務完成了提交或中止。
可采取同樣的方式防止臟讀。即事務也必須獲取讀鎖來讀取對象。這種方式當寫事務運行時間過長時,會影響讀效率。另一種方式是,對于每個待更新的對象,數(shù)據(jù)庫會維護其舊值與事務將要設置的新值兩個版本。事務提交之前,所有其他讀操作都讀取舊值,事務提交之后,才會切換到讀取新值。
Oracle, DB2, SQL Server,PostgreSQL的默認隔離級別。
- 可重復讀取 (Repeatable Read)
不允許不可重復讀。但允許幻讀,即在一個事務范圍內(nèi)兩次對數(shù)據(jù)總量的統(tǒng)計不一致。這是由于另一個事務執(zhí)行了插入操作。
快照隔離級別是解決可重復讀取最常見的方法。為了實現(xiàn)快照隔離級別,數(shù)據(jù)庫采用了多版本并發(fā)控制(MVCC)保留了對象多個不同的提交版本。在讀-提交的兩個版本(已提交的舊版本和尚未提交的新版本)基礎(chǔ)上,對每個不同的查詢單獨創(chuàng)建一個快照。
解決更新丟失方法有:
1)數(shù)據(jù)庫原子寫操作。如UPDATE counters SET value = value +1 WHERE key = 'foo'。原子寫操作通常是采用對讀取對象加獨占鎖的方式來實現(xiàn)的,這樣在更新被提交之前不會有其他事務可以讀它?;驈娭扑械脑硬僮鞫荚趩尉€程上執(zhí)行。
2)顯示加鎖,如SELECT FOR UPDATE語法。
3)自動檢測更新丟失。數(shù)據(jù)庫可以借助快照級別隔離來檢測更新丟失,如果檢測到則中止當前事務。PostgreSQL, Oracle和 SQL Server都支持。但MySQL不支持。
- 串行化 (Serializable)
不允許幻讀,要求所有事務都被串行執(zhí)行,不能并發(fā)執(zhí)行。
實現(xiàn)串行化最直接的方式是避免并發(fā),即在一個線程上按順序方式每次只執(zhí)行一個事務。Redis采用了這種方式。
- 持久性
一旦某個事務提交,它對數(shù)據(jù)庫所做的更新就必須被永久保存下來,即使存在硬件故障或數(shù)據(jù)庫崩潰。
CAP定理
成熟的ACID模型可保證數(shù)據(jù)的嚴格一致性。但對于一個高并發(fā)的分布式分布式系統(tǒng)來說,嚴格一致性可能犧牲掉可用性。由此出現(xiàn)了CAP定理。
CAP定理指出:一個分布式系統(tǒng)不可能同時滿足一致性、可用性和分區(qū)容錯性,最多只能同時滿足其中兩項。
- 一致性 (Consistency)
同樣數(shù)據(jù)在分布式系統(tǒng)中的多個節(jié)點之間是相同的。在分布式系統(tǒng)中,如果一個數(shù)據(jù)項的更新操作成功后,所有用戶都可以讀取到其最新的值,這樣的系統(tǒng)認為具有強一致性。
- 可用性 (Availability)
系統(tǒng)對于用戶的每一個操作請求總是能夠在有限的時間內(nèi)返回結(jié)果。
- 分區(qū)容錯性 (Partition tolerance)
分布式系統(tǒng)在遇到任何網(wǎng)絡分區(qū)故障的時候,仍能夠保證對外提高滿足一致性和可用性的服務,除非是整個網(wǎng)絡環(huán)境都發(fā)生了故障。
BASE理論
BASE是對CAP中一致性和可用性權(quán)衡的結(jié)果。
- 基本可用 (Basically Available)
分布式系統(tǒng)在出現(xiàn)不可預知故障的時候,允許損失部分可用性。包括:響應時間上的損失和功能上的損失。
- 軟狀態(tài) (Soft state)
允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認為該狀態(tài)不影響系統(tǒng)的整體可用性,即允許系統(tǒng)在多個不同節(jié)點的數(shù)據(jù)副本存在數(shù)據(jù)延時。
- 最終一致性 (Eventually consistent)
上面說軟狀態(tài),然后不可能一直是軟狀態(tài),必須有個時間期限。在期限過后,應當保證所有副本保持數(shù)據(jù)一致性,從而達到數(shù)據(jù)的最終一致性。這個時間期限取決于網(wǎng)絡延時、系統(tǒng)負載、數(shù)據(jù)復制方案設計等等因素。
而在實際工程實踐中,最終一致性分為5種:
- 因果一致性(Causal consistency)
因果一致性指的是:如果節(jié)點A在更新完某個數(shù)據(jù)后通知了節(jié)點B,那么節(jié)點B之后對該數(shù)據(jù)的訪問和修改都是基于A更新后的值。于此同時,和節(jié)點A無因果關(guān)系的節(jié)點C的數(shù)據(jù)訪問則沒有這樣的限制。
- 讀己之所寫(Read your writes)
讀己之所寫指的是:節(jié)點A更新一個數(shù)據(jù)后,它自身總是能訪問到自身更新過的最新值,而不會看到舊值。其實也算一種因果一致性。
- 會話一致性(Session consistency)
會話一致性將對系統(tǒng)數(shù)據(jù)的訪問過程框定在了一個會話當中:系統(tǒng)能保證在同一個有效的會話中實現(xiàn) “讀己之所寫” 的一致性,也就是說,執(zhí)行更新操作之后,客戶端能夠在同一個會話中始終讀取到該數(shù)據(jù)項的最新值。
- 單調(diào)讀一致性(Monotonic read consistency)
單調(diào)讀一致性指的是:如果一個節(jié)點從系統(tǒng)中讀取出一個數(shù)據(jù)項的某個值后,那么系統(tǒng)對于該節(jié)點后續(xù)的任何數(shù)據(jù)訪問都不應該返回更舊的值。
- 單調(diào)寫一致性(Monotonic write consistency)
單調(diào)寫一致性指的是:一個系統(tǒng)要能夠保證來自同一個節(jié)點的寫操作被順序的執(zhí)行。