自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用Python輕松完成一個分布式事務(wù)TCC,保姆級教程

開發(fā) 前端 分布式
分布式事務(wù)就是指事務(wù)的發(fā)起者、資源及資源管理器和事務(wù)協(xié)調(diào)者分別位于分布式系統(tǒng)的不同節(jié)點之上。

 

什么是分布式事務(wù)?銀行跨行轉(zhuǎn)賬業(yè)務(wù)是一個典型分布式事務(wù)場景,假設(shè)A需要跨行轉(zhuǎn)賬給B,那么就涉及兩個銀行的數(shù)據(jù),無法通過一個數(shù)據(jù)庫的本地事務(wù)保證轉(zhuǎn)賬的ACID,只能夠通過分布式事務(wù)來解決。

分布式事務(wù)就是指事務(wù)的發(fā)起者、資源及資源管理器和事務(wù)協(xié)調(diào)者分別位于分布式系統(tǒng)的不同節(jié)點之上。在上述轉(zhuǎn)賬的業(yè)務(wù)中,用戶A-100操作和用戶B+100操作不是位于同一個節(jié)點上。本質(zhì)上來說,分布式事務(wù)就是為了保證在分布式場景下,數(shù)據(jù)操作的正確執(zhí)行。

什么是TCC分布式事務(wù),TCC是Try、Confirm、Cancel三個詞語的縮寫,最早是由 Pat Helland 于 2007 年發(fā)表的一篇名為《Life beyond Distributed Transactions:an Apostate’s Opinion》的論文提出。

TCC組成

TCC分為3個階段

  • Try 階段:嘗試執(zhí)行,完成所有業(yè)務(wù)檢查(一致性), 預(yù)留必須業(yè)務(wù)資源(準(zhǔn)隔離性)
  • Confirm 階段:如果所有分支的Try都成功了,則走到Confirm階段。Confirm真正執(zhí)行業(yè)務(wù),不作任何業(yè)務(wù)檢查,只使用 Try 階段預(yù)留的業(yè)務(wù)資源
  • Cancel 階段:如果所有分支的Try有一個失敗了,則走到Cancel階段。Cancel釋放 Try 階段預(yù)留的業(yè)務(wù)資源。

TCC分布式事務(wù)里,有3個角色,與經(jīng)典的XA分布式事務(wù)一樣:

  • AP/應(yīng)用程序,發(fā)起全局事務(wù),定義全局事務(wù)包含哪些事務(wù)分支
  • RM/資源管理器,負(fù)責(zé)分支事務(wù)各項資源的管理
  • TM/事務(wù)管理器,負(fù)責(zé)協(xié)調(diào)全局事務(wù)的正確執(zhí)行,包括Confirm,Cancel的執(zhí)行,并處理網(wǎng)絡(luò)異常

如果我們要進(jìn)行一個類似于銀行跨行轉(zhuǎn)賬的業(yè)務(wù),轉(zhuǎn)出(TransOut)和轉(zhuǎn)入(TransIn)分別在不同的微服務(wù)里,一個成功完成的TCC事務(wù)典型的時序圖如下:

TCC實踐

對于前面的跨行轉(zhuǎn)賬操作,最簡單的做法是,在Try階段調(diào)整余額,在Cancel階段反向調(diào)整余額,Confirm階段則空操作。這么做帶來的問題是,如果A扣款成功,金額轉(zhuǎn)入B失敗,最后回滾,把A的余額調(diào)整為初始值。在這個過程中如果A發(fā)現(xiàn)自己的余額被扣減了,但是收款方B遲遲沒有收到余額,那么會對A造成困擾。

更好的做法是,Try階段凍結(jié)A轉(zhuǎn)賬的金額,Confirm進(jìn)行實際的扣款,Cancel進(jìn)行資金解凍,這樣用戶在任何一個階段,看到的數(shù)據(jù)都是清晰明了的。

下面我們進(jìn)行一個TCC事務(wù)的具體開發(fā)

