ShardingSphere 分布式事务
ShardingSphere里定义了分布式事务的SPI接口ShardingTransactionManager,Sharding-JDBC和Sharding-Proxy为分布式事务的两个接入端。XAShardingTransactionManager为分布式事务的XA实现类,通过引入sharding-transaction-xa-core依赖,即可加入ShardingSphere 的分布式事务生态中。XAShardingTransactionManager主要负责对actual datasource进行管理和适配,并且将接入端事务的begin/commit/rollback操作委托给具体的XA事务管理器。
XA事务简单介绍
XA 分布式事务是强一致的分布式事务。 XA 整体设计思路可以概括为,如何在现有事务模型上微调扩展,实现分布式事务。
XA 分布式事务可以简单的概括为三个部分:
- 应用程序(Application Program ,简称 AP): 用于定义事务边界(即定义事务的开始和结束),并 且在事务边界内对资源进行操作。
- 资源管理器(Resource Manager,简称 RM): 如数据库、文件系统等,并提供访问资源的方式
- 事务管理器 (Transaction Manager ,简称 TM):负责分配 事务唯一标识,监控事务的执行进度,并负责事务 的提交、回滚等。
XAShardingSphereTransactionManager为Apache ShardingSphere 的分布式事务的 XA 实现类。 它主要负责对多数据源进行管理和适配,并且将相应事务的开启、提交和回滚操作委托给具体的 XA 事务管理器。
Java 通过定义 JTA 接口实现了 XA 模型,JTA 接口中的 ResourceManager 需要数据库厂商提供 XA 驱动实现, TransactionManager 则需要事务管理器的厂商实现,传统的事务管理器需要同应用服务器绑定,因此使用的成本很高。 而嵌入式的事务管器可以以 jar 包的形式提供服务,同 Apache ShardingSphere 集成后,可保证分片后跨库事务强一致性。
通常,只有使用了事务管理器厂商所提供的 XA 事务连接池,才能支持 XA 的事务。Apache ShardingSphere 在整合 XA 事务时,采用分离 XA 事务管理和连接池管理的方式,做到对应用程序的零侵入。
从ShardingSphere-jdbc开始
根据上篇文章的介绍,我们可以了解到在初始化ShardingSphereDataSource的过程中,会调用transactionContexts创建事务有关的上下文。 这篇文章我们还是从 createDataSource开始一步步查看分布式事务有关的代码
下面代码是 createDataSource中初始化的部分
String xaTransactionMangerType = metaDataContexts.getProps().getValue(ConfigurationPropertyKey.XA_TRANSACTION_MANAGER_TYPE);
transactionContexts = createTransactionContexts(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), dataSourceMap, xaTransactionMangerType);
可以看到metaDataContexts中的参数已经初始化完毕,基础的数据库以及分库分表等规则都已经载入了metaDataContexts原数据上下文中,ShardingSphereDataSource开始载入事物有关内容
private TransactionContexts createTransactionContexts(final DatabaseType databaseType, final Map<String, DataSource> dataSourceMap, final String xaTransactionMangerType) {
ShardingTransactionManagerEngine engine = new ShardingTransactionManagerEngine();
engine.init(databaseType, dataSourceMap, xaTransactionMangerType);
return new StandardTransactionContexts(Collections.singletonMap(DefaultSchema.LOGIC_NAME, engine));
}
程序调用了createTransactionContexts 方法中的ShardingTransactionManagerEngine的 init 初始化,根据传入的xaTransactionMangerType(这里可以看到是Bitronix)
Bitronix是一个流行的和Atomikos类似的开源JTA事务管理器实现,
经过init的初始化程序,事务有关的信息被注入到了
transactionManagerMap
public ShardingTransactionManager getTransactionManager(final TransactionType transactionType) {
ShardingTransactionManager result = transactionManagerMap.get(transactionType);
if (TransactionType.LOCAL != transactionType) {
Preconditions.checkNotNull(result, "Cannot find transaction manager of [%s]", transactionType);
}
return result;
}
然后通过getTransactionManager方法最后返回ShardingTransactionManager类作为封装好的事务管理器。
到这里可以看到初始化ShardingTransactionManager的方法已经结束了。
XATransactionManager初探
XATransactionManager是 ShardingSphere负责管理xa服务的类,它继承了 TypedSPI 。
/**
* Typed SPI.
*/
public interface TypedSPI {
/**
* Get type.
*
* @return type
*/
String getType();
/**
* Get properties.
*
* @return properties
*/
default Properties getProps() {
return new Properties();
}
/**
* Set properties.
*
* @param props properties
*/
default void setProps(final Properties props) {
}
}
TypedSPI可以视为sharing 的基础spi,基本上所有的spi接口都继承了这个基础接口,这个接口的内容主要包含 getType()获得类型,getProps()获得配置文件和setProps( Properties props)设置配置文件.
public interface XATransactionManager extends AutoCloseable, TypedSPI {
/**
* Initialize XA transaction manager.
*/
void init();
/**
* Register recovery resource.
*
* @param dataSourceName data source name
* @param xaDataSource XA data source
*/
void registerRecoveryResource(String dataSourceName, XADataSource xaDataSource);
/**
* Remove recovery resource.
*
* @param dataSourceName data source name
* @param xaDataSource XA data source
*/
void removeRecoveryResource(String dataSourceName, XADataSource xaDataSource);
/**
* Enlist single XA resource.
*
* @param singleXAResource single XA resource
*/
void enlistResource(SingleXAResource singleXAResource);
/**
* Get transaction manager.
*
* @return transaction manager
*/
TransactionManager getTransactionManager();
}
xa接口的实现类有三种, atomikos分布式事务 ,Bitronix分布式事务 还有narayana分布式事务
XATransactionManager提炼出了jta事务Manager的通用的五个实现:
init()初始化 ,registerRecoveryResource注册事务恢复资源,removeRecoveryResource 废弃事务恢复资源 ,enlistResource 登记单个xa事务 ,getTransactionManager 获得事务manager资源。
以bitronix作为例子,XATransactionManager的init方法直接调用bitronix.tm.TransactionManagerServices的初始化getTransactionManager
@Override
public void init() {
bitronixTransactionManager = TransactionManagerServices.getTransactionManager();
}
@SneakyThrows(RecoveryException.class)
@Override
public void registerRecoveryResource(final String dataSourceName, final XADataSource xaDataSource) {
ResourceRegistrar.register(new BitronixRecoveryResource(dataSourceName, xaDataSource));
}
然后调用registerRecoveryResource 获取了xa事务的manager。而这些方法都是XATransactionDataSource 的初始化方法。
public XATransactionDataSource(final DatabaseType databaseType, final String resourceName, final DataSource dataSource, final XATransactionManager xaTransactionManager) {
this.databaseType = databaseType;
this.resourceName = resourceName;
this.dataSource = dataSource;
if (!CONTAINER_DATASOURCE_NAMES.contains(dataSource.getClass().getSimpleName())) {
xaDataSource = XADataSourceFactory.build(databaseType, dataSource);
this.xaTransactionManager = xaTransactionManager;
xaTransactionManager.registerRecoveryResource(resourceName, xaDataSource);
}
}
小结
本次分析首先讨论了xa事务的一些特性和 xa事务在 sharding-spare中的 基础管理类XAShardingTransactionManager 。在sharing的代码里首先我们可以看到无处不在的adapter和Factory 类,统一进行adapter对代码的健壮性是极强的提升,同时把很多具有相同特性代码相似的部分进行提炼和归并,也可以极大的提升代码的质量,也让代码的可理解性得到了极大的提升。同时也可以让阅读代码的人一法通,万法通,可以在较短的时间内读懂最多的代码。