apache / incubator-seata-samples

Apache Seata(incubating) Samples for Java
https://seata.apache.org/
Apache License 2.0
2.28k stars 1.92k forks source link

springboot tcc sample keeps blocking #254

Open dreamoftch opened 5 years ago

dreamoftch commented 5 years ago

i run the latest sample code(commit id is: 145b2cf95b1af3124f7d169c1339e0ed764f8efc) follow the guide

both seata server and the provider application run ok, but SpringbootTccTransactionApplication keeps blocking.

when i use jstack to find what happened, i see this:

"main" #1 prio=5 os_prio=31 tid=0x00007ff4e382d800 nid=0x1903 in Object.wait() [0x0000700007fb3000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at io.seata.core.rpc.netty.RmRpcClient.lambda$getPoolKeyFunction$0(RmRpcClient.java:153)
    - locked <0x000000076af19e58> (a java.lang.Object)
    at io.seata.core.rpc.netty.RmRpcClient$$Lambda$58/1183701566.apply(Unknown Source)
    at io.seata.core.rpc.netty.NettyClientChannelManager.doConnect(NettyClientChannelManager.java:196)
    at io.seata.core.rpc.netty.NettyClientChannelManager.acquireChannel(NettyClientChannelManager.java:102)
    - locked <0x000000076af19d50> (a java.lang.Object)
    at io.seata.core.rpc.netty.AbstractRpcRemotingClient.sendMsgWithResponse(AbstractRpcRemotingClient.java:226)
    at io.seata.core.rpc.netty.AbstractRpcRemotingClient.sendMsgWithResponse(AbstractRpcRemotingClient.java:233)
    at io.seata.rm.AbstractResourceManager.branchRegister(AbstractResourceManager.java:67)
    at io.seata.rm.DefaultResourceManager.branchRegister(DefaultResourceManager.java:96)
    at io.seata.rm.tcc.interceptor.ActionInterceptorHandler.doTccActionLogStore(ActionInterceptorHandler.java:118)
    at io.seata.rm.tcc.interceptor.ActionInterceptorHandler.proceed(ActionInterceptorHandler.java:69)
    at io.seata.spring.tcc.TccActionInterceptor.invoke(TccActionInterceptor.java:85)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at org.apache.dubbo.common.bytecode.proxy0$$EnhancerBySpringCGLIB$$e08bc0cf.prepare(<generated>)
    at io.seata.samples.tcc.springboot.dubbo.service.TccTransactionService.doTransactionCommit(TccTransactionService.java:32)
    at io.seata.samples.tcc.springboot.dubbo.service.TccTransactionService$$FastClassBySpringCGLIB$$e1c6fcc.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at io.seata.spring.annotation.GlobalTransactionalInterceptor$1.execute(GlobalTransactionalInterceptor.java:104)
    at io.seata.tm.api.TransactionalTemplate.execute(TransactionalTemplate.java:64)
    at io.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalTransaction(GlobalTransactionalInterceptor.java:101)
    at io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:76)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at io.seata.samples.tcc.springboot.dubbo.service.TccTransactionService$$EnhancerBySpringCGLIB$$81f65c15.doTransactionCommit(<generated>)
    at io.seata.samples.tcc.springboot.dubbo.starter.SpringbootTccTransactionApplication.transactionCommitDemo(SpringbootTccTransactionApplication.java:51)
    at io.seata.samples.tcc.springboot.dubbo.starter.SpringbootTccTransactionApplication.main(SpringbootTccTransactionApplication.java:42)

   Locked ownable synchronizers:
    - None

after looking at the source code in io.seata.core.rpc.netty.RmRpcClient:

            String resourceIds = getMergedResourceKeys();
            synchronized (ResourceManager.RESOURCE_LOCK) {
                while (StringUtils.isNullOrEmpty(resourceIds)) {
                    try {
                        ResourceManager.RESOURCE_LOCK.wait();
                    } catch (InterruptedException exx) {
                        LOGGER.error("wait resourceIds interrupted error:{}", exx.getMessage(), exx);
                    }
                    resourceIds = getMergedResourceKeys();
                }
            }

i found the reason leads to blocking is that SpringbootTccTransactionApplication which acts as TM does not have RM inside, but ActionInterceptorHandler invokes the branchRegister method, which finally requires RM resources, thus code goes into ResourceManager.RESOURCE_LOCK.wait().

i found that the synchronized control code was added by @slievrly , which comments bugfix:rm channel register null resource (#1401), so @slievrly could you help look at this problem?

thanks so much ...

dreamoftch commented 5 years ago

i changed seata version from 0.9.0 to 0.8.0, it works

slievrly commented 4 years ago

@dreamoftch please update to the latest version.