标签:线程变量 返回 exce exe 恢复 存储 rpc 冲突 txt
一、描述:
随着分布式服务的到来,分布式事务必然也就成为分布式的重点,因此了解tx-lcn很有必要
二、tx-lcn的TC与TM的交互图:
注:其中事务发起方为TC-A,而TC-B、TC-C为事务参与方,TM为事务处理器:
交互描述:
1、TC-A向TM发送创建组请求
2、TC-B向TM发送加入组请求
3、TC-C向TM发送加入组请求
4、TC-B将调用结果返回TC-A
5、TC-B将事务状态发送到TM
6、TC-C将调用结果返回TC-A
7、TC-C将事务状态发送到TM
8、TC-A向TM发送事务完成通知
9、TM根据事务情况,分别向TC-A,TC-B,TC-C发送事务通知
二、各注解的适用:
1、@LCNTransaction:(一般用于mysql或oracle,在于支持事务场景)
代理本地connection连接,使用数据库本身提供的commit或者rollback完成事务的提交或者回滚
2、@TCCTransaction:(一般用于redis,memcache)
不代理本地connection连接,以callback指定类,confirm、cancel指定类内的方法完成事务的提交或者回滚
3、@TXCTransaction:(一般用于mysql或oracle,在于不支持事务场景)
代理本地connection连接,将操作可影响到的数据先查询缓存,通过TM的事务通知完成删除备份数据或者恢复备份数据
4、@TXTransaction:
以上三个注解的抽象版,默认为@LCNTransaction
注:分布式事务的组合可以是LCN+LCN+LCN,TCC+TCC+TCC,TXC+TXC+TXC,LCN+TCC+TXC或者LCN+LCN(LCN+TCC+TXC)+TXC,也就是说可以任意组合、嵌套;
三、TM交互步骤:
TM的交互分三层:
第一层为接受TC的调用通知:
ServerRpcAnswer:callback();
第二层初始化通信数据:
(1):QueryTMClusterExecuteService
查询已缓存的TM地址
(2):InitClientService
绑定TC的通信信息
第三层为TM和TC的事务交互层:
(1):CreateGroupExecuteService
创建事务组,开始分布式事务
(2):AcquireDTXLockExecuteService
获取分布式锁(一般用于TXC类型的事务)
(3):JoinGroupExecuteService
加入事务组
(4):NotifyGroupExecuteService
通知TC事务的状态
(5):CleanInvalidTMExecuteService、
通知TC要求清空事务日志
(6):ReleaseDTXLockExecuteService
释放分布式锁(和获取搭配使用)
(7):WriteTxExceptionExecuteService
将事务异常写入本地日志
四、TC交互步骤:
TC的交互分三层:
第一层为获取注解层:
如:TransactionAspect类的方法:
(1):代理标注@LCNTransaction注解的方法
@Pointcut("@annotation(com.codingapi.txlcn.tc.annotation.TxTransaction)")
public void txTransactionPointcut() {}
(2):代理标注@TCCTransaction注解的方法
@Pointcut("@annotation(com.codingapi.txlcn.tc.annotation.LcnTransaction)")
public void lcnTransactionPointcut() {}
(3):代理标注@TXCTransaction注解的方法
@Pointcut("@annotation(com.codingapi.txlcn.tc.annotation.TxcTransaction)")
public void txcTransactionPointcut() {}
(4):代理标注@TXTransaction注解的方法
@Pointcut("@annotation(com.codingapi.txlcn.tc.annotation.TccTransaction)")
public void tccTransactionPointcut() {}
第二层为代理connection层:
如:LcnTransactionResourceProxy类的方法:proxyConnection
如:TccTransactionResourceProxy类的方法:proxyConnection
如:TxcTransactionResourceProxy类的方法:proxyConnection
第三层为rpc交互层:
获取事务管理类:
(1):如TC-A所示处于事务最外层:
使用(TCN|TCC|TXC)StartingTransaction作为事务的代理层包含三部分内容:
preBusinessCode:创建组并代理本地connection,如createGroup,makeProxy
onBusinessCodeError|onBusinessCodeSuccess:记录或清空本地事务状态
postBusinessCode:发送事务状态通知,如notifyGroup
(2):如TC-B、TC-C所示处于事务内层(这里假设TC-A、TC-B、TC-C处于同一个应用系统):
使用(TCN|TCC|TXC)RunningTransaction作为事务的代理层包含三部分内容:
preBusinessCode:代理本地connection,如makeProxy
onBusinessCodeError:清空本地事务日志记录
onBusinessCodeSuccess:加入组,如joinGroup
进行交互:
交互执行类:DTXServiceExecutor:
交互方法transactionRunning:
//被代理方法执行前操作
dtxLocalControl.preBusinessCode(info);
//调用被代理的方法
dtxLocalControl.doBusinessCode(info);
//代理方法执行后操作
dtxLocalControl.onBusinessCodeSuccess(info, result);
//被代理执行出错操作
dtxLocalControl.onBusinessCodeError(info, e);
//整个交互完成后操作
dtxLocalControl.postBusinessCode(info);
接收TM的调用:ClientRpcAnswer:callback()
//或是通知提交事务,或是通知回滚事务,或是通知删除日志
注:参与分布式事务的每个服务需要分别建组,如果当前线程变量里面已经存有组,加入即可,否则需要创建组并存储到线程变量内
五、疑问以及解答:
1、如何保证分布式服务的多个参与方同属于一个事务组
在主参与方创建事务组groupId,并保存到redis中,后面每个事务参与者都携带该groupId:统一管理事务组
2、若在一个分布式事务中多次调用同一应用的同一方法,如何做区分
每个事务参与方都有groupId(事务组)+modeId(模块标识)+unitId(方法全称)+transactionType(事务类型)做唯一性区分:如果业务合理应该不会冲突
3、最终分布式事务能不能完成提交或者回滚
最终分布式事务的决断在TM,而TM只会向同一groupId事务参与方发送通知,也就是说只支持同一个服务内的多个参与方的分布式事务:改源码
4、Txc类型的事务能不能嵌套
经过简单试验,确实可以
五、demo地址:https://gitee.com/lswater/tx-lcn-demo
标签:线程变量 返回 exce exe 恢复 存储 rpc 冲突 txt
原文地址:https://www.cnblogs.com/lswater/p/11863336.html