一 什么是事務?有什么用?
事務的特性ACID
事務提供了一種機制,可用來將一系列數據庫更改歸入一個邏輯操作。更改數據庫后,所做的更改可以作為一個單元進行提交或取消。事務可確保遵循原子性、一致性、隔離性和持續性(ACID)這幾種屬性,以使數據能夠正確地提交到數據庫中。
1)原子性(Atomicity)原子性是指事務是一個不可分割的工作單位,事務中的操作 要么都發生,要么都不發生。
2)一致性(Consistency)一個事務中,事務前后數據的完整性必須保持一致。
3)隔離性(Isolation)多個事務,事務的隔離性是指多個用戶並發訪問數據庫時, 一個用戶的 事務不能被其它用戶的事務所干擾,多個並發事務之間數據要相互隔離。
4)持久性(Durability)持久性是指一個事務一旦被提交,它對數據庫中數據的改變 就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。
二 事務的並發會產生的問題有哪些
1.臟讀
一個事務正在對數據進行更新操作,但是更新還未提交,另一個事務這時也來操作這組數據,並且讀取了前一個事務還未提交的數據,而前一個事務如果操作失敗進行了回滾,后一個事務讀取的就是錯誤的數據,這樣就造成了臟讀
2.不可重復讀
一個事務多次讀取同一個數據,在該事務還未結束時,另一個事務也對該數據進行 了操作,而且在第一個事務兩次讀取之間,第二個事務對數據進行了更新,那么第一個 事務前后兩個讀取到的數據是不同的,這樣就造成了不可重復讀
3.幻讀
第一個數據正在查詢某一條數據,這時,另一個事務又插入了一條符合條件的數據,第一個事務在第二次查詢符合同一條件的數據時,發現多了一條前一次查詢時沒有的數據,仿佛幻覺一樣,這就是幻讀
三 不可重復讀和幻讀的區別
不可重復讀是指在同一查詢事務中多次進行,由於其他提交事務所做的修改和刪除,每次返回不同的結果集,此時發生不可重復讀
幻讀是指在同一查詢事務中多次進行,由於其他提交的事務所做的插入操作,每次返回不同的結果集,此時發生幻讀表面上看,區別就在於不可重復讀能看見其他事務提交的修改和刪除,而幻讀能看見其他事務提交的插入
四 spring 事務隔離級別
1.default:(默認)
默認隔離級別,使用數據庫默認的事務隔離級別
2.read_uncommitted:(讀未提交)
這是事務最低的隔離級別,他允許另外一個事務可以看到這個事務未提交的數據,這種隔離級別會產生臟讀,不可重復讀和幻讀
3.read_committed(讀已提交)
保證一個事務修改的數據提交后才能被另外一個事務讀取,另外一個事務不能讀取該事務未提交的數據.這種事務隔離級別可以避免臟讀,但是可能會出現不可重復讀和幻讀
4.repeatable_read(可重復讀)
這種事務級別可以防止臟讀,不可重復讀.但是可能出現幻讀.他除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了不可重復讀
5.Serializable 串行化
這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。防止了臟讀、不可重復讀、幻讀
總結:
臟讀 不可重復讀 幻讀
讀未提交 會 會 會
讀已提交 不會 會 會
可重復讀 不會 不會 會
串行化 不會 不會 不會
五 spring事務的傳播行為
1.requierd
如果有事務那么加入事務,沒有的話新建一個
2.not_supported
不開啟事務
3.requires_new
不管是否存在事務,都創建一個新的事務,原來的掛起,新的執行完,繼續執行老事務
4.mandatory
必須在一個已有的事務中執行,否則拋出異常
5.never
必須在一個沒有的事務中執行,否則拋出異常
6.supports
如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務那就不用事務
7.PROPAGATION_NESTED
如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則按REQUIRED屬性執行。
六 Spring聲明式事務的回滾機制
在Spring 的事務框架中推薦的事務回滾方法是,在當前執行的事務上下文中拋出一個異常。如果異常未被處理,當拋出異常調用堆棧的時候,Spring 的事務框架代碼將捕獲任何未處理的異常,然后並決定是否將此事務標記為回滾。
在默認配置中,Spring 的事務框架代碼只會將出現runtime, unchecked 異常的事務標記為回滾;也就是說事務中拋出的異常時RuntimeException或者是其子類,這樣事務才會回滾(默認情況下Error也會導致事務回滾)。在默認配置的情況下,所有的 checked 異常都不會引起事務回滾。如果有需要,可以通過rollback-for 和no-rollback-for進行指定。
七 分布式環境下如何處理事務
分布式事務處理是很難保證acid的。一般做法是犧牲一致性,滿足可用性和分區容錯。采用的方式可以是二階段提交,由於二階段提交存在着諸如同步阻塞、單點問題、數據不一致、宕機等缺陷,所以還可以采用TCC(補償事務)的方式實現,TCC核心思想是:針對每個操作,都要注冊一個與其對應的確認和補償(撤銷)操作。它分為三個階段,本質也是2階段提交,缺點也比較明顯的,在確認和補償時都有可能失敗,一些業務流程可能用TCC不太好定義及處理。分布式事務還可以基於 mq(消息隊列)/rpc(遠程方法調用)實現最終一致性。還有Mycat可以通過用戶會話Session中設置autocommit=false啟動事務,通過設置ServerConnection中變量txInterrupted=true來控制是否事務異常需要回滾。在Mycat中的事務是一種二階段提交事務方式,但是從實際應用場景出發這種出現故障的概率還是比較小的,因此這種實現方式可以滿足很多應用需求,但如果出現問題,會很麻煩。但在分庫分表,立即可見的應用上是不能滿足業務需求的,所以分布式事務需要根據具體業務的需要權衡取舍的。
分享文章:
微服務架構下處理分布式事務,你必須知道的事兒
根據微服務架構的鼻祖 Martin Fowler 的忠告,微服務架構中應當盡量避免分布式事務。然而,在某些領域,分布式事務如同宿命中的對手無法避免。
根據微服務架構的鼻祖 Martin Fowler 的忠告,微服務架構中應當盡量避免分布式事務。然而,在某些領域,分布式事務如同宿命中的對手無法避免。
在工程領域,分布式事務的討論主要聚焦於強一致性和最終一致性的解決方案。
典型方案包括:
- 兩階段提交(2PC, Two-phase Commit)方案。
- eBay 事件隊列方案。
- TCC 補償模式。
- 緩存數據最終一致性。
一致性理論
分布式事務的目的是保障分庫數據一致性,而跨庫事務會遇到各種不可控制的問題,如個別節點永久性宕機,像單機事務一樣的 ACID 是無法奢望的。
另外,業界著名的 CAP 理論也告訴我們,對分布式系統,需要將數據一致性和系統可用性、分區容忍性放在天平上一起考慮。
兩階段提交協議(簡稱2PC)是實現分布式事務較為經典的方案,但 2PC 的可擴展性很差,在分布式架構下應用代價較大,eBay 架構師 Dan Pritchett 提出了 BASE 理論,用於解決大規模分布式系統下的數據一致性問題。
BASE 理論告訴我們:可以通過放棄系統在每個時刻的強一致性來換取系統的可擴展性。
01.CAP 理論
在分布式系統中,一致性(Consistency)、可用性(Availability)和分區容忍性(Partition Tolerance)3 個要素最多只能同時滿足兩個,不可兼得。其中,分區容忍性又是不可或缺的。
- 一致性:分布式環境下,多個節點的數據是否強一致。
- 可用性:分布式服務能一直保證可用狀態。當用戶發出一個請求后,服務能在有限時間內返回結果。
- 分區容忍性:特指對網絡分區的容忍性。
舉例:Cassandra、Dynamo 等,默認優先選擇 AP,弱化 C;HBase、MongoDB 等,默認優先選擇 CP,弱化 A。
02.BASE 理論
核心思想:
- 基本可用(Basically Available):指分布式系統在出現故障時,允許損失部分的可用性來保證核心可用。
- 軟狀態(Soft State):指允許分布式系統存在中間狀態,該中間狀態不會影響到系統的整體可用性。
- 最終一致性(Eventual Consistency):指分布式系統中的所有副本數據經過一定時間后,最終能夠達到一致的狀態。
一致性模型
數據的一致性模型可以分成以下三類:
- 強一致性:數據更新成功后,任意時刻所有副本中的數據都是一致的,一般采用同步的方式實現。
- 弱一致性:數據更新成功后,系統不承諾立即可以讀到最新寫入的值,也不承諾具體多久之后可以讀到。
- 最終一致性:弱一致性的一種形式,數據更新成功后,系統不承諾立即可以返回最新寫入的值,但是保證最終會返回上一次更新操作的值。
分布式系統數據的強一致性、弱一致性和最終一致性可以通過 Quorum NRW 算法分析。
分布式事務解決方案
01.2PC 方案——強一致性
2PC 的核心原理是通過提交分階段和記日志的方式,記錄下事務提交所處的階段狀態,在組件宕機重啟后,可通過日志恢復事務提交的階段狀態,並在這個狀態節點重試。
如 Coordinator 重啟后,通過日志可以確定提交處於 Prepare 還是 Prepare All 狀態。若是前者,說明有節點可能沒有 Prepare 成功,或所有節點 Prepare 成功但還沒有下發 Commit,狀態恢復后給所有節點下發 RollBack。
若是 Prepare All 狀態,需要給所有節點下發 Commit,數據庫節點需要保證 Commit 冪等。
2PC 方案的三個問題:
- 同步阻塞。
- 數據不一致。
- 單點問題。
升級的 3PC 方案旨在解決這些問題,主要有兩個改進:
- 增加超時機制。
- 兩階段之間插入准備階段。
但三階段提交也存在一些缺陷,要徹底從協議層面避免數據不一致,可以采用 Paxos 或者 Raft 算法。
02.eBay 事件隊列方案——最終一致性
eBay 的架構師 Dan Pritchett,曾在一篇解釋 BASE 原理的論文《Base:An Acid Alternative》中提到一個 eBay 分布式系統一致性問題的解決方案。
它的核心思想是將需要分布式處理的任務通過消息或者日志的方式來異步執行,消息或日志可以存到本地文件、數據庫或消息隊列,再通過業務規則進行失敗重試,它要求各服務的接口是冪等的。
描述的場景為,有用戶表 user 和交易表 transaction,用戶表存儲用戶信息、總銷售額和總購買額。交易表存儲每一筆交易的流水號、買家信息、賣家信息和交易金額。如果產生了一筆交易,需要在交易表增加記錄,同時還要修改用戶表的金額。
論文中提出的解決方法是將更新交易表記錄和用戶表更新消息放在一個本地事務來完成,為了避免重復消費用戶表更新消息帶來的問題,增加一個操作記錄表 updates_applied 來記錄已經完成的交易相關的信息。
這個方案的核心在於第二階段的重試和冪等執行。失敗后重試,這是一種補償機制,它是能保證系統最終一致的關鍵流程。
03.TCC (Try-Confirm-Cancel)補償模式——最終一致性
某業務模型如圖,由服務 A、服務 B、服務 C、服務 D 共同組成的一個微服務架構系統。服務 A 需要依次調用服務 B、服務 C 和服務 D 共同完成一個操作。
當服務 A 調用服務 D 失敗時,若要保證整個系統數據的一致性,就要對服務 B 和服務 C 的 invoke 操作進行回滾,執行反向的 revert 操作。回滾成功后,整個微服務系統是數據一致的。
實現的三個關鍵要素:
- 服務調用鏈必須被記錄下來。
- 每個服務提供者都需要提供一組業務邏輯相反的操作,互為補償,同時回滾操作要保證冪等。
- 必須按失敗原因執行不同的回滾策略。
實現的兩個難點:
- 補償模式的特點是實現簡單,但是想形成一定程度的通用方案比較困難,特別是服務鏈的記錄,因為大部分時候,業務參數或者業務邏輯千差萬別。
- 很多業務特征使得該服務無法提供一個安全的回滾操作。
04.緩存數據最終一致性
在我們的業務系統中,緩存(Redis 或者 Memcached)通常被用在數據庫前面,作為數據讀取的緩沖,使得 I/O 操作不至於直接落在數據庫上。
以商品詳情頁為例,假如賣家修改了商品信息,並寫回到數據庫,但是這時候用戶從商品詳情頁看到的信息還是從緩存中拿到的過時數據,這就出現了緩存系統和數據庫系統中的數據不一致的現象。
要解決該場景下緩存和數據庫數據不一致的問題,我們有以下兩種解決方案:
- 為緩存數據設置過期時間。當緩存中數據過期后,業務系統會從數據庫中獲取數據,並將新值放入緩存。這個過期時間就是系統可以達到最終一致的容忍時間。
- 更新數據庫數據后,同時清除緩存數據。數據庫數據更新后,同步刪除緩存中數據,使得下次對商品詳情的獲取直接從數據庫中獲取,並同步到緩存。
選擇建議
在面臨數據一致性問題的時候,首先要從業務需求的角度出發,確定我們對於三種一致性模型的接受程度,再通過具體場景來決定解決方案。
從應用角度看,分布式事務的現實場景常常無法規避,在有能力給出其他解決方案前,2PC 也是一個不錯的選擇。
對購物轉賬等電商和金融業務,中間件層的 2PC 最大問題在於業務不可見,一旦出現不可抗力或意想不到的一致性破壞。
如數據節點永久性宕機,業務難以根據 2PC 的日志進行補償。金融場景下,數據一致性是命根,業務需要對數據有百分之百的掌控力。
建議使用 TCC 這類分布式事務模型,或基於消息隊列的柔性事務框架,這兩種方案都在業務層實現,業務開發者具有足夠掌控力,可以結合 SOA 框架來架構,包括 Dubbo、Spring Cloud 等。