深入解析中间件之-TCC事务

TCC

重拾了一把JavaWeb的部署流程,使用Jetty在Idea专业版上运行。步骤如下:

  1. 本地下载Jetty,Idea启用Jetty Intergration插件(注意:不是Jetty Runner)
  2. 在Run Configuration中选择Jetty Server/Local,配置本地的Jetty服务器(图1)
  3. 新建Jetty Server,在Deployment中添加web工程的war exploded(图2)
  4. 保存后,点击右上角的三角箭头启动Jetty

1

2

坑爹的是由于有三个工程,第二个Jetty工程即使在vm.options中添加-Djetty.http.port=8081,使用的还是8080端口

3

遂放弃,采用mvn jetty:run的方式

在根pom.xml中添加jetty-plugin的配置(注意:不需要在capital/order/red下添加):

1
2
3
4
5
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.7.v20170914</version>
</plugin>

然后进入到tcc-transaction的根目录(注意不要进入到实际的capital/order/red等目录)分别执行(开三个终端):

1
2
3
➜  tcc-transaction git:(master-1.2.x) ✗ mvn jetty:run -projects tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-capital -am
➜ tcc-transaction git:(master-1.2.x) ✗ mvn -Djetty.http.port=8088 jetty:run -projects tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-redpacket -am
➜ tcc-transaction git:(master-1.2.x) ✗ mvn -Djetty.http.port=8086 jetty:run -projects tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-order -am

解释下这里的参数含义:

  • -Djetty.http.port=8088表示web端口,端口不能相同,默认是8080
  • 通过-projects定位到具体的web子项目
  • 最后还要加上-am,表示会编译相关的依赖模块

比如capital的依赖:

1
2
3
4
5
6
7
8
[INFO] tcc-transaction
[INFO] tcc-transaction-api
[INFO] tcc-transaction-core
[INFO] tcc-transaction-spring
[INFO] tcc-transaction-tutorial-sample
[INFO] tcc-transaction-http-sample
[INFO] tcc-transaction-http-capital-api
[INFO] tcc-transaction-http-capital

red的依赖:

1
2
3
4
5
6
7
8
[INFO] tcc-transaction
[INFO] tcc-transaction-api
[INFO] tcc-transaction-core
[INFO] tcc-transaction-spring
[INFO] tcc-transaction-tutorial-sample
[INFO] tcc-transaction-http-sample
[INFO] tcc-transaction-http-redpacket-api
[INFO] tcc-transaction-http-redpacket

order的依赖:

1
2
3
4
5
6
7
8
9
[INFO] tcc-transaction
[INFO] tcc-transaction-api
[INFO] tcc-transaction-core
[INFO] tcc-transaction-spring
[INFO] tcc-transaction-tutorial-sample
[INFO] tcc-transaction-http-sample
[INFO] tcc-transaction-http-capital-api
[INFO] tcc-transaction-http-redpacket-api
[INFO] tcc-transaction-http-order

如果没有报错,会输出下面类似的启动成功日志(以order的8086端口为例):

1
2
3
[INFO] Started ServerConnector@6bc6692e{HTTP/1.1,[http/1.1]}{0.0.0.0:8086}
[INFO] Started @17821ms
[INFO] Started Jetty Server

既然命令行方式启动,也可以通过Idea的maven插件代替执行:

5

但是要使用Debug时,还是会出现地址已经被使用的情况。可以通过在命令行启动mvnDebug:

1
2
3
4
5
6
7
8
9
10
➜  tcc-transaction git:(master-1.2.x) ✗ mvnDebug -Djetty.http.port=8086 jetty:run -projects tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-order -am
Preparing to Execute Maven in Debug Mode
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512M; support was removed in 8.0
Listening for transport dt_socket at address: 8000

//当下一步执行Debug后,在终端这里会打印日志:
...
[INFO] Started ServerConnector@74d776fb{HTTP/1.1,[http/1.1]}{0.0.0.0:8086}
[INFO] Started @113766ms
[INFO] Started Jetty Server

然后在Idea中配置Remote,保存后,在右上角点击Debug(也只有Debug,无法选Run):

6

打开order的页面,这里是http://localhost:8086

4

购买一个IPhonx后,三个终端的日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//资金终端
capital try record called. time seq:2017-11-24 23:26:29
capital confirm record called. time seq:2017-11-24 23:26:33
capital try record called. time seq:2017-11-24 23:26:50

//红包终端
red packet try record called. time seq:2017-11-24 23:26:31
red packet confirm record called. time seq:2017-11-24 23:26:34

