1. 程式人生 > >深入理解大資料之——事務及其ACID特性

深入理解大資料之——事務及其ACID特性

目錄

  • 事務簡介
    • 事物的定義
    • 事務的目的
    • 事務的狀態
  • 事務的ACID屬性
    • ACID簡介
    • 原子性(Atomicity)
    • 一致性(Consistency)
    • 隔離性(Isolation)
    • 永續性(Durability)
  • 總結
  • 參考文獻

版權宣告:本文為Heriam博主原創文章,遵循CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。
原文連結:https://jiang-hao.com/articles/2019/backend-transactions-acid.html


事務簡介

事物的定義

事務(Transaction)是由一系列對系統中資料進行訪問或更新的操作所組成的一個程式執行邏輯單元(Unit)。在計算機術語中,事務通常就是指資料庫事務 。

在資料庫管理系統(DBMS)中,事務是資料庫恢復和併發控制的基本單位。它是一個操作序列,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。

例如,銀行轉帳工作:從源帳號扣款並使目標帳號增款,這兩個操作必須要麼全部執行,要麼都不執行,否則就會出現該筆金額平白消失或出現的情況。所以,應該把他們看成一個事務。

在現代資料庫中,事務還可以實現其他一些事情,例如,確保你不能訪問別人寫了一半的資料;但是基本思想是相同的——事務是用來確保無論發生什麼情況,你使用的資料都將處於一個合理的狀態:

transactions are there to ensure, that no matter what happens, the data you work with will be in a sensible state.

它保證在任何情況下都不會出現在轉賬後從一個帳戶中扣除了資金,而未將其存入另一個帳戶的情況。

事務的目的

資料庫事務通常包含了一個序列的對資料庫的讀/寫操作。包含有以下兩個目的:

  1. 為資料庫操作序列提供了一個從失敗中恢復到正常狀態的方法,同時提供了資料庫即使在異常狀態下仍能保持一致性的方法。
  2. 當多個應用程式在併發訪問資料庫時,可以在這些應用程式之間提供一個隔離方法,以防止彼此的操作互相干擾。

當事務被提交給了DBMS,則DBMS需要確保該事務中的所有操作都成功完成且其結果被永久儲存在資料庫中,如果事務中有的操作沒有成功完成,則事務中的所有操作都需要回滾,回到事務執行前的狀態;同時,該事務對資料庫或者其他事務的執行無影響,所有的事務都好像在獨立的執行。

Martin Kleppmann在他的《Designing Data-Intensive Applications》一書中有提到:

Transactions are not a law of nature; they were created with a purpose, namely to simplify the programming model for applications accessing a database. By using transactions, the application is free to ignore certain potential error scenarios and concurrency issues, because the database takes care of them instead (we call these safety guarantees).

在現實情況下,失敗的風險很高。在一個數據庫事務的執行過程中,有可能會遇上事務操作失敗、資料庫系統或作業系統出錯,甚至是儲存介質出錯等情況。而上述Martin的話說明了事務的存在,就是為了能夠簡化我們的程式設計模型,不需要我們去考慮各種各樣的潛在錯誤和併發問題 。我們在實際使用事務時,不需要考慮資料庫宕機,網路異常,併發修改等問題,整個事務要麼提交,要麼回滾,非常方便。所以本質上來說,事務的出現了是為了應用層服務的,而不是資料庫系統本身的需要 。

事務的狀態

因為事務具有原子性,所以從外部看的話,事務就是密不可分的一個整體,事務的狀態也只有三種:Active、Commited 和 Failed,事務要不就在執行中,要不然就是成功或者失敗的狀態。

進一步放大看,事物內部還有部分提交這個中間狀態,其對外是不可見的。

所以,具體來說,事務有以下幾種可能的狀態:

  • Active:事務的初始狀態,表示事務正在執行;
  • Partially Committed:在最後一條語句執行之後;
  • Failed:發現事務無法正常執行之後;
  • Aborted:事務被回滾並且資料庫恢復到了事務進行之前的狀態之後;
  • Committed:成功執行整個事務。

我們也可以看到,事務在執行之後只會以Aborted或者Committed狀態作為結束。

事務的ACID屬性

ACID簡介

