【JAVA祕籍功法篇-分散式事務】事務的實現原理
事務基本概念
什麼是事務?
在我們平常使用Mysql等資料庫時,經常會遇到事務的提交和回滾等場景。那到底什麼是事務呢?
事務是恢復和併發控制的基本單位,事務有四個特性,也是我們常說的ACID,原子性(Atomicity),一 致性(Consistency),隔離性(Isolation),永續性(Durability)。
事務經典場景
對於銀行轉賬,是我們最常見的事務控制的場景了,比如老王給張三轉賬1萬塊 ,那整個轉賬流程為:
- 先查詢老王賬戶是否大於10000
- 賬戶大於10000,老王賬戶扣款10000
- 張三賬戶增加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 的時候,硬碟中已經有了我們修改或新增的資料,由 此做到持久化。
事務原理與鎖
鎖的問題場景:
多對一問題,多個操作者同時操作一個資源,而資源的狀態變化是非原子的(有中間態), 哄搶會導致資源狀態混亂
事務的問題場景:
一對多的問題,一個操作者需要繫結操作一系列資源(比如多條 sql),若任何一條操作失敗, 都會導致整個操作失去意義;
事務的實現方案
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幣支付失敗了,那整個支付流程都應該是失敗的。那我怎麼能通知到其他不同庫進行業務回滾呢?
分散式中的兩個基礎理論
在我們做分散式系統中,cap和base理論算是我們經常接觸到的了,在這裡簡單介紹下。,=
CAP理論
CAP 定理,又被叫作布魯爾定理。
CAP 指的是:一致性(Consistency) 、可用性(Availability) 、分割槽容錯性(Partition tolerance )。
[分割槽] 在分散式系統中,不同的節點分佈在不同的子網路中,由於一些特殊的原因,這些子節點之間出現了網路不通的狀態,但他們的內部子網路是正常的。從而導致了整個系統的環境被切分成了若干個孤立的區域。這就是分割槽。
CAP 定律說的是,在一個分散式系統中,最多隻能滿足 C 、A 、P 中的兩個,不可能三個同時滿足。而在分散式系統中,網路無法 100% 可靠,分割槽其實是一個必然現象。
如果我們選擇了 CA 而放棄了 P ,那麼當發生分割槽現象時,為了保證一致性,這個時候必須拒絕請求,但是 A 又不允許,所以分散式系統理論上 不可能選擇 CA 架構,只能選擇 CP 或者 AP 架構。
而且,顯然任何橫向擴充套件策略都要依賴於資料分割槽。因此,設計人員必須在一致性與可用性之間做出選擇。
BASE 理論
往往在分散式系統中無法實現完全一致性,於是有了BASE 理論,它是對 CAP 定律的進一步擴充
BASE 指的是:
- Basically Available (基本可用) : 分散式系統在出現故障時,允許損失部分可用功能,保證核心功能可用
- Soft state (軟狀態) : 允許系統中存在中間狀態,這個狀態不影響系統可用性
- Eventually consistent (最終一致性) : 經過一段時間後,所有節點資料都將會達到一致
BASE 理論是對 CAP 中的一致性和可用性進行一個權衡的結果
BASE 理論核心思想就是:我們無法做到強一致,但每個應用都可以根據自身的業務特點,採用適當的方式來使系統達到最終一致性
BASE 和 ACID 是相反的,它完全不同於 ACID 的強一致性模型,而是通過犧牲強一致性來獲得可用性,並允許資料在一段時 間內是不一致的,但最終達到一致狀態。
- 保姆級JAVA對接ChatGPT教程,實現自己的AI對話助手
- ChatGPT保姆級註冊教學
- 公司產品太多了,怎麼實現一次登入產品互通?
- 前一陣鬧得沸沸揚揚的IP歸屬地,到底是怎麼實現的?
- 漫談資料安全-老闆擔心敏感資料洩露,該如何建設安全的資料體系?
- 【JAVA祕籍功法篇-分散式事務】事務的實現原理
- 必知必會JVM三-面試必備,JVM堆記憶體詳解
- Spring Cloud Zuul閘道器修改為短連線方法
- Jar包問題查詢指令碼
- Myabtis原始碼分析五-Mybatis配置載入完全圖解,建造者模式的使用
- Myabtis原始碼分析四-快取模組分析 ,裝飾模式的使用
- Mybatis開發要點-resultType和resultMap有什麼區別?
- 程式碼review神器Upsource,讓你快樂的進行CodeReview