//订单终端
order try make payment called.time seq:2017-11-24 23:26:28
order confirm make payment called. time seq:2017-11-24 23:26:32
order try make payment called.time seq:2017-11-24 23:26:49

再买一个Mac,资金都不够了,最终订单失败:

1
2
3
4
5
6
7
8
9
//资金终端
java.lang.RuntimeException: not enough balance!
capital cancel record called. time seq:2017-11-24 23:26:52

//红包终端没有新的输出

//订单终端
java.lang.RuntimeException: not enough balance!
order cancel make payment called.time seq:2017-11-24 23:26:51

数据库信息:

6

TCC的事务调用流程设计本地事务和远程事务、根事务与分支事务,并且还有一个Proxy代理层。
本地事务、代理事务、远程事务都加上了@Conpensable注解,并且都定义了try/confirm/cancel方法。
为了弄清楚各种事务的调用链,在相关代码上加上日志(补偿事务、资源协调者、业务类):

sample-http-order(订单主事务):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
1.根事务(订单)的两个拦截器
16:48:22,476 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:ROOT
16:48:22,548 [CompensableTransactionInterceptor] ⭐️root transaction begin, participants size:0
16:48:22,607 [ResourceCoordinatorInterceptor] 添加参与者到事务中,participant:Participant@23b7d68f,当前参与者数量:1
16:48:22,610 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:11137112-7fee-3a85-b17d-13cc79e2f02b,状态:TRYING,参与者数量:1
16:48:22,835 [PaymentServiceImpl] ⭐️order try make payment called.time seq:2017-11-26 16:48:22

2.分支事务1(账户代理)的两个拦截器。这里会先远程RPC调用账户远程事务,完成后,才会接着执行分支事务2
16:48:22,843 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:NORMAL
16:48:22,871 [ResourceCoordinatorInterceptor] 添加参与者到事务中,participant:Participant@a03f70e,当前参与者数量:2
16:48:22,871 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:11137112-7fee-3a85-b17d-13cc79e2f02b,状态:TRYING,参与者数量:2
16:48:22,891 [TradeOrderServiceProxy] ⭐️capital proxy record..事务状态:TRYING

4.分支事务2(红包代理)的两个拦截器。等待账户分支事务的try方法完成后(包括RPC调用),才会开始分支事务2
16:48:24,321 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:NORMAL
16:48:24,345 [ResourceCoordinatorInterceptor] 添加参与者到事务中,participant:Participant@226f03da,当前参与者数量:3
16:48:24,345 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:11137112-7fee-3a85-b17d-13cc79e2f02b,状态:TRYING,参与者数量:3
16:48:24,346 [TradeOrderServiceProxy] ⭐️redPacket proxy record..事务状态:TRYING

6.根事务的try方法执行完成,两个分支事务代理以及远程事务的try方法也都完成了
16:48:25,737 [CompensableTransactionInterceptor] root transaction proceed finished!

7.根事务的commit方法开始。订单(第一个参与者):23b7d68f,账户(第二个参与者):a03f70e,红包(最后一个参与者):226f03da。
16:48:25,737 [CompensableTransactionInterceptor] root transaction commit begins, participants size:3
16:48:25,744 [TransactionManager] 事务状态更新为CONFIRMING,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:11137112-7fee-3a85-b17d-13cc79e2f02b,参与者数量:3
16:48:25,744 [Transaction] 参与者提交事务,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:78226cf3-348f-327d-a21d-4df15d8a1c0b,participant:Participant@23b7d68f

8.根事务的confirm方法。注意这里调用参与者的commit方法先从订单(第一个参与者)开始,而不是红包(最后一个参与者)开始。
️16:48:26,746 [PaymentServiceImpl] ⭐️order confirm make payment called. time seq:2017-11-26 16:48:26

9.分支事务(账户代理,第二个参与者)的confirm方法
16:48:26,756 [Transaction] 参与者提交事务,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:e9e80142-1477-3161-ad50-fc474e70ade1,participant:Participant@a03f70e
16:48:26,756 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:NORMAL
16:48:26,757 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:11137112-7fee-3a85-b17d-13cc79e2f02b,状态:CONFIRMING,参与者数量:3
16:48:26,757 [TradeOrderServiceProxy] ⭐️capital proxy record..事务状态:CONFIRMING

