TCC设计理解-RPC适配(3)

TCC设计理解3-RPC适配

RPC框架通常并不推荐使用业务异常传输,在使用Result的情况下,在成功和失败都会正确地返回Result,这种情况下需要根据Result中的异常Code判断来抛出异常,让TCC框架捕获异常依据。

角色设计

RPC适配设计方案参考tcc-transaction项目,虽然只是个简单的tcc实现,但是对研究rpc tcc提供了非常好的思路。

先提几个框架中的概念:

方法类型

ROOT、CONSUMER、PROVIDER、NORMAL

  • root 主要是做充当事务协调者的角色Leader,事务成功和失败的判断者
  • consumer 作为provider中转,提前设置事务上下文,以方便分支事务做关联,调用方,消费provider
  • provider 其实和root差不多,只是把root的上下文关联过来,接收consumer传递过来的事务上下文
  • normal 不做特殊处理,普通方法,通常执行confirm和cancel方法

这几个类型的区分主要是靠1、是否存在@Compensable注解2、是否有TransactionContext等来判断

  • 事务上下文,TransactionContext
    主要是作用是用来传输事务信息给远程服务。
    分支事务通常是不同的应用服务提供的,与根事务 是在不同的进程中,consumer主要是将事务信息传给远程服务。

事务持久化

事务持久化提供独立于业务的持久化支持,可以选择mysql、redis、内存数据库或者本地File文件支持,主要提供以下方法即可。

定义接口类

1
2
3
4
5
6
7
8
9
10
11
12
public interface TransactionRepository {
int create(Transaction transaction);
int update(Transaction transaction);
int delete(Transaction transaction);
Transaction findByXid(int xid);
List<Transaction> findAllUnmodifiedSince(Date date);
}

RPC设计

返回包装 | 异常

这里着重推荐使用业务BizResult表示Consumer得到的结果,在服务不可用的情况下,底层便已经抛出了异常,不在讨论范围内。

如果使用自定义异常,则在底层Result解析BizResult时便抛出了异常,会直接将异常上抛给Consumer,通常TCC会选择将异常作为依据,但是推荐在这个基础上适配BizResult解析作为异常依据

基于RPC的TCC框架和链路跟踪有着一致的设计方式,不同的是TCC不仅需要一套完善的信息存储,同时还需要根据业务状态对数据进行重复使用,这里的数据就是事务。

RPC阶段可能需要考虑的问题:

  1. 事务本身信息的传递是RPC框架需要考虑的信息,如何将该事物信息作为传输的一部分,这里可以借鉴链路跟踪的技术。
    >
    如果是DUBBO参考:
    https://github.com/xuminwlt/j360-trace

  2. 获取RPC中传输的信息,如何有效在业务之前将TCC植入到RPC和业务代码中,这里通常是用AOP,通过AOP可以很好地依据业务形势来做出相应的TCC动作,获取RPC中的数据可以使用变量传递,或者定义ThreadLocal来获取。

在使用AOP方式时,通常业务代码本身会使用1到多个AOP,这里需要注意AOP的执行顺序,通过Order来实现,最小的最先执行,最终返回的结果是后面一个AOP执行的结果。