【JAVA祕籍功法篇-分散式事務】事務的實現原理

語言: CN / TW / HK

事務基本概念

什麼是事務?

在我們平常使用Mysql等資料庫時,經常會遇到事務的提交和回滾等場景。那到底什麼是事務呢?

事務是恢復和併發控制的基本單位,事務有四個特性,也是我們常說的ACID,原子性(Atomicity),一 致性(Consistency),隔離性(Isolation),永續性(Durability)。

事務經典場景

對於銀行轉賬,是我們最常見的事務控制的場景了,比如老王給張三轉賬1萬塊 ,那整個轉賬流程為:

  1. 先查詢老王賬戶是否大於10000
  2. 賬戶大於10000,老王賬戶扣款10000
  3. 張三賬戶增加10000

如果第2步驟執行後,系統崩潰掉了。結果如何呢?

問題:A老王賬戶被扣了 10000 ,但張三的賬戶未能加10000. 此時,老王和張三的金錢總額憑空少了10000 。那麼資料不一致了。

那麼我們如何解決呢?

我們希望步驟 1 和步驟 2 能夠繫結在一起執行,不可分;並且在步驟 1 和步驟 2 執行的過程中,儘量規避中間狀態。即謂事務。

事務在解決上述問題中,提出了以下四種特性

原子性

原子性就是不可拆分的特性,要麼全部成功然後提交(commit) ,要麼全部失敗然後回滾 (rollback)。若開啟事務,在上述場景就不會出現了。 MySQL 通過Redo Log重做日誌實現了原子性,在將執行 SQL 語句時,會先寫入redo log buffer, 再執行 SQL 語句,若 SQL 語句執行出錯就會根據 redo log buffer 中的記錄來執行回滾操作, 由此擁有原子性。

一致性

一致性指事務將資料庫從一種狀態轉變為下一種一致的狀態。比如有一個欄位 name 有 唯一索引約束,那麼在事務前後都不能有重複的 name 出現違反唯一索引約束,否則回滾。 在上述場景中即金錢總數總是 20000 ,不能憑空增加減少。MySQL 通過 undo Log 實現一致性, 執行 SQL 語句時,會先寫入 undo log 再寫入 redo log buffer。undo 是邏輯日誌,會根據之前 的 SQL 語句進行相應回滾, 比如之前是 insert 那麼回滾時會執行一個 delete ,一個 update 會執行 一個相反的 update 。並且除了回滾,undo log 還有一個作用是 MVCC ,當用戶讀取 一行記錄時,若該記錄已經被其他事務佔用,當前事務可通過 undo 讀取之前的行版本資訊,實現非鎖定讀取。並且 undo log 也會產生 redo log ,因為 undo log 也需要永續性的保護。

隔離性

首先介紹如果沒有隔離性會發生的 4 種情況

丟失更新

A 事務撤銷時,把已經提交的 B 事務的更新資料覆蓋了。這種錯誤可能造成很嚴重的問 題,通過下面的賬戶取款轉賬就可以看出來,MySQL 通過三級封鎖協議的第一級解決了丟失更新,事務T要修改資料 A 時必須加鎖,直到 T 結束才釋放鎖。

髒讀

髒讀主要是讀取到了其他事務的資料,而其他事務隨後發生回滾。MySQL 通過三級封鎖 協議的第二級解決了髒讀,在一級的基礎上,要求讀取資料 A 時必須加 S 鎖,讀取完馬上 釋放 S 鎖。

不可重複讀

不可重複讀是讀取到資料後,隨後其他事務對資料發生了修改,無法再次讀取。MySQL 通過三級封鎖協議的第三級解決了不可重複讀。在二級的基礎上,要求讀取資料 A 時必須 加 S 鎖,直到事務結束了才能釋放 S 鎖。

幻讀

幻讀是讀取到資料後,隨後其他事務對資料發生了新增,無法再次讀取。在 InnoDB 引擎 Repeatable Read 的隔離級別下,MySQL 通過 Next- Key Lock 以及 MVCC 解決了幻讀,事務中 分為當前讀以及快照讀。

永續性

一旦事務提交,則其所做的修改就會永久儲存到資料庫中。此時即使系統崩潰,修改的資料 也不會丟失。具體實現原理就是在事務 commit 之前會將,redo log buffer 中的資料持久化到 硬碟中的 redo logfile ,這樣在 commit 的時候,硬碟中已經有了我們修改或新增的資料,由 此做到持久化。

事務原理與鎖

鎖的問題場景:

多對一問題,多個操作者同時操作一個資源,而資源的狀態變化是非原子的(有中間態), 哄搶會導致資源狀態混亂

image.png

事務的問題場景:

一對多的問題,一個操作者需要繫結操作一系列資源(比如多條 sql),若任何一條操作失敗, 都會導致整個操作失去意義;

image.png

事務的實現方案

redo log

redo log 叫做重做日誌,是用來實現事務的永續性。

該日誌檔案由兩部分組成:重做日誌緩衝(redo log buffer) 以及重做日誌檔案(redo log),前者是在記憶體中,後者在磁碟中。 當事務提交之後會把所有修改資訊都會存到該日誌中。