目前可用于TCC的開源框架,主要為Java語言,其中以seata為代表。我們的例子采用Python語言,使用的分布式事務(wù)框架為https://github.com/yedf/dtm,它對分布式事務(wù)的支持非常優(yōu)雅。下面來詳細(xì)講解TCC的組成

我們首先創(chuàng)建兩張表,一張是用戶余額表,一張是凍結(jié)資金表,建表語句如下:

  1. CREATE TABLE dtm_busi.`user_account` ( 
  2.   `id` int(11) AUTO_INCREMENT PRIMARY KEY, 
  3.   `user_id` int(11) not NULL UNIQUE , 
  4.   `balance` decimal(10,2) NOT NULL DEFAULT '0.00'
  5.   `create_time` datetime DEFAULT now(), 
  6.   `update_time` datetime DEFAULT now() 
  7. ); 
  8.  
  9. CREATE TABLE dtm_busi.`user_account_trading` ( 
  10.   `id` int(11) AUTO_INCREMENT PRIMARY KEY, 
  11.   `user_id` int(11) not NULL UNIQUE , 
  12.   `trading_balance` decimal(10,2) NOT NULL DEFAULT '0.00'
  13.   `create_time` datetime DEFAULT now(), 
  14.   `update_time` datetime DEFAULT now() 
  15. ); 

trading表中,trading_balance記錄正在交易的金額。

