千家信息网

怎么用python完成一个分布式事务TCC

发表于:2025-02-24 作者:千家信息网编辑
千家信息网最后更新 2025年02月24日,这篇文章主要讲解了"怎么用python完成一个分布式事务TCC",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"怎么用python完成一个分布式事务TCC
千家信息网最后更新 2025年02月24日怎么用python完成一个分布式事务TCC

这篇文章主要讲解了"怎么用python完成一个分布式事务TCC",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"怎么用python完成一个分布式事务TCC"吧!

1、TCC组成

TCC分为3个阶段

  • Try 阶段:尝试执行,完成所有业务检查(一致性), 预留必须业务资源(准隔离性)

  • Confirm 阶段:如果所有分支的Try都成功了,则走到Confirm阶段。Confirm真正执行业务,不作任何业务检查,只使用 Try 阶段预留的业务资源

  • Cancel 阶段:如果所有分支的Try有一个失败了,则走到Cancel阶段。Cancel释放 Try 阶段预留的业务资源。

TCC分布式事务里,有3个角色,与经典的XA分布式事务一样:

  • AP/应用程序,发起全局事务,定义全局事务包含哪些事务分支

  • RM/资源管理器,负责分支事务各项资源的管理

  • TM/事务管理器,负责协调全局事务的正确执行,包括ConfirmCancel的执行,并处理网络异常

如果我们要进行一个类似于银行跨行转账的业务,转出(TransOut)和转入(TransIn)分别在不同的微服务里,

一个成功完成的TCC事务典型的时序图如下:

2、TCC实践

对于前面的跨行转账操作,最简单的做法是,在Try阶段调整余额,在Cancel阶段反向调整余额,Confirm阶段则空操作。这么做带来的问题是,如果A扣款成功,金额转入B失败,最后回滚,把A的余额调整为初始值。在这个过程中如果A发现自己的余额被扣减了,但是收款方B迟迟没有收到余额,那么会对A造成困扰。

更好的做法是,Try阶段冻结A转账的金额,Confirm进行实际的扣款,Cancel进行资金解冻,这样用户在任何一个阶段,看到的数据都是清晰明了的。

下面我们进行一个TCC事务的具体开发

目前可用于TCC的开源框架,主要为Java语言,其中以seata为代表。我们的例子采用Python语言,使用的分布式事务框架为 https://github.com/yedf/dtm ,它对分布式事务的支持非常优雅。下面来详细讲解TCC的组成

我们首先创建两张表,一张是用户余额表,一张是冻结资金表,建表语句如下:

CREATE TABLE dtm_busi.`user_account` (  `id` int(11) AUTO_INCREMENT PRIMARY KEY,  `user_id` int(11) not NULL UNIQUE ,  `balance` decimal(10,2) NOT NULL DEFAULT '0.00',  `create_time` datetime DEFAULT now(),  `update_time` datetime DEFAULT now());CREATE TABLE dtm_busi.`user_account_trading` (  `id` int(11) AUTO_INCREMENT PRIMARY KEY,  `user_id` int(11) not NULL UNIQUE ,  `trading_balance` decimal(10,2) NOT NULL DEFAULT '0.00',  `create_time` datetime DEFAULT now(),  `update_time` datetime DEFAULT now());

trading表中,trading_balance记录正在交易的金额。

我们先编写核心代码,冻结/解冻资金操作,会检查约束balance+trading_balance >= 0,如果约束不成立,执行失败

def tcc_adjust_trading(cursor, uid, amount):  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))  if affected == 0:    raise Exception("update error, maybe balance not enough")

然后是调整余额

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

下面我们来编写具体的Try/Confirm/Cancel的处理函数

