柔性事务解决方案之TCC

675d8747bee7b39a6823b30b4ce76d4e.jpg

前言

在开始之前先聊一聊什么是微服务,顾名思义,微服务得从两个方面去理解,什么是"微"、什么是"服务", 微 狭义来讲就是体积小、著名的"2 pizza 团队"很好的诠释了这一解释(2 pizza 团队最早是亚马逊 CEO Bezos提出来的,意思是说单个服务的设计,所有参与人从设计、开发、测试、运维所有人加起来 只需要2个披萨就够了 )。 而所谓服务,一定要区别于系统,服务一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集。

场景

这里就不啰嗦哪些东西了,百度一大堆,咱们用代码看问题~ ~。

public function completeOrder() {
orderDao::update(); // 订单服务本地更新订单状态
accountService::update(); // 调用资金账户服务给资金帐户加款
pointService::update(); // 调用积分服务给积分帐户增加积分
}

在传统的单体架构的业务中可以使Mysql事务来保持数据的一致性,如果跨系统、跨服务、跨数据库,应该如何保持数据一致性呢?

概念引入

在了解分布式事务之前要先了解这两个概念:BASE理论及CAP定理。

BASE理论

BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写,BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

  • BA: Basic Availability 基本业务可用性(支持分区失败)
  • S: Soft state 柔性状态(状态允许有短时间不同步,异步)
  • E: Eventual consistency 最终一致性(最终数据是一致的,但不是实时一致)
CAP定理

对于共享数据系统,最多只能同时拥有CAP其中的两个,没法三者兼顾,任两者的组合都有其适用场景,真实系统应当是ACID与BASE的混合体,不同类型的业务可以也应当区别对待
image.png

柔性事务解决方案之TCC

进入主题,介绍下分布式事务TCC的技术方案,先上一张图。
image.png

实现

这里讲述下,我在代码中的实现思路以及方法,供大家参考,方法不一定是最好的,主要讲的是实现的一个基本思路,可能有很多内容没考虑到,需要大家的指正。

业务中设计阶段有:
try尝试阶段:预留扣除(增加)资源
confirm提交阶段:确认扣除(增加)资源
cancel回滚阶段:回滚预留资源
也就是说每个服务提供者必须要实现这三个阶段的方法
image.png

  1. 一个完整的业务活动由一个主业务服务与若干从业务服务组成;
  2. 主业务服务负责发起并完成整个业务活动;
  3. 从业务服务提供TCC型业务操作;
  4. 业务活动管理器控制业务活动的一致性,它登记业务活动中的操作, 并在业务活动提交时确认所有的TCC型操作的confirm操作,在业务活动取消时调用所有TCC型操作的cancel操作

TCC事务注意事项

并发控制

用户在实现 TCC 时,应当考虑并发性问题,将锁的粒度降到最低,以最大限度提高分布式事务的并发性。

在一阶段 Try 操作中,分布式事务 T1 和分布式事务 T2 分别预留的那一部分资源,相互之间无干扰。这样在分布式事务的二阶段,无论 T1 是提交还是回滚,都不会对 T2 产生影响,这样 T1 和 T2 可以在同一笔业务数据上并行执行。
image.png

允许空回滚

如下图所示,事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因为丢包而导致的网络超时。此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,而 Cancel 操作调用未出现超时。

TCC 服务在未收到 Try 请求的情况下收到 Cancel 请求,这种场景被称为空回滚。空回滚在生产环境经常出现,用户在实现 TCC 服务时,应允许空回滚的执行,即收到空回滚时返回成功。
image.png

防悬挂控制

如下图所示,事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时。此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 调用未超时。在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现二阶段 Cancel 请求比一阶段 Try 请求先执行的情况,此 TCC 服务在执行晚到的Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel,造成 TCC 服务悬挂。

用户在实现 TCC 服务时,要允许空回滚,但是要拒绝执行空回滚之后 Try 请求,要避免出现悬挂。
图片1.png

幂等控制

无论是网络数据包重传,还是异常事务的补偿执行,都会导致 TCC 服务的 Try、Confirm 或者 Cancel 操作被重复执行;用户在实现 TCC 服务时,需要考虑幂等控制,即 Try、Confirm、Cancel 执行一次和执行多次的业务结果是一样的。
image.png

TCC事务组件

组件是基于hyper实现的,实现其主要目的是为了加强自己对TCC事务认识,组件没有生产环境使用,主要是先学习一个简单思想,然后从中找到不足加以改正,如果大家发现有什么问题可以及时联系我^ ^
GitHub:https://github.com/LoyaltyLu/...

谢谢观赏

这个篇幅较长,谢谢耐心观看,希望对您有所帮助,也希望大家提供下不同的意见,谢谢!


Grace development
记录分享开发、学习中的点点滴滴
1.7k 声望
89 粉丝
0 条评论
推荐阅读
可靠消息最终一致(异步确保型)
一致性设计在分布式系统中是一个重要问题。如果一个系统同时使用多个子数据系统来存储与读取数据,就必须设计满足功能需求的一致性定义。如果系统对不同数据子系统进行操作的结果不一致,不但可能会使用户困惑,...

LoyaltyLu9阅读 5.4k评论 1

程序猿必读-防范CSRF跨站请求伪造
CSRF(Cross-site request forgery,中文为跨站请求伪造)是一种利用网站可信用户的权限去执行未授权的命令的一种恶意攻击。通过伪装可信用户的请求来利用信任该用户的网站,这种攻击方式虽然不是很流行,但是却...

mylxsw22阅读 15.1k评论 12

PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go11阅读 2.7k评论 4

封面图
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go6阅读 2.9k评论 4

封面图
图片防盗链破解 解决图片防盗链问题 反向代理
当客户端(浏览器)向服务器请求内容的时候,会提交一个header,这个header中包含了如:浏览器信息、cookie等内容,那么有一个叫referer的东东,也包含在这里面。

TANKING7阅读 11.7k评论 5

Hyperf 3.0 发布,PHP 新时代
在过去的一年半时间里,Hyperf 2.2 共发布了 35 个小版本,使 Hyperf 达到了一个前所未有的高度,这里也获得了一些不错的数据反馈。

huangzhhui4阅读 1.5k评论 1

封面图
Redis的线程模型和事务
我原本只是想学习Redis的事务,但后来发现,Redis和传统关系型数据库的事务在ACID的表现上差异很大。而要想详细了解其中的缘由,就离不开Redis独特的单线程模型,因此本文将二者联系在一起讲解。

KerryWu6阅读 5.9k评论 2

1.7k 声望
89 粉丝
宣传栏