我們先編寫核心代碼,凍結(jié)/解凍資金操作,會檢查約束balance+trading_balance >= 0,如果約束不成立,執(zhí)行失敗

  1. def tcc_adjust_trading(cursor, uid, amount): 
  2.   affected = utils.sqlexec(cursor, "update dtm_busi.user_account_trading set trading_balance=trading_balance + %d where user_id=%d and trading_balance + %d + (select balance from dtm_busi.user_account where id=%d) >= 0" % (amount, uid, amount, uid)) 
  3.   if affected == 0
  4.     raise Exception("update error, maybe balance not enough"

然后是調(diào)整余額

  1. def tcc_adjust_balance(cursor, uid, amount): 
  2.   utils.sqlexec(cursor, "update dtm_busi.user_account_trading set trading_balance = trading_balance+ %d where user_id=%d" %( -amount, uid)) 
  3.   utils.sqlexec(cursor, "update dtm_busi.user_account set balance=balance+%d where user_id=%d" %(amount, uid)) 

下面我們來編寫具體的Try/Confirm/Cancel的處理函數(shù)

  1. @app.post("/api/TransOutTry"
  2. def trans_out_try(): 
  3.   # 事務(wù)以及異常處理 
  4.   tcc_adjust_trading(c, out_uid, -30
  5.   return {"dtm_result""SUCCESS"
  6.  
  7. @app.post("/api/TransOutConfirm"
  8. def trans_out_confirm(): 
  9.   # 事務(wù)以及異常處理 
  10.   tcc_adjust_balance(c, out_uid, -30
  11.   return {"dtm_result""SUCCESS"
  12.  
  13. @app.post("/api/TransOutCancel"
  14. def trans_out_cancel(): 
  15.   # 事務(wù)以及異常處理 
  16.   tcc_adjust_trading(c, out_uid, 30
  17.   return {"dtm_result""SUCCESS"
  18.  
  19. @app.post("/api/TransInTry"
  20. def trans_in_try(): 
  21.   # 事務(wù)以及異常處理 
  22.   tcc_adjust_trading(c, in_uid, 30
  23.   return {"dtm_result""SUCCESS"
  24.  
  25. @app.post("/api/TransInConfirm"
  26. def trans_in_confirm(): 
  27.   # 事務(wù)以及異常處理 
  28.   tcc_adjust_balance(c, in_uid, 30
  29.   return {"dtm_result""SUCCESS"
  30.  
  31. @app.post("/api/TransInCancel"
  32. def trans_in_cancel(): 
  33.   # 事務(wù)以及異常處理 
  34.   tcc_adjust_trading(c, in_uid, -30
  35.   return {"dtm_result""SUCCESS"

到此各個子事務(wù)的處理函數(shù)已經(jīng)OK了,然后是開啟TCC事務(wù),進(jìn)行分支調(diào)用

  1. @app.get("/api/fireTcc"
  2. def fire_tcc(): 
  3.     # 發(fā)起tcc事務(wù) 
  4.     gid = tcc.tcc_global_transaction(dtm, utils.gen_gid(dtm), tcc_trans) 
  5.     return {"gid": gid} 
  6.  
  7. # tcc事務(wù)的具體處理 
  8. def tcc_trans(t): 
  9.     req = {"amount"30} # 業(yè)務(wù)請求的負(fù)荷 
  10.     # 調(diào)用轉(zhuǎn)出服務(wù)的Try|Confirm|Cancel 
  11.     t.call_branch(req, svc + "/TransOutTry", svc + "/TransOutConfirm", svc + "/TransOutCancel"
  12.     # 調(diào)用轉(zhuǎn)入服務(wù)的Try|Confirm|Cancel 
  13.     t.call_branch(req, svc + "/TransInTry", svc + "/TransInConfirm", svc + "/TransInCancel"

至此,一個完整的TCC分布式事務(wù)編寫完成。

如果您想要完整運行一個成功的示例,那么按照dtmcli-py-sample項目的說明tcc的例子即可

TCC的回滾

假如銀行將金額準(zhǔn)備轉(zhuǎn)入用戶2時,發(fā)現(xiàn)用戶2的賬戶異常,返回失敗,會怎么樣?我們修改代碼,模擬這種情況:

  1. @app.post("/api/TransInTry"
  2. def trans_in_try(): 
  3.   # 事務(wù)以及異常處理 
  4.   tcc_adjust_trading(c, in_uid, 30
  5.   return {"dtm_result""FAILURE"

這是事務(wù)失敗交互的時序圖

這個跟成功的TCC差別就在于,當(dāng)某個子事務(wù)返回失敗后,后續(xù)就回滾全局事務(wù),調(diào)用各個子事務(wù)的Cancel操作,保證全局事務(wù)全部回滾。

TCC網(wǎng)絡(luò)異常

TCC在整個全局事務(wù)的過程中,可能發(fā)生各類網(wǎng)絡(luò)異常情況,典型的是空回滾、冪等、懸掛,由于TCC的異常情況,和SAGA、可靠消息等事務(wù)模式有相近的地方,因此我們把所有異常的解決方案統(tǒng)統(tǒng)放在這篇文章分布式事務(wù)最經(jīng)典的七種解決方案的異常處理章節(jié)進(jìn)行講解

小結(jié)

在這篇文章里,我們介紹了TCC的理論知識,也通過一個例子,完整給出了編寫一個TCC事務(wù)的過程,涵蓋了正常成功完成,以及成功回滾的情況。相信讀者通過這邊文章,對TCC已經(jīng)有了深入的理解。

責(zé)任編輯:張燕妮 來源: Go語言中文網(wǎng)
相關(guān)推薦

2021-10-11 09:24:14

分布式架構(gòu)系統(tǒng)

2021-09-14 13:55:15

Go開發(fā)分布式

2021-09-07 09:26:13

Python 開發(fā)編程語言

2024-06-04 10:58:30

2024-06-12 09:06:48

2022-06-27 08:36:27

分布式事務(wù)XA規(guī)范

2021-06-08 12:46:27

分布式阿里TCC

2024-10-09 14:14:07

2022-07-20 06:55:10

TCC分布式事務(wù)微服務(wù)

2019-12-27 16:00:56

分布式事務(wù)框架Java

2024-06-28 09:07:19

2024-12-09 09:35:00

2022-06-27 08:21:05

Seata分布式事務(wù)微服務(wù)

2018-11-23 09:25:00

TCC分布式事務(wù)

2022-01-12 10:02:02

TCC模式 Seata

2022-09-29 08:28:57

SpringRedis分布式

2022-09-22 13:28:34

Redis分布式鎖

2022-06-21 08:27:22

Seata分布式事務(wù)

2017-07-26 15:08:05

大數(shù)據(jù)分布式事務(wù)

2020-07-30 09:35:09

Redis分布式鎖數(shù)據(jù)庫
點贊
收藏

51CTO技術(shù)棧公眾號