為了保持資料庫的一致性,在事務處理之前和之後,都遵循某些屬性,也就是大家耳熟能詳的ACID屬性:

  • 原子性(Atomicity):即不可分割性,事務中的操作要麼全不做,要麼全做
  • 一致性(Consistency):一個事務在執行前後,資料庫都必須處於正確的狀態,滿足完整性約束
  • 隔離性(Isolation):多個事務併發執行時,一個事務的執行不應影響其他事務的執行
  • 永續性(Durability):事務處理完成後,對資料的修改就是永久的,即便系統故障也不會丟失

並非任意的對資料庫的操作序列都是資料庫事務。ACID屬性是一系列操作組成事務的必要條件。總體而言,ACID屬性提供了一種機制,使每個事務都”作為一個單元,完成一組操作,產生一致結果,事務彼此隔離,更新永久生效“,從而來確保資料庫的正確性和一致性。

原子性(Atomicity)

原子性也被稱為“全有或全無規則”。它非常好理解,即整個事務要麼完整發生,要麼根本不發生,不會部分發生。它涉及以下兩個操作:

  • 中止:如果事務中止,則看不到對資料庫所做的更改。
  • 提交:如果事務提交,則所做的更改可見。

拿之前轉賬的例子來說,使用者A給使用者B轉賬,至少要包含兩個操作,使用者A錢數減少,使用者B錢數增加,增加和減少的操作要麼全部成功,要麼全部失敗,是一個原子操作。如下圖,如果事務在T1 完成之後但在T2完成之前失敗,將導致資料庫狀態不正確。

一致性(Consistency)

一致性是指,一個事務必須使資料庫從一個一致性狀態變換到另一個一致性狀態(執行成功),或回滾到原始的一致性狀態(執行失敗)。這意味著必須維護完整性約束,以使在事務之前和之後資料庫保持一致性和正確性。

參考上面的示例,假設使用者A和使用者B兩者的錢加起來一共是700,那麼不管A和B之間如何轉賬,轉幾次賬,這一約束都得成立,即事務結束後兩個使用者的錢相加起來還得是700,這就是事務的一致性。

如果轉賬過程中,僅完成A扣款或B增款兩個操作中的一個,即未保證原子性,那麼結果資料如上述完整性約束也就無法得到維護,一致性也就被打破。可以看出,事務的一致性和原子性是密切相關的,原子性的破壞可能導致資料庫的不一致。

但資料的一致性問題並不都和原子性有關。比如轉賬的過程中,使用者A扣款了100,而使用者B只收款了50,那麼該過程可以符合原子性,但是資料的一致性就出現了問題。

一致性既是事務的屬性,也是事務的目的。也正如本文開篇所提到的,“事務是用來確保無論發生什麼情況,你使用的資料都將處於一個合理的狀態“,這裡所說的合理/正確,也就是指滿足完整性約束。

總的來說,一致性是事務ACID四大特性中最重要的屬性,而原子性、隔離性和永續性,都是作為保障一致性的手段。事務作為這些性質的載體,實現了這種由ACID保障C的機制。

ACID和CAP中C(一致性)的區別

請注意,我們一直在討論的一致性,即ACID中的C,是指單一實體內部的正確狀態在時間維度上的一致性,進一步說,是通過維護資料的完整性約束,來保持資料庫在時間上(比如事務前後)保持一致的正確狀態。因為是描述單一實體的內部狀態,故又稱“內部一致性”。

而CAP原則中的一致性是指在分散式系統中,空間維度上,某一特定時刻,多個實體中不同資料備份之間值的一致性,又稱“外部一致性”。具體我們會在另文CAP原則相關內容中做詳細介紹。

隔離性(Isolation)

隔離性是指,併發執行的各個事務之間不能互相干擾,即一個事務內部的操作及使用的資料,對併發的其他事務是隔離的。此屬性確保併發執行一系列事務的效果等同於以某種順序序列地執行它們,也就是要達到這麼一種效果:對於任意兩個併發的事務T1和T2,在事務T1看來,T2要麼在T1開始之前就已經結束,要麼在T1結束之後才開始,這樣每個事務都感覺不到有其他事務在併發地執行。這要求兩件事:

  • 在一個事務執行過程中,資料的中間的(可能不一致)狀態不應該被暴露給所有的其他事務。
  • 兩個併發的事務應該不能操作同一項資料。資料庫管理系統通常使用鎖來實現這個特徵。