11.分支事务(红包代理,第三个参与者)的confirm方法
16:48:27,873 [Transaction] 参与者提交事务,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:16a32620-06a8-3228-8046-e60516206fdd,participant:Participant@226f03da
16:48:27,874 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:NORMAL
16:48:27,874 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:11137112-7fee-3a85-b17d-13cc79e2f02b,状态:CONFIRMING,参与者数量:3
16:48:27,874 [TradeOrderServiceProxy] ⭐️redPacket proxy record..事务状态:CONFIRMING

13.根事务的commit完成
16:48:28,959 [CompensableTransactionInterceptor] root transaction commit finish, participants size:3
16:48:28,960 [CompensableTransactionInterceptor] root transaction finally, participants size:3

sample-http-capital(资金分支事务):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3.远程事务的try方法:
16:48:23,024 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:PROVIDER
16:48:23,068 [CompensableTransactionInterceptor] [TRYING]provider transaction propagationNewBegin, participants size:0
16:48:23,096 [ResourceCoordinatorInterceptor] 添加参与者到事务中,participant:Participant@3d279b8e,当前参与者数量:1
16:48:23,097 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:e9e80142-1477-3161-ad50-fc474e70ade1,状态:TRYING,参与者数量:1
16:48:24,276 [CapitalTradeOrderServiceImpl] ⭐️capital try record called. time seq:2017-11-26 16:48:24TRYING
16:48:24,315 [CompensableTransactionInterceptor] [TRYING]provider transaction proceed finish, participants size:1
16:48:24,315 [CompensableTransactionInterceptor] provider transaction finally, participants size:1

10.远程事务的confirm方法:
16:48:26,770 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:PROVIDER
16:48:26,771 [CompensableTransactionInterceptor] [CONFIRMING]provider transaction propagationExistBegin, participants size:1
16:48:26,782 [TransactionManager] 事务状态更新为CONFIRMING,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:e9e80142-1477-3161-ad50-fc474e70ade1,参与者数量:1
16:48:26,782 [Transaction] 参与者提交事务,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:f4b5c1ed-f64c-3e1d-b99d-b57bc2449937,participant:Participant@3d279b8e
16:48:27,788 [CapitalTradeOrderServiceImpl] ⭐️capital confirm record called. time seq:2017-11-26 16:48:27CONFIRMING
16:48:27,871 [CompensableTransactionInterceptor] [CONFIRMING]provider transaction commit finish, participants size:1
16:48:27,871 [CompensableTransactionInterceptor] provider transaction finally, participants size:1

sample-http-redpacket(红包分支事务):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
5.远程事务的try方法:
16:48:24,404 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:PROVIDER
16:48:24,432 [CompensableTransactionInterceptor] [TRYING]provider transaction propagationNewBegin, participants size:0
16:48:24,468 [ResourceCoordinatorInterceptor] 添加参与者到事务中,participant:Participant@403700a,当前参与者数量:1
16:48:24,469 [ResourceCoordinatorInterceptor] 事务xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:16a32620-06a8-3228-8046-e60516206fdd,状态:TRYING,参与者数量:1
16:48:25,705 [RedPacketTradeOrderServiceImpl] ⭐️red packet try record called. time seq:2017-11-26 16:48:25TRYING
16:48:25,732 [CompensableTransactionInterceptor] [TRYING]provider transaction proceed finish, participants size:1
16:48:25,732 [CompensableTransactionInterceptor] provider transaction finally, participants size:1

12.远程事务的confirm方法:
16:48:27,886 [CompensableTransactionInterceptor] [CompensableTransactionInterceptor拦截器],方法类型:PROVIDER
16:48:27,886 [CompensableTransactionInterceptor] [CONFIRMING]provider transaction propagationExistBegin, participants size:1
16:48:27,895 [TransactionManager] 事务状态更新为CONFIRMING,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:16a32620-06a8-3228-8046-e60516206fdd,参与者数量:1
16:48:27,897 [Transaction] 参与者提交事务,xid:globalTransactionId:c1acaf66-0151-3d16-874d-b89840ba49b5,branchQualifier:4812b875-712e-3cd7-92e5-42c1d8d0d8f1,participant:Participant@403700a
16:48:28,901 [RedPacketTradeOrderServiceImpl] ⭐️red packet confirm record called. time seq:2017-11-26 16:48:28CONFIRMING
16:48:28,935 [CompensableTransactionInterceptor] [CONFIRMING]provider transaction commit finish, participants size:1
16:48:28,935 [CompensableTransactionInterceptor] provider transaction finally, participants size:1

调用图如下:

1


文章目录