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

发布时间:2021-10-25 10:11:41 作者:iii
来源:亿速云 阅读:100

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

1、TCC组成

TCC分为3个阶段

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

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

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

怎么用python完成一个分布式事务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"}

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

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

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

4、TCC网络异常

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

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

推荐阅读:
  1. 怎么用Python完成股票回测框架
  2. 分布式事务之深入理解什么是2PC、3PC及TCC协议?

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

python

上一篇:如何使用send-mailmessage命令发送域内邮件

下一篇:Python爬虫经常会被封的原因是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》