還是拿轉賬來說,在A向B轉賬的整個過程中,只要事務還沒有提交(commit),查詢A賬戶和B賬戶的時候,兩個賬戶裡面的錢的數量都不會有變化。如果在A給B轉賬的同時,有另外一個事務執行了C給B轉賬的操作,那麼當兩個事務都結束的時候,B賬戶裡面的錢必定是A轉給B的錢加上C轉給B的錢再加上自己原有的錢。

如此,隔離性防止了多個事務併發執行時由於交叉執行而導致資料的不一致。事務隔離分為不同級別,包括未提交讀(Read uncommitted)、提交讀(read committed)、可重複讀(repeatable read)和序列化(Serializable)。以上4個級別的隔離性依次增強,分別解決不同的問題。事務隔離級別越高,就越能保證資料的完整性和一致性,但同時對併發效能的影響也越大。

永續性(Durability)

事務的永續性又稱為永久性(Permanency),是指一個事務一旦提交,對資料庫中對應資料的狀態變更就應該是永久性的。即使發生系統崩潰或機器宕機等故障,只要資料庫能夠重新啟動,那麼一定能夠根據事務日誌對未持久化的資料重新進行操作,將其恢復到事務成功結束的狀態。永續性意味著在事務完成以後,該事務所對資料庫所作的更改便持久的儲存在資料庫之中,並不會因為系統故障而被回滾。(完成的事務是系統永久的部分,對系統的影響是永久性的)

許多資料庫通過引入預寫式日誌(Write-ahead logging,縮寫 WAL)機制,來保證事務永續性和資料完整性,同時又很大程度上避免了基於事務直接重新整理資料的頻繁IO對效能的影響。

在使用WAL的系統中,所有的修改都先被寫入到日誌中,然後再被應用到系統狀態中。假設一個程式在執行某些操作的過程中機器掉電了。在重新啟動時,程式可能需要知道當時執行的操作是成功了還是部分成功或者是失敗了。如果使用了WAL,程式就可以檢查log檔案,並對突然掉電時計劃執行的操作內容跟實際上執行的操作內容進行比較。在這個比較的基礎上,程式就可以決定是撤銷已做的操作還是繼續完成已做的操作,或者是保持原樣。

總結

事務(Transaction)是由一系列對系統中資料進行訪問或更新的操作所組成的一個程式執行邏輯單元(Unit)。在事務的ACID特性中,C即一致性是事務的根本追求,而對資料一致性的破壞主要來自兩個方面:

  • 事務的併發執行
  • 事務故障或系統故障

資料庫系統是通過併發控制技術和日誌恢復技術來避免這種情況發生的。

併發控制技術保證了事務的隔離性,使資料庫的一致性狀態不會因為併發執行的操作被破壞。

日誌恢復技術保證了事務的原子性,使一致性狀態不會因事務或系統故障被破壞。同時使已提交的對資料庫的修改不會因系統崩潰而丟失,保證了事務的永續性。

我們將另文對以上兩種技術進行詳細介紹。

參考文獻

  1. What is a database transaction? (2019). Retrieved November 5, 2019, from Stack Overflow website: https://stackoverflow.com/questions/974596/what-is-a-database-transaction

  2. Communcations and Information Processing: First International Conference, ICCIP 2012, Aveiro, Portugal, March 7-11, 2012, Proceedings, 第 2 部分

  3. Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems, 第25節

  4. ACID Properties in DBMS - GeeksforGeeks. (2016, August 7). Retrieved November 5, 2019, from GeeksforGeeks website: https://www.geeksforgeeks.org/acid-properties-in-dbms/

  5. 維基百科. (2011, July 25). 預寫式日誌. Retrieved November 5, 2019, from Wikipedia.org website: https://zh.wikipedia.org/wiki/%E9%A2%84%E5%86%99%E5%BC%8F%E6%97%A5%E5%BF%97

  6. 資料庫事務的概念及其實現原理 - takumiCX - 部落格園. (2018). Retrieved November 5, 2019, from Cnblogs.com website: https://www.cnblogs.com/takumicx/p/9998844.html

  7. 淺入深出MySQL中事務的實現. (2017, August 20). Retrieved November 5, 2019, from 面向信仰程式設計 website: https://draveness.me/mysql-transaction