@app.post("/api/TransOutTry")def trans_out_try():  # 事务以及异常处理  tcc_adjust_trading(c, out_uid, -30)  return {"dtm_result": "SUCCESS"}@app.post("/api/TransOutConfirm")def trans_out_confirm():  # 事务以及异常处理  tcc_adjust_balance(c, out_uid, -30)  return {"dtm_result": "SUCCESS"}@app.post("/api/TransOutCancel")def trans_out_cancel():  # 事务以及异常处理  tcc_adjust_trading(c, out_uid, 30)  return {"dtm_result": "SUCCESS"}@app.post("/api/TransInTry")def trans_in_try():  # 事务以及异常处理  tcc_adjust_trading(c, in_uid, 30)  return {"dtm_result": "SUCCESS"}@app.post("/api/TransInConfirm")def trans_in_confirm():  # 事务以及异常处理  tcc_adjust_balance(c, in_uid, 30)  return {"dtm_result": "SUCCESS"}@app.post("/api/TransInCancel")def trans_in_cancel():  # 事务以及异常处理  tcc_adjust_trading(c, in_uid, -30)  return {"dtm_result": "SUCCESS"}

到此各个子事务的处理函数已经OK了,然后是开启TCC事务,进行分支调用

@app.get("/api/fireTcc")def fire_tcc():    # 发起tcc事务    gid = tcc.tcc_global_transaction(dtm, utils.gen_gid(dtm), tcc_trans)    return {"gid": gid}# tcc事务的具体处理def tcc_trans(t):    req = {"amount": 30} # 业务请求的负荷    # 调用转出服务的Try|Confirm|Cancel    t.call_branch(req, svc + "/TransOutTry", svc + "/TransOutConfirm", svc + "/TransOutCancel")    # 调用转入服务的Try|Confirm|Cancel    t.call_branch(req, svc + "/TransInTry", svc + "/TransInConfirm", svc + "/TransInCancel")

至此,一个完整的TCC分布式事务编写完成。

如果您想要完整运行一个成功的示例,那么按照dtmcli-py-sample项目的说明tcc的例子即可

3、TCC的回滚

假如银行将金额准备转入用户2时,发现用户2的账户异常,返回失败,会怎么样?我们修改代码,模拟这种情况:

@app.post("/api/TransInTry")def trans_in_try():  # 事务以及异常处理  tcc_adjust_trading(c, in_uid, 30)  return {"dtm_result": "FAILURE"}

这是事务失败交互的时序图:

这个跟成功的TCC差别就在于,当某个子事务返回失败后,后续就回滚全局事务,调用各个子事务的Cancel操作,保证全局事务全部回滚。

4、TCC网络异常

TCC在整个全局事务的过程中,可能发生各类网络异常情况,典型的是空回滚、幂等、悬挂,由于TCC的异常情况,和SAGA、可靠消息等事务模式有相近的地方,因此我们把所有异常的解决方案统统放在这篇文章 分布式事务最经典的七种解决方案 的异常处理章节进行讲解

感谢各位的阅读,以上就是"怎么用python完成一个分布式事务TCC"的内容了,经过本文的学习后,相信大家对怎么用python完成一个分布式事务TCC这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

事务 阶段 处理 分布式 业务 余额 全局 成功 分支 资源 情况 用户 金额 调整 个子 网络 资金 学习 服务 检查 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 低分女生可以学计算机网络技术 服务器管理员工 公安警务技术网络安全管理考什么 甘肃软件开发人月单价 素质数据库是什么意思 靠谱软件开发技术 数控机床软件开发上市公司 网络安全防范难度升级 论文网络安全与信息化战略 我的世界服务器挖方块榜指令 互联网黑科技是干什么的 dtu服务器转发 棋牌服务器租用价格 工程决算软件开发 社区数据库 a11芯片有神经网络技术吗 软件开发转型项目管理 魔兽世界二区哪个服务器是均衡服 武汉诚毅软件开发有限公司 专科学计算机网络技术怎样 软件开发和测试环境维护记录单 丰润区网络安全宣传 纯软件开发的预算报价 新手三国志战略版选择服务器 怎么租独立服务器 电力网络安全分级 学习网络安全工程师有前途吗 女孩在警校学网络安全还是刑技好 数据库如何查看两张表关联 软件开发部KPI制作模板
0