在實際案例中,mysql 為了提升效能不會把每次的資料修改都實時同步到磁碟,而是會先存到 Boffer Pool(緩衝池)裡頭,把這個當作快取 來用。然後使用後臺執行緒去做緩衝池和磁碟之間的同步。

redo log 主要用來恢復資料, 用於保障,已提交事務的持久化特性(宕機時,redo log 的資訊是全的)

undo log

undo log叫做回滾日誌,用於記錄資料被修改前的資訊。他正好跟前面所說的重做日誌所記錄的相反,重做日誌記錄資料被修改後的資訊。

undo log 主要記錄的是資料的邏輯變化,為了在發生錯誤時回滾之前的操作,需要將之前的操作都記錄下來,然後在發生錯誤 時才可以回滾。

mysql 每次寫入資料或者修改資料之前都會把修改前的資訊記錄到 undo log

mysql 鎖技術

當多個請求同時來臨時,mysql 要控制讀讀可並行,而寫讀,寫寫不能並行

| | 讀鎖 | 寫鎖 | | -- | ---- | ---- | | 讀鎖 | 可並行 | 不可並行 | | 寫鎖 | 不可並行 | 不可並行 |

MVCC

MVCC (MultiVersion Concurrency Control) 叫做多版本併發控制。

InnoDB 的 MVCC是通過在每行記錄的後面儲存兩個隱藏的列來實現的。這兩個列,一個儲存了行的建立時間,一個儲存了 行的過期時間,當然儲存的並不是實際的時間值,而是系統版本號。他的主要實現思想是通過資料多版本來做到讀寫分離。從而實現不加鎖讀進而做到讀寫並行。

總結

通過以上技術方案總結

  • 事務的原子性是通過undo log來實現的
  • 事務的永續性是通過redo log來實現的
  • 事務的隔離性是通過 (讀寫鎖+MVCC)來實現的

事物的一致性則是通過原子性,永續性以及隔離性統一來保證的。

分散式事務概念

分散式事務產生的原因

隨著網際網路高速發展,事務的參與者、支援事務的伺服器、資源伺服器以及事務管理器分別位於不同的分散式系統的不同節點 之上。簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分佈在不同的伺服器上,且屬於不同的應用。在這種環境中,我們之前說過資料庫的 ACID 四大特性,已經無法滿足我們分散式事務。本質上來說,分散式事務就是為了保證不同資料庫的資料一致性

如:我們購買王者榮耀的面板時,可以使用點券和優惠券,如果不足的可以通過Q幣在進行補償。那麼我們購買的時候就要扣除我們的優惠券,然後在扣除點券,最後在扣除Q幣。那麼三個操作是在三個不同的伺服器的能力,那麼之間要通過RPC呼叫才能完成。那麼如果我最終Q幣支付失敗了,那整個支付流程都應該是失敗的。那我怎麼能通知到其他不同庫進行業務回滾呢?

image.png

分散式中的兩個基礎理論

在我們做分散式系統中,cap和base理論算是我們經常接觸到的了,在這裡簡單介紹下。,=

CAP理論

CAP 定理,又被叫作布魯爾定理。

CAP 指的是:一致性(Consistency) 、可用性(Availability) 、分割槽容錯性(Partition tolerance )。

[分割槽]  在分散式系統中,不同的節點分佈在不同的子網路中,由於一些特殊的原因,這些子節點之間出現了網路不通的狀態,但他們的內部子網路是正常的。從而導致了整個系統的環境被切分成了若干個孤立的區域。這就是分割槽。

CAP 定律說的是,在一個分散式系統中,最多隻能滿足 C 、A 、P 中的兩個,不可能三個同時滿足。而在分散式系統中,網路無法 100% 可靠,分割槽其實是一個必然現象。

如果我們選擇了 CA 而放棄了 P ,那麼當發生分割槽現象時,為了保證一致性,這個時候必須拒絕請求,但是 A 又不允許,所以分散式系統理論上 不可能選擇 CA 架構,只能選擇 CP 或者 AP 架構。

而且,顯然任何橫向擴充套件策略都要依賴於資料分割槽。因此,設計人員必須在一致性與可用性之間做出選擇。

BASE 理論

往往在分散式系統中無法實現完全一致性,於是有了BASE 理論,它是對 CAP 定律的進一步擴充

BASE 指的是:

  1. Basically Available (基本可用) : 分散式系統在出現故障時,允許損失部分可用功能,保證核心功能可用
  2. Soft state (軟狀態) : 允許系統中存在中間狀態,這個狀態不影響系統可用性
  3. Eventually consistent (最終一致性) : 經過一段時間後,所有節點資料都將會達到一致

BASE 理論是對 CAP 中的一致性和可用性進行一個權衡的結果

BASE 理論核心思想就是:我們無法做到強一致,但每個應用都可以根據自身的業務特點,採用適當的方式來使系統達到最終一致性

BASE 和 ACID 是相反的,它完全不同於 ACID 的強一致性模型,而是通過犧牲強一致性來獲得可用性,並允許資料在一段時 間內是不一致的,但最終達到一致狀態。