TCC-Transaction 解析系列(1):dubbo-sample

分布式服务

分布式服务框架是大型互联网架构的基础组件之一,目标是能让各个业务服务化,并且在服务化框架的管理下能够实现基本的 RPC 功能,以及必要的服务发现、服务治理、熔断、限流等高级功能。Dubbo 是阿里开源的比较知名的分布式服务化框架。

服务化的好处显而易见,能让各个系统解耦,便于系统拆分,服务之间的调用能很好的被管理起来,无状态的服务可以部署多个实例,提升系统的处理能力。但是系统拆分过后,会有一个明显的问题要解决,即分布式事务的问题。比如一次请求需要对两个服务分别执行一次写操作,当一个服务的写操作失败后,另一个服务的已经持久化的写操作如何有效地进行回滚,是一个很关键的问题,回滚不到位的话,就会产生脏数据。

分布式事务的基本原理本质上都是两阶段提交协议(2PC),TCC (try-confirm-cancel)其实也是一种 2PC,只不过 TCC 规定了在服务层面实现的具体细节,即参与分布式事务的服务方和调用方至少要实现三个方法:try 方法、confirm 方法、cancel 方法。

服务调用方( Consumer )在 try 阶段调用提供方( Provider )的 try 方法,真整个 try 阶段一旦成功,接下来就相继调用各个服务参与者的 confirm 方法,而 try 阶段一旦失败,就立即相继调用各个服务参与者的 cancel 方法,保证整个事务的最终一致性。而一旦进入 confirm 或者 cancel 阶段,就会一直 confirm 或者 cancel 下去,系统应该提供恢复机制,即使在 confirm 阶段出错时,也能够保证立即或者定时 confirm,直到全部的服务 confirm 成功。

TCC-Transaction 是一种开源的 TCC 型事务的实现,源代码在 Github 可以找到,内部提供一个基于 dubbo 的例子。事实上,TCC-Transaction 并不依赖具体的 RPC 框架,用 dubbo 只是为演示例子的方便。

Dubbo-sample 整体流程

TCC-Transaction 的源码用 maven 管理,其中有一个 tcc-transaction-dubbo-sample 的子模块,跑 demo 之前需要提前执行在 src/main/dbscripts 中的数据库脚本。dubbo-sample 模拟的是一个经典的订单购物扣款的例子,其中包含的服务有:

  • order 服务:负责发起下单操作
  • capital 服务:管理用户的资金账户,对外提供资金扣款的操作
  • redpacket 服务 : 管理用户的红包账户,对外提供红包扣款的操作

整个流程是这样的:order 服务创建订单,然后调用 capital 服务请求扣除资金账户金额,再调用 redpacket 服务请求扣除红包账户余额,当资金账户和红包账户余额在 try 阶段都成功后,order 服务开始执行 confirm 方法把订单置为成功,同时调用 capital 和 redpakcet 服务把转账订单置为成功。

Zookeeper 与 Dubbo

dubbo 的启动需要一个注册中心,源码中的例子中使用 zookeeper 作为注册中心,所以在启动例子之前需要先下载并启动 zookeeper . zookeeper 可以在 Apache 官网下载下来,解压之后将 confg 下的 zoo_sample.cfg 重命名为 zoo.cfg 后(即使用默认配置),通过启动脚本 bin/zkServer.sh start 启动 zookeeper 即可。由于 zookeeper 默认监听 2181 端口,要保证此端口不被其他程序占用。

之后需要在 IDE 中配置三个Tomcat,分别启动 tcc-transaction-dubbo-capital、tcc-transaction-dubbo-redpacket、tcc-transaction-dubbo-order .

启动后可按提示模拟支付请求,比如如下界面,可输入具体金额然后执行相应的支付流程:

源码导读

在 order 的 controller 层接受页面上用户发起的下单和支付请求,发起 TCC 事务的代码为makePayment

paymentService.makePayment(order, redPacketPayAmount, order.getTotalAmount().subtract(redPacketPayAmount));

在 makePayment 方法内部是 TCC 的实现逻辑,包括 try、confirm、cancel 方法,并通过 @Compensable 注解的形式告诉 TCC-Transaction 框架如何找到这三个方法:

@Compensable(confirmMethod = "confirmMakePayment", cancelMethod = "cancelMakePayment")
@Transactional
public void makePayment(Order order, BigDecimal redPacketPayAmount, BigDecimal capitalPayAmount) {
    System.out.println("order try make payment called.time seq:" + DateFormatUtils.format(Calendar.getInstance(), "yyyy-MM-dd HH:mm:ss"));

    order.pay(redPacketPayAmount, capitalPayAmount);
    orderRepository.updateOrder(order);

    String result = capitalTradeOrderService.record(buildCapitalTradeOrderDto(order));
    String result2 = redPacketTradeOrderService.record(buildRedPacketTradeOrderDto(order));
}

同理,在 capital 和 redpacket 服务中出现 @Compensable 注解的地方同样实现了 try、confirm、cancel方法。通过断点调试的方法,可以观察出三个服务的执行顺序。

总结

通过 tcc-transaction 中的例子,可以初步体验 TCC 型事务的实现逻辑,作为使用方需要通过 tcc-transaction 提供的注解来标记相应的 try、confirm、cancel 方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 通过之前的几篇文章我相信您已经搭建好了运行环境,本次的项目实战是依照happylifeplat-tcc-demo项...
    dromara阅读 1,086评论 0 3
  • 本人最近学习了一下微服务下数据一致性的特点,总结了下目前的保障微服务下数据一致性的几种实现方式如下,以备后查。此篇...
    SawyerZhou阅读 31,910评论 11 66
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 林中有两条路 人们总是走着一条 怀念着另一条 但愿有无数个平行时空 容纳我们想象过的各种意外 如果有 我会昂首挺胸...
    水果猎人的彪悍生活阅读 180评论 0 3
  • 最难忘, 你一眼望过来时的脉脉含情…… 我便娇羞的低下头, 任凭火热的心情把双颊烫红! 最难忘, 你偷偷递过来的纸...
    梦艳儿阅读 168评论 0 3