在使用spring cloud 分布式 app时候, 对于跨app的transaction管理, 可以使用阿里的SETA, 也就是阿里开源分布式事务框架FESCAR,
https://github.com/seata/seata
只是有时候只需要其中一小部分功能, 不想复杂化。
本文介绍的就是一个简化的分布式事务构件RedTx.
https://github.com/dong099/RedTx
steps to use RedTX open source projects
新建 RedTx server(refer to consul-service-mgr)
- pom.xml
com.sc
redtx-mgr
1.0
- add one annotation -@RedtxServer on springboot main class
@RedtxServer
@SpringBootApplication
public class RedTxServer {
...
}
- check the sample configuration - application.yml (redis and host/port setup)
redtx:
mgr:
host: ${REDTX_SERVER_NAME:172.10.1.63}
port: ${REDTX_SERVER_PORT:9011}
txTimeout: 6000
- start this app, it should show:
=========================================================
RedTx Server runs on hotst/port: 172.10.1.63:9011
=========================================================
新建 RedTx client app (refer to consul-service-a/b/c)
- pom.xml
com.sc
redtx-core
1.0
- add annotations
a). springboot main class - @EnableRedTx
@EnableRedTx
@SpringBootApplication
public class ServiceAApplication {
...
}
b). transaction method on service class - @RedTxTransaction
@Service
@Slf4j
public class DemoServiceImpl implements DemoService {
@Autowired
private FeignServiceBClient serviceBClient;
@Autowired
private FeignServiceCClient serviceCClient;
@Override
@RedTxTransaction
public String execRedTx(String value, String rollbackFlag) {
//codes on this section
log.debug("now enter into A - service - {}, {}", value, rollbackFlag);
String bResult = serviceBClient.runRedTx(value);
log.debug("now called B - service- Result - {}", bResult);
String cResult = serviceCClient.runRedTx(value);
log.debug("now called C - service- Result - {}", cResult);
return "success";
}
}
- check the configuration pointing to RedTx Server
redtx:
client:
tx-timeout: 30000
mgrAddrs: ${REDTX_SERVER:172.10.1.63:9011}
- start this client app, it will show:
=========================================================
Netty Client connected to server successfully! RedtxClientConfig [txTimeout=6000, mgrAddrs=172.10.1.63:9011, txSyncCallTimeout=3000]
=========================================================
下文提供的是调试结果简介
启动RedTx Server and spring cloud apps
[root@hadoopnode4 sts]# export REDTX_SERVER=172.10.1.63:9011
[root@hadoopnode4 sts]# java -jar consul-service-a.jar
[root@hadoopnode4 sts]# java -jar consul-service-b.jar
[root@hadoopnode4 sts]# java -jar consul-service-c.jar
[root@hadoopnode3 sts]# export REDTX_SERVER_NAME=172.10.1.63
[root@hadoopnode3 sts]# export REDTX_SERVER_PORT=9011
[root@hadoopnode3 sts]# java -jar consul-service-mgr.jar
app部署情况一览
client/server 启动没有先后, 会自动彼此重连
启动测试url
失败(rollback设置为true, 或者先填入db等同的重复key数据):
curl -i -H "Authorization: Bearer 1b87cdd8-39f5-46f1-b0a2-87f374a2793d" http://172.10.28.8:8900/svca/runRedTx -d "value=mygod72&rollbackFlag=false"
HTTP/1.1 200 OK
X-RateLimit-Remaining: 3
X-RateLimit-Burst-Capacity: 4
X-RateLimit-Replenish-Rate: 4
Content-Type: application/json;charset=UTF-8
Content-Length: 112
{"resultObj":"NoObj","resultCode":"fail","resultMessage":"Sorry, the network has some issue, please try again!"}
成功:
curl -i -H "Authorization: Bearer 1b87cdd8-39f5-46f1-b0a2-87f374a2793d" http://172.10.28.8:8900/svca/runRedTx -d "value=mygod73&rollbackFlag=false"
HTTP/1.1 200 OK
X-RateLimit-Remaining: 3
X-RateLimit-Burst-Capacity: 4
X-RateLimit-Replenish-Rate: 4
Set-Cookie: JSESSIONID=73AD3811B7E8722BC7F0A632E77F3621; Path=/; HttpOnly
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/plain;charset=UTF-8
Content-Length: 7
Date: Fri, 12 Jul 2019 10:15:21 GMT
success
检查每个db table数据插入情况, 应该是一致的
查看日志 (失败部分 consul-service-a.log)
[2019-07-12 18:11:58:315] [INFO ] [Thread: main] [method:com.redtx.core.netty.NettyClientBootstrap.run(NettyClientBootstrap.java:85)]
=========================================================
[2019-07-12 18:11:58:315] [INFO ] [Thread: main] [method:com.redtx.core.netty.NettyClientBootstrap.run(NettyClientBootstrap.java:86)]
Netty Client connected to server successfully! RedtxClientConfig [txTimeout=30000, mgrAddrs=172.10.1.63:9011, txSyncCallTimeout=3000]
[2019-07-12 18:11:58:316] [INFO ] [Thread: main] [method:com.redtx.core.netty.NettyClientBootstrap.run(NettyClientBootstrap.java:87)]
=========================================================
[2019-07-12 18:13:03:229] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.http.CallChainUtil.callGetter(CallChainUtil.java:40)]
getting groupId:
[2019-07-12 18:13:03:294] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.aop.TransactionAspect.transactionRunning(TransactionAspect.java:51)]
now get into AOP transactionRunning [value, rollbackFlag], [mygod72, false]
[2019-07-12 18:13:03:298] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxInfo.getFromCache(RedTxInfo.java:48)]
get txMethodId RedTxInfo [targetClazz=class com.sc.svca.service.DemoServiceImpl, businessMethod=public java.lang.String com.sc.svca.service.DemoServiceImpl.execRedTx(java.lang.String,java.lang.String), txMethodId=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String)]
[2019-07-12 18:13:03:303] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:28)]
started local RedTxContext!
[2019-07-12 18:13:03:309] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:42)]
redTxContextManager.startTx(), txHolder
[2019-07-12 18:13:03:321] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:49)]
current module's txHolder
[2019-07-12 18:13:03:342] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.service.DemoServiceImpl.execRedTx(DemoServiceImpl.java:27)]
now enter into A - service - mygod72, false
[2019-07-12 18:13:04:270] [INFO ] [Thread: hystrix-consul-service-b-1] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 0829A9CFBEE9B588BD2A5A6FD9EEA91B
[2019-07-12 18:13:04:289] [INFO ] [Thread: hystrix-consul-service-b-1] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 0829A9CFBEE9B588BD2A5A6FD9EEA91B
[2019-07-12 18:13:04:291] [DEBUG] [Thread: hystrix-consul-service-b-1] [method:com.redtx.core.http.CallChainUtil.callSetter(CallChainUtil.java:26)]
passing groupId:3e2e806d7e3846b7a221707c07d3ede3
[2019-07-12 18:13:06:361] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.service.DemoServiceImpl.execRedTx(DemoServiceImpl.java:31)]
now called B - service- Result - success
[2019-07-12 18:13:06:391] [INFO ] [Thread: hystrix-consul-service-c-1] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 0829A9CFBEE9B588BD2A5A6FD9EEA91B
[2019-07-12 18:13:06:393] [INFO ] [Thread: hystrix-consul-service-c-1] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 0829A9CFBEE9B588BD2A5A6FD9EEA91B
[2019-07-12 18:13:06:394] [DEBUG] [Thread: hystrix-consul-service-c-1] [method:com.redtx.core.http.CallChainUtil.callSetter(CallChainUtil.java:26)]
passing groupId:3e2e806d7e3846b7a221707c07d3ede3
[2019-07-12 18:13:08:164] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.service.DemoServiceImpl.execRedTx(DemoServiceImpl.java:38)]
now called C - service- Result - Calling consul-service-c FAILED! - FALLING BACK - with parameter - value:mygod72
[2019-07-12 18:13:08:168] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.netty.NettyClientBootstrap.getChannel(NettyClientBootstrap.java:54)]
try to get netty connection to server with config RedtxClientConfig [txTimeout=30000, mgrAddrs=172.10.1.63:9011, txSyncCallTimeout=3000]
[2019-07-12 18:13:08:189] [DEBUG] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.netty.NettyClientHandler.channelRead0(NettyClientHandler.java:61)]
received txMsg from netty server :
[2019-07-12 18:13:08:190] [INFO ] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.netty.NettyClientHandler.channelRead0(NettyClientHandler.java:66)]
received sync msg - TxMsg(txStatus=1, groupId=3e2e806d7e3846b7a221707c07d3ede3, unitId=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String), txLauncher=true, msgStr=null)
[2019-07-12 18:13:08:190] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxExecutor.runBizMethod(RedTxExecutor.java:43)]
txLauncher get sync netty tx msg
[2019-07-12 18:13:08:191] [INFO ] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxExecutor.runBizMethod(RedTxExecutor.java:46)]
Distributed Transaction already failed! thread name-http-nio-8901-exec-7, txHolder-txStatus-null
[2019-07-12 18:13:08:193] [ERROR] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.ds.RedTxServiceImpl.undo(RedTxServiceImpl.java:262)]
Rollback(undo) is not needed for current module, group 3e2e806d7e3846b7a221707c07d3ede3 unit String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String) with exception: No qualifying bean of type 'javax.sql.DataSource' available
查看日志 (成功部分 consul-service-a.log)
[2019-07-12 18:15:20:926] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.aop.TransactionAspect.transactionRunning(TransactionAspect.java:51)]
now get into AOP transactionRunning [value, rollbackFlag], [mygod73, false]
[2019-07-12 18:15:20:927] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxInfo.getFromCache(RedTxInfo.java:48)]
get txMethodId RedTxInfo [targetClazz=class com.sc.svca.service.DemoServiceImpl, businessMethod=public java.lang.String com.sc.svca.service.DemoServiceImpl.execRedTx(java.lang.String,java.lang.String), txMethodId=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String)]
[2019-07-12 18:15:20:928] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:28)]
started local RedTxContext!
[2019-07-12 18:15:20:929] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:42)]
redTxContextManager.startTx(), txHolder
[2019-07-12 18:15:20:931] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:49)]
current module's txHolder
[2019-07-12 18:15:20:932] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.service.DemoServiceImpl.execRedTx(DemoServiceImpl.java:27)]
now enter into A - service - mygod73, false
[2019-07-12 18:15:20:936] [INFO ] [Thread: hystrix-consul-service-b-2] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 73AD3811B7E8722BC7F0A632E77F3621
[2019-07-12 18:15:20:937] [INFO ] [Thread: hystrix-consul-service-b-2] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 73AD3811B7E8722BC7F0A632E77F3621
[2019-07-12 18:15:20:938] [DEBUG] [Thread: hystrix-consul-service-b-2] [method:com.redtx.core.http.CallChainUtil.callSetter(CallChainUtil.java:26)]
passing groupId:286c237bb4564deea75fca9713b1865f
[2019-07-12 18:15:21:007] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.service.DemoServiceImpl.execRedTx(DemoServiceImpl.java:31)]
now called B - service- Result - success
[2019-07-12 18:15:21:012] [INFO ] [Thread: hystrix-consul-service-c-2] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 73AD3811B7E8722BC7F0A632E77F3621
[2019-07-12 18:15:21:013] [INFO ] [Thread: hystrix-consul-service-c-2] [method:com.sc.cmn.config.FeginOAuth2Interceptor.apply(FeginOAuth2Interceptor.java:44)]
=session-id: 73AD3811B7E8722BC7F0A632E77F3621
[2019-07-12 18:15:21:014] [DEBUG] [Thread: hystrix-consul-service-c-2] [method:com.redtx.core.http.CallChainUtil.callSetter(CallChainUtil.java:26)]
passing groupId:286c237bb4564deea75fca9713b1865f
[2019-07-12 18:15:21:114] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.service.DemoServiceImpl.execRedTx(DemoServiceImpl.java:38)]
now called C - service- Result - success
[2019-07-12 18:15:21:116] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.netty.NettyClientBootstrap.getChannel(NettyClientBootstrap.java:54)]
try to get netty connection to server with config RedtxClientConfig [txTimeout=30000, mgrAddrs=172.10.1.63:9011, txSyncCallTimeout=3000]
[2019-07-12 18:15:21:124] [DEBUG] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.netty.NettyClientHandler.channelRead0(NettyClientHandler.java:61)]
received txMsg from netty server :
[2019-07-12 18:15:21:125] [INFO ] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.netty.NettyClientHandler.channelRead0(NettyClientHandler.java:66)]
received sync msg - TxMsg(txStatus=0, groupId=286c237bb4564deea75fca9713b1865f, unitId=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String), txLauncher=true, msgStr=null)
[2019-07-12 18:15:21:125] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxExecutor.runBizMethod(RedTxExecutor.java:43)]
txLauncher get sync netty tx msg
[2019-07-12 18:15:21:126] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:57)]
current module's txHolder after biz method
[2019-07-12 18:15:21:127] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.netty.NettyClientBootstrap.getChannel(NettyClientBootstrap.java:54)]
try to get netty connection to server with config RedtxClientConfig [txTimeout=30000, mgrAddrs=172.10.1.63:9011, txSyncCallTimeout=3000]
[2019-07-12 18:15:21:131] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxService.execTx(RedTxService.java:61)]
send netty msg
[2019-07-12 18:15:21:132] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.redtx.core.tx.RedTxContext.remove(RedTxContext.java:38)]
Last clean on current module local context - RedTxContext(groupId=286c237bb4564deea75fca9713b1865f, unitId=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String), resource=null)
[2019-07-12 18:15:21:133] [DEBUG] [Thread: http-nio-8901-exec-7] [method:com.sc.svca.controller.RedTxTestController.execute(RedTxTestController.java:25)]
A - service returned success
[2019-07-12 18:15:21:154] [DEBUG] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.ds.RedTxServiceImpl.cleanUndo(RedTxServiceImpl.java:195)]
cleaned undo log DELETE FROM TXC_UNDO_LOG WHERE GROUP_ID=286c237bb4564deea75fca9713b1865f AND UNIT_ID=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String).
[2019-07-12 18:15:21:169] [DEBUG] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.netty.NettyClientHandler.channelRead0(NettyClientHandler.java:61)]
received txMsg from netty server :
[2019-07-12 18:15:21:170] [DEBUG] [Thread: nioEventLoopGroup-7-1] [method:com.redtx.core.ds.RedTxServiceImpl.cleanUndo(RedTxServiceImpl.java:195)]
cleaned undo log DELETE FROM TXC_UNDO_LOG WHERE GROUP_ID=286c237bb4564deea75fca9713b1865f AND UNIT_ID=String com.sc.svca.service.DemoServiceImpl.execRedTx(String,String).