分佈式事務處理方案

分佈式事務處理方案


1 背景

分佈式環境下,無法採用單機事務(JDBC事務,Spring管理事務),在多步驟操作時,由於無法回滾(Rollback),容易導致產生髒數據。

2 總體方案

目標: 基於互聯網行業成熟經驗,和BASE理論,分佈式事務目標是柔性事務和最終一致性。

基本策略:基於數據版本+事務隔離+異步兩階段提交+事務補償機制。

3 具體方案

3.1 事務字段:

在庫表結構設計上為每個業務表增加事務表,表結構一致,並增加幾個事務字段,如:txid 等。

數據格式: 基本字段, ...., txid, txtime,txstate, version

需要記錄事務序號,事務時間,事務狀態,

每條update語句需要對version進行自增:

create table if not exists tx_item like item; //創建主表對應的事務表,表結構一致 

alter table tx_item add txid int;
alter table tx_item add txid int;

update tx_item set ....... , txid=#{txid}, txtime=#{txtime}, txstate=#{txstate}, version = version + 1
where item_id = #{itemId}

其中, #{txid}, #{txtime}, txstate=#{txstate} 由應用程序傳入。

3.2 多步操作處理流程

1) 開啟事務,生成事務流水號和時間戳,

tx = new Dtransaction();
txid = tx.getTxid(); //流水號,可以用 txtime + 6位隨機號代替
txtime = tx.getTxtime(); //當前時間,精確到納秒

2) 執行操作1

變更數據時帶上 tx信息。例如: 更新賬戶餘額表 Balance , 減掉商品總價, 增加 修改日誌

create table if not exists tx_balance like balance; //創建主表對應的事務表,表結構一致

update balance set balance = balance - #{totalPrice} , txid=#{txid}, txtime=#{txtime}, txstate=#{txstate}, version = version + 1
where member_id = #{member_id} and balance - #{totalPrice} > 0

3) 執行操作2

變更數據時帶上 tx信息。例如: 更新產品 item, 減少庫存

create table if not exists tx_item like item; //創建主表對應的事務表,表結構一致
update item set stock = stock - #{quantity} , txid=#{txid}, txtime=#{txtime}, txstate=#{txstate}, version = version + 1
where item_id = #{itemId}

4.1) 假如 操作2也執行成功,則提交事務

tx.commit();

後臺操作是, 在數據庫事務表中,增加一條事務記錄,

insert into txlog(...) values(txid, txtime, txstate,version)

其中 txstate = 1 , 表示事務已提交, 待最終處理

4.2) 假如 操作2失敗, 則回滾事務

tx.rollback();

後臺操作是, 在數據庫事務表中,增加一條事務記錄,

insert into txlog(...) values(txid, txtime, txstate,version)

其中 txstate = -1, 表示事務失敗

5) 同時,事務協調任務根據事務表信息處理未提交事務數據 ( 通過線程方式,或MQ方式 )

獲取 txstate = 1 狀態為“已提交” 的事務

將txstate 改為 2. 事務狀態為完成, 並將事務記錄拷貝到主表

update item inner join tx_item on item.item_id = tx_item.item_id
set xxx = xxx

where txid = #{txid}

6) 失敗事務處理任務定期清理失敗事務( 例如:timeout = 30分鐘一次)

刪除 txstate = -1, txtime 超過 30分鐘的事務記錄。

delete from tx_item where currenttime - txtime > 30分鐘

3.3 事務隔離處理

事務隔離包括兩個場景含義:

一指當前事務的中間修改狀態(即未提交狀態)不應該被其他正在進行的事務訪問到(包括:查詢,修改,刪除)

二指當前事務中的查詢,修改,刪除不應該訪問到其他事務未提交的中間數據。

3.3.1 對他隔離

對他隔離主要防範事務隔離四個基本特性中的髒讀,讀未提交

對他隔離採用基本的 查詢邏輯就可以滿足需求。 因為其他事務訪問的是主表數據,而事務表的中間數據並未提交合併到主表。

3.3.1 對己隔離

二指當前事務中的查詢,修改,刪除不應該訪問到其他事務未提交的中間數據。

對己主要滿足事務四個基本特性的可重複讀。 可重複讀要求,在自己的事務中的中途修改能夠在事務提交前的讀取中反映出來 。

例如: 一次事務中, 未完成訂單為10條, 然後將其中2條修改為已完成, 則接下來的查詢未完成訂單應該是8條。

可重複讀的查詢主要是:

主表query結果 union 事務表查詢結果 where txid = #{txid}

其中 #{txid} 為當前事務id

3.3.3 防範幻讀

防幻讀指,在一個事務中,前後兩次查詢的數據結果是一致的, 其他事務刪除或增加的數據即便符合當前事務的數據查詢範圍,也不影響當前事務的第二次查詢結果。

策略。其他事務的新增數據先保存到 事務表 就可以實現 防幻讀。

其他事務的刪除數據以日誌形式先保存到事務表,從而防範幻讀。


分享到:


相關文章: