成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用 Python 輕松完成一個 Saga 分布式事務

開發 前端 分布式
在這篇文章里,我們介紹了 SAGA 的理論知識,也通過一個例子,完整給出了編寫一個 SAGA 事務的過程,涵蓋了正常成功完成,異常情況,以及成功回滾的情況。

 [[422283]]

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

分布式事務

分布式事務在分布式環境下,為了滿足可用性、性能與降級服務的需要,降低一致性與隔離性的要求,一方面遵循 BASE 理論:

  • 基本業務可用性( Basic Availability )

  • 柔性狀態( Soft state )

  • 最終一致性( Eventual consistency )

另一方面,分布式事務也部分遵循 ACID 規范:

  • 原子性:嚴格遵循

  • 一致性:事務完成后的一致性嚴格遵循;事務中的一致性可適當放寬

  • 隔離性:并行事務間不可影響;事務中間結果可見性允許安全放寬

  • 持久性:嚴格遵循

SAGA

Saga 是這一篇數據庫論文SAGAS提到的一個分布式事務方案。其核心思想是將長事務拆分為多個本地短事務,由 Saga 事務協調器協調,如果各個本地事務成功完成那就正常完成,如果某個步驟失敗,則根據相反順序一次調用補償操作。

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

DTM 事務框架里,有 3 個角色,與經典的 XA 分布式事務一樣:

  • AP/應用程序,發起全局事務,定義全局事務包含哪些事務分支

  • RM/資源管理器,負責分支事務各項資源的管理

  • TM/事務管理器,負責協調全局事務的正確執行,包括 SAGA 正向 /逆向操作的執行

下面看一個成功完成的 SAGA 時序圖,就很容易理解 SAGA 分布式事務:

SAGA 實踐

對于我們要進行的銀行轉賬的例子,我們將在正向操作中,進行轉入轉出,在補償操作中,做相反的調整。

首先我們創建賬戶余額表:

  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. ); 

我們先編寫核心業務代碼,調整用戶的賬戶余額

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

下面我們來編寫具體的正向操作 /補償操作的處理函數

  1. @app.post("/api/TransOutSaga"
  2. def trans_out_saga(): 
  3.   saga_adjust_balance(c, out_uid, -30
  4.   return {"dtm_result""SUCCESS"
  5.  
  6. @app.post("/api/TransOutCompensate"
  7. def trans_out_compensate(): 
  8.   saga_adjust_balance(c, out_uid, 30
  9.   return {"dtm_result""SUCCESS"
  10.  
  11. @app.post("/api/TransInSaga"
  12. def trans_in_saga(): 
  13.   saga_adjust_balance(c, in_uid, 30
  14.   return {"dtm_result""SUCCESS"
  15.  
  16. @app.post("/api/TransInCompensate"
  17. def trans_in_compensate(): 
  18.   saga_adjust_balance(c, in_uid, -30
  19.   return {"dtm_result""SUCCESS"

到此各個子事務的處理函數已經 OK 了,然后是開啟 SAGA 事務,進行分支調用

  1. # 這是 dtm 服務地址 
  2. dtm = "http://localhost:8080/api/dtmsvr" 
  3. # 這是業務微服務地址 
  4. svc = "http://localhost:5000/api" 
  5.  
  6.     req = {"amount"30
  7.     s = saga.Saga(dtm, utils.gen_gid(dtm)) 
  8.     s.add(req, svc + "/TransOutSaga", svc + "/TransOutCompensate"
  9.     s.add(req, svc + "/TransInSaga", svc + "/TransInCompensate"
  10.     s.submit() 

至此,一個完整的 SAGA 分布式事務編寫完成。

如果您想要完整運行一個成功的示例,那么參考這個例子yedf/dtmcli-py-sample,將它運行起來非常簡單

  1. # 部署啟動 dtm 
  2. # 需要 docker 版本 18 以上 
  3. git clone https://github.com/yedf/dtm 
  4. cd dtm 
  5. docker-compose up 
  6.  
  7. # 另起一個命令行 
  8. git clone https://github.com/yedf/dtmcli-py-sample 
  9. cd dtmcli-py-sample 
  10. pip3 install flask dtmcli requests 
  11. flask run 
  12.  
  13. # 另起一個命令行 
  14. curl localhost:5000/api/fireSaga 

處理網絡異常

假設提交給 dtm 的事務中,調用轉入操作時,出現短暫的故障怎么辦?按照 SAGA 事務的協議,dtm 會重試未完成的操作,這時我們要如何處理?故障有可能是轉入操作完成后出網絡故障,也有可能是轉入操作完成中出現機器宕機。如何處理才能夠保障賬戶余額的調整是正確無問題的?

這類網絡異常的妥當處理,是分布式事務中的大難題,異常情況包括三類:重復請求、空補償、懸掛,都需要正確處理

DTM 提供了子事務屏障功能,保證上述異常情況下的業務邏輯,只會有一次正確順序下的成功提交。(子事務屏障詳情參考分布式事務最經典的七種解決方案的子事務屏障環節)

我們把處理函數調整為:

  1. @app.post("/api/TransOutSaga"
  2. def trans_out_saga(): 
  3.   with barrier.AutoCursor(conn_new()) as cursor: 
  4.     def busi_callback(c): 
  5.       saga_adjust_balance(c, out_uid, -30
  6.     barrier_from_req(request).call(cursor, busi_callback) 
  7.   return {"dtm_result""SUCCESS"

這里的 barrier_from_req(request).call(cursor, busi_callback)調用會使用子事務屏障技術,保證 busi_callback 回調函數僅被提交一次

您可以嘗試多次調用這個 TransIn 服務,僅有一次余額調整。

處理回滾

假如銀行將金額準備轉入用戶 2 時,發現用戶 2 的賬戶異常,返回失敗,會怎么樣?我們調整處理函數,讓轉入操作返回失敗

  1. @app.post("/api/TransInSaga"
  2. def trans_in_saga(): 
  3.   return {"dtm_result""FAILURE"

我們給出事務失敗交互的時序圖:

這里有一點,TransIn 的正向操作什么都沒有做,就返回了失敗,此時調用 TransIn 的補償操作,會不會導致反向調整出錯了呢?

不用擔心,前面的子事務屏障技術,能夠保證 TransIn 的錯誤如果發生在提交之前,則補償為空操作;TransIn 的錯誤如果發生在提交之后,則補償操作會將數據提交一次。

您可以將返回錯誤的 TransIn 改成:

  1. @app.post("/api/TransInSaga"
  2. def trans_in_saga(): 
  3.   with barrier.AutoCursor(conn_new()) as cursor: 
  4.     def busi_callback(c): 
  5.       saga_adjust_balance(c, in_uid, 30
  6.     barrier_from_req(request).call(cursor, busi_callback) 
  7.   return {"dtm_result""FAILURE"

最后的結果余額依舊會是對的,原理可以參考:分布式事務最經典的七種解決方案的子事務屏障環節

小結

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

文中使用的 dtm 是新開源的 Golang 分布式事務管理框架,功能強大,支持 TCC 、SAGA 、XA 、事務消息等事務模式,支持 Go 、python 、PHP 、node 、csharp 等語言的。同時提供了非常簡單易用的接口。

閱讀完此篇干貨,歡迎大家訪問項目https://github.com/yedf/dtm,給顆星星支持!

 

責任編輯:張燕妮 來源: 別枝驚鵲
相關推薦

2021-10-25 10:33:29

Python 開發編程語言

2021-09-14 13:55:15

Go開發分布式

2021-10-11 09:24:14

分布式架構系統

2022-06-27 08:36:27

分布式事務XA規范

2019-12-27 16:00:56

分布式事務框架Java

2021-03-18 09:18:39

分布式事務Saga

2022-06-27 08:21:05

Seata分布式事務微服務

2022-06-21 08:27:22

Seata分布式事務

2017-07-26 15:08:05

大數據分布式事務

2022-09-29 08:28:57

SpringRedis分布式

2022-09-22 13:28:34

Redis分布式鎖

2020-07-30 09:35:09

Redis分布式鎖數據庫

2019-10-10 09:16:34

Zookeeper架構分布式

2009-06-19 15:28:31

JDBC分布式事務

2024-06-07 08:06:36

2009-09-18 15:10:13

分布式事務LINQ TO SQL

2021-09-29 09:07:37

分布式架構系統

2023-11-01 18:02:33

RayPython分布式

2024-02-19 00:00:00

Redis分布式

2021-12-09 10:45:19

分布式事務框架
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品免费视频一区二区 | 亚洲午夜av久久乱码 | 欧美一区二区大片 | 国产97视频在线观看 | 欧美黄色绿像 | 精品中文字幕一区二区三区 | 久久精品日产第一区二区三区 | 在线观看成人小视频 | 国产精品中文字幕一区二区三区 | 精品国产31久久久久久 | 久久专区 | 欧美日韩精品在线免费观看 | 天天操夜夜操 | 亚洲一区在线日韩在线深爱 | 中文在线一区二区 | 一区二区三区不卡视频 | 欧美黄色一区 | 国产我和子的乱视频网站 | 视频一区在线 | 国产特级毛片 | 视频一区 国产精品 | 亚洲精品一区av在线播放 | 日本精品视频一区二区 | 色99视频 | 福利成人 | 精品国产网| 日日摸日日碰夜夜爽2015电影 | 四虎影院免费在线播放 | 丝袜天堂 | 国产婷婷色一区二区三区 | 一级黄色淫片 | 成年人国产在线观看 | 欧美一区二区三区 | 成人在线视频一区二区三区 | 四虎最新地址 | 欧美在线观看免费观看视频 | 91精品国产一区二区三区 | 婷婷精品 | 国产探花在线精品一区二区 | 中文字幕视频三区 | 国产高清视频在线观看 |