011.什麼是分布式事務
要了解分布式事務,必須先了解本地事務。
1.1.本地事務
本地事務,是指傳統的單機資料庫事務,必須具備ACID原則:
原子性
所謂的原子性就是說,在整個事務中的所有操作,要麼全部完成,要麼全部不做,沒有中間狀態。對於事務在執行中發生錯誤,所有的操作都會被回滾,整個事務就像從沒被執行過一樣。
一致性
事務的執行必須保證系統的一致性,在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞,就拿轉帳為例,A有500元,B有500元,如果在一個事務裡A成功轉給B50元,那麼不管發生什麼,那麼最後A帳戶和B帳戶的數據之和必須是1000元。
隔離性
所謂的隔離性就是說,事務與事務之間不會互相影響,一個事務的中間狀態不會被其他事務感知。資料庫保證隔離性包括四種不同的隔離級別:
Read Uncommitted(讀取未提交內容)
Read Committed(讀取提交內容)
Repeatable Read(可重讀)
Serializable(可串行化)
-持久性
所謂的持久性,就是說一旦事務提交了,那麼事務對數據所做的變更就完全保存在了資料庫中,即使發生停電,系統宕機也是如此。
因為在傳統項目中,項目部署基本是單點式:即單個伺服器和單個資料庫。這種情況下,資料庫本身的事務機制就能保證ACID的原則,這樣的事務就是本地事務。
概括來講,單個服務與單個資料庫的架構中,產生的事務都是本地事務。
其中原子性和持久性就要靠undo和redo 日誌來實現。
02undo和redo
在資料庫系統中,既有存放數據的文件,也有存放日誌的文件。日誌在內存中也是有緩存Log buffer,也有磁碟文件log file。
MySQL中的日誌文件,有這麼兩種與事務有關:undo日誌與redo日誌。
1.2.1.undo日誌
資料庫事務具備原子性(**Atomicity**),如果事務執行失敗,需要把數據回滾。
事務同時還具備持久性**(Durability)**,事務對數據所做的變更就完全保存在了資料庫,不能因為故障而丟失。
原子性可以利用undo日誌來實現。
Undo Log的原理很簡單,為了滿足事務的原子性,在操作任何數據之前,首先將數據備份到Undo Log。然後進行數據的修改。如果出現了錯誤或者用戶執行了ROLLBACK語句,系統可以利用Undo Log中的備份將數據恢復到事務開始之前的狀態。
資料庫寫入數據到磁碟之前,會把**數據先緩存在內存**中,事務提交時才會寫入磁碟中。
用Undo Log實現原子性和持久化的事務的簡化過程:
假設有A、B兩個數據,值分別為1,2。
A. 事務開始.
B. 記錄A=1到undo log.
C. 修改A=3.
D. 記錄B=2到undo log.
E. 修改B=4.
F. 將undo log寫到磁碟。
G. 將數據寫到磁碟。
H. 事務提交
如何保證持久性?
事務提交前,會把修改數據到磁碟前,也就是說只要事務提交了,數據肯定持久化了。
如何保證原子性?
- 每次對資料庫修改,都會把修改前數據記錄在undo log,那麼需要回滾時,可以讀取undo log,恢復數據。
- 若系統在G和H之間崩潰
此時事務並未提交,需要回滾。而undo log已經被持久化,可以根據undo log來恢復數據
- 若系統在G之前崩潰
此時數據並未持久化到硬碟,依然保持在事務之前的狀態
缺陷:每個事務提交前將數據和Undo Log寫入磁碟,這樣會導致大量的磁碟IO,因此性能很低。
如果能夠將數據緩存一段時間,就能減少IO提高性能。但是這樣就會喪失事務的持久性。因此引入了另外一種機制來實現持久化,即**Redo Log**.
1.2.2.redo日誌
和Undo Log相反,Redo Log記錄的是**新數據**的備份。在事務提交前,只要將Redo Log持久化即可,不需要將數據持久化,減少了IO的次數。
先來看下基本原理:
Undo + Redo事務的簡化過程
假設有A、B兩個數據,值分別為1,2
A. 事務開始.
B. 記錄A=1到undo log buffer.
C. 修改A=3.
D. 記錄A=3到redo log buffer.
E. 記錄B=2到undo log buffer.
F. 修改B=4.
G. 記錄B=4到redo log buffer.
H. 將undo log寫入磁碟
I. 將redo log寫入磁碟
J. 事務提交
03 安全和性能問題
如何保證原子性?
如果在事務提交前故障,通過undo log日誌恢復數據。如果undo log都還沒寫入,那麼數據就尚未持久化,無需回滾