目录
Client端
TM / RM初始化
我们以RMClient为例,分析客户端的初始化、请求发送,请求/响应接收,从代码的角度来讲,TM和RM只是处理的请求对象不同,还有就是TM注册和RM注册存在细微差异,其他逻辑基本一致。
来到入口类GlobalTransactionScanner的afterPropertiesSet方法,这个方法在spring初始化GlobalTransactionScanner这个bean的时候会被调用。
public class GlobalTransactionScanner extends AbstractAutoProxyCreator
implements ConfigurationChangeListener, InitializingBean, ApplicationContextAware, DisposableBean {
@Override
public void afterPropertiesSet() {
if (disableGlobalTransaction) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global transaction is disabled.");
}
ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
(ConfigurationChangeListener)this);
return;
}
if (initialized.compareAndSet(false, true)) {
//初始化客户端
initClient();
}
}
private void initClient() {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Initializing Global Transaction Clients ... ");
}
if (DEFAULT_TX_GROUP_OLD.equals(txServiceGroup)) {
LOGGER.warn("the default value of seata.tx-service-group: {} has already changed to {} since Seata 1.5, " +
"please change your default configuration as soon as possible " +
"and we don't recommend you to use default tx-service-group's value provided by seata",
DEFAULT_TX_GROUP_OLD, DEFAULT_TX_GROUP);
}
if (StringUtils.isNullOrEmpty(applicationId) || StringUtils.isNullOrEmpty(txServiceGroup)) {
throw new IllegalArgumentException(String.format("applicationId: %s, txServiceGroup: %s", applicationId, txServiceGroup));
}
//TM 初始化
TMClient.init(applicationId, txServiceGroup, accessKey, secretKey);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Transaction Manager Client is initialized. applicationId[{}] txServiceGroup[{}]", applicationId, txServiceGroup);
}
//RM 初始化
RMClient.init(applicationId, txServiceGroup);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Resource Manager is initialized. applicationId[{}] txServiceGroup[{}]", applicationId, txServiceGroup);
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global Transaction Clients are initialized. ");
}
registerSpringShutdownHook();
}
}
RmNettyRemotingClient(RM)和TmNettyRemotingClient(TM)都继承自AbstractNettyRemotingClient。
public class RMClient {
public static void init(String applicationId, String transactionServiceGroup) {
// 创建RmNettyRemotingClient对象与TC进行通信
RmNettyRemotingClient rmNettyRemotingClient = RmNettyRemotingClient.getInstance(applicationId, transactionServiceGroup);
// 设置RM资源管理器DefaultResourceManager
rmNettyRemotingClient.setResourceManager(DefaultResourceManager.get());
// 设置RM消息处理器,接收TC发起的分支请求
rmNettyRemotingClient.setTransactionMessageHandler(DefaultRMHandler.get());
// 初始化
rmNettyRemotingClient.init();
}
}
public final class RmNettyRemotingClient extends AbstractNettyRemotingClient {
@Override
public void init() {
// 这里很重要,根据请求和响应的类型注册各自的处理器,处理器分2类:
// 第1种:对TC发起的请求作响应的处理。RmBranchCommitProcessor、RmBranchRollbackProcessor、RmUndoLogProcessor
// 第2种:对RM请求TC后,接收TC返回的响应作处理。ClientOnResponseProcessor、ClientHeartbeatProcessor
registerProcessor();
if (initialized.compareAndSet(false, true)) {
// 接着往父类看
super.init();
// Found one or more resources that were registered before initialization
// 如果已经有分支注册到了resourceManager中,向TC发起RM注册,RM 通过channel与TC服务端建立连接,若未连接过,会开启一个channel(开启RM通信端口)
// 由于此时还未完成初始化,所以一般不会走这段逻辑
if (resourceManager != null
&& !resourceManager.getManagedResources().isEmpty()
&& StringUtils.isNotBlank(transactionServiceGroup)) {
getClientChannelManager().reconnect(transactionServiceGroup);
}
}
}
}
RmNettyRemotingClient装载了2个对象:
- DefaultResourceManager:管理注册好的所有分支事务
- DefaultRMHandler:处理分支事务注册、提交、回滚请求
再来看下父类的构造方法
public abstract class AbstractNettyRemotingClient extends AbstractNettyRemoting implements RemotingClient {
public AbstractNettyRemotingClient(NettyClientConfig nettyClientConfig, EventExecutorGroup eventExecutorGroup,
ThreadPoolExecutor messageExecutor, NettyPoolKey.TransactionRole transactionRole) {
super(messageExecutor);
// 角色:RM
this.transactionRole = transactionRole;
// netty客户端
clientBootstrap = new NettyClientBootstrap(nettyClientConfig, eventExecutorGroup, transactionRole);
// 这个handler很重要,netty都是将请求委托给handler进行处理。也就是说RM收到的请求,最后会到ClientHandler中处理
clientBootstrap.setChannelHandlers(new ClientHandler());
// NettyClientChannelManager:netty通信管道管理器
// getPoolKeyFunction():根据TC server端地址组装 RM注册请求,server端不同的机器对应不同的NettyPoolKey
clientChannelManager = new NettyClientChannelManager(
new NettyPoolableFactory(this, clientBootstrap), getPoolKeyFunction(), nettyClientConfig);
}
}
public final class RmNettyRemotingClient extends AbstractNettyRemotingClient {
@Override
protected Function<String, NettyPoolKey> getPoolKeyFunction() {
return serverAddress -> {
// 获取所有已注册的resourceId用“,”隔开,拼接成字符串
String resourceIds = getMergedResourceKeys();
if (resourceIds != null && LOGGER.isInfoEnabled()) {
LOGGER.info("RM will register :{}", resourceIds);
}
// 组装成RM注册请求对象
RegisterRMRequest message = new RegisterRMRequest(applicationId, transactionServiceGroup);
message.setResourceIds(resourceIds);
// 保装成NettyPoolKey
return new NettyPoolKey(NettyPoolKey.TransactionRole.RMROLE, serverAddress, message);
};
}
}
netty都是将请求委托给handler进行处理。其实TC向RM/TM发送的请求最后都会到ClientHandler中进行处理,这个我们后面再看。
TM / RM注册Channel
NettyClientChannelManager
这里还有个特殊的类:NettyClientChannelManager,Client端有2种通信角色,RM和TM。它们两个都要向TC注册,并保持连接。NettyClientChannelManager就是用来管理他们两个产生的Channel通道,当前的角色是RM,那就是管理RM相关信息,TM同理。
class NettyClientChannelManager {
/**
* 支持按serverAddress维度加锁(synchronized)
*/
private final ConcurrentMap<String, Object> channelLocks = new ConcurrentHashMap<>();
/**
* 缓存了 serverAddress >> NettyPoolKey的映射关系
*/
private final ConcurrentMap<String, NettyPoolKey> poolKeyMap = new ConcurrentHashMap<>();
/**
* 缓存了 serverAddress >> Channel的映射关系(与每台server建立的连接通道)
*/
private final ConcurrentMap<String, Channel> channels = new ConcurrentHashMap<>();
/**
* 缓存池包装对象,与NettyPoolableFactory配合创建channel,并缓存NettyPoolKey >> Channel映射关系
*/
private final GenericKeyedObjectPool<NettyPoolKey, Channel> nettyClientKeyPool;
/**
* 根据 serverAddress 创建RM/TM请求对象
*/
private Function<String, NettyPoolKey> poolKeyFunction;
NettyClientChannelManager(final NettyPoolableFactory keyPoolableFactory, final Function<String, NettyPoolKey> poolKeyFunction,
final NettyClientConfig clientConfig) {
// keyPoolableFactory 很重要,真正建立channel的地方
nettyClientKeyPool = new GenericKeyedObjectPool<>(keyPoolableFactory);
nettyClientKeyPool.setConfig(getNettyPoolConfig(clientConfig));
this.poolKeyFunction = poolKeyFunction;
}
/**
* Acquire netty client channel connected to remote server.
* 获取server端地址对应的channel对象,连接server端
* @param serverAddress server address
* @return netty channel
*/
Channel acquireChannel(String serverAddress) {
Channel channelToServer = channels.get(serverAddress);
if (channelToServer != null) {
channelToServer = getExistAliveChannel(channelToServer, serverAddress);
if (channelToServer != null) {
return channelToServer;
}
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("will connect to {}", serverAddress);
}
Object lockObj = CollectionUtils.computeIfAbsent(channelLocks, serverAddress, key -> new Object());
synchronized (lockObj) {
//建立建立
return doConnect(serverAddress);
}
}
/**
* Reconnect to remote server of current transaction service group.
* 与server端重连
* @param transactionServiceGroup transaction service group
*/
void reconnect(String transactionServiceGroup) {
List<String> availList = null;
try {
// 从注册中心拉取server端地址
availList = getAvailServerList(transactionServiceGroup);
} catch (Exception e) {
LOGGER.error("Failed to get available servers: {}", e.getMessage(), e);
return;
}
// 日志打印
if (CollectionUtils.isEmpty(availList)) {
RegistryService registryService = RegistryFactory.getInstance();
String clusterName = registryService.getServiceGroup(transactionServiceGroup);
if (StringUtils.isBlank(clusterName)) {
LOGGER.error("can not get cluster name in registry config '{}{}', please make sure registry config correct",
ConfigurationKeys.SERVICE_GROUP_MAPPING_PREFIX,
transactionServiceGroup);
return;
}
if (!(registryService instanceof FileRegistryServiceImpl)) {
LOGGER.error("no available service found in cluster '{}', please make sure registry config correct and keep your seata server running", clusterName);
}
return;
}
Set<String> channelAddress = new HashSet<>(availList.size());
try {
// 与server端的每个实例建立连接
for (String serverAddress : availList) {
try {
acquireChannel(serverAddress);
channelAddress.add(serverAddress);
} catch (Exception e) {
LOGGER.error("{} can not connect to {} cause:{}", FrameworkErrorCode.NetConnect.getErrCode(),
serverAddress, e.getMessage(), e);
}
}
} finally {
if (CollectionUtils.isNotEmpty(channelAddress)) {
List<InetSocketAddress> aliveAddress = new ArrayList<>(channelAddress.size());
for (String address : channelAddress) {
String[] array = address.split(":");
aliveAddress.add(new InetSocketAddress(array[0], Integer.parseInt(array[1])));
}
RegistryFactory.getInstance().refreshAliveLookup(transactionServiceGroup, aliveAddress);
} else {
RegistryFactory.getInstance().refreshAliveLookup(transactionServiceGroup, Collections.emptyList());
}
}
}
private Channel doConnect(String serverAddress) {
// 通过serverAddress尝试从缓存中获取channel
Channel channelToServer = channels.get(serverAddress);
// 检活
if (channelToServer != null && channelToServer.isActive()) {
return channelToServer;
}
Channel channelFromPool;
try {
// 创建TM/RM注册请求对象
NettyPoolKey currentPoolKey = poolKeyFunction.apply(serverAddress);
// 如果是TM注册请求
if (currentPoolKey.getMessage() instanceof RegisterTMRequest) {
// 保存TM serverAddress >> NettyPoolKey映射关系
poolKeyMap.put(serverAddress, currentPoolKey);
} else {// RM注册请求
// 保存RM serverAddress >> NettyPoolKey映射关系
NettyPoolKey previousPoolKey = poolKeyMap.putIfAbsent(serverAddress, currentPoolKey);
if (previousPoolKey != null && previousPoolKey.getMessage() instanceof RegisterRMRequest) {
// 更新RegisterRMRequest中的resourceId
RegisterRMRequest registerRMRequest = (RegisterRMRequest) currentPoolKey.getMessage();
((RegisterRMRequest) previousPoolKey.getMessage()).setResourceIds(registerRMRequest.getResourceIds());
}
}
// 还未建立过channel,创建channel通道
channelFromPool = nettyClientKeyPool.borrowObject(poolKeyMap.get(serverAddress));
channels.put(serverAddress, channelFromPool);
} catch (Exception exx) {
LOGGER.error("{} register RM failed.", FrameworkErrorCode.RegisterRM.getErrCode(), exx);
throw new FrameworkException("can not register RM,err:" + exx.getMessage());
}
return channelFromPool;
}
/**
* 从注册中心,拉取服务端可用的TC server端地址
* @param transactionServiceGroup
* @return
* @throws Exception
*/
private List<String> getAvailServerList(String transactionServiceGroup) throws Exception {
List<InetSocketAddress> availInetSocketAddressList = RegistryFactory.getInstance()
.lookup(transactionServiceGroup);
if (CollectionUtils.isEmpty(availInetSocketAddressList)) {
return Collections.emptyList();
}
return availInetSocketAddressList.stream()
.map(NetUtil::toStringAddress)
.collect(Collectors.toList());
}
/**
* 从缓存中获取存活的channel
* @param rmChannel
* @param serverAddress
* @return
*/
private Channel getExistAliveChannel(Channel rmChannel, String serverAddress) {
if (rmChannel.isActive()) {
return rmChannel;
} else {
int i = 0;
for (; i < NettyClientConfig.getMaxCheckAliveRetry(); i++) {
try {
Thread.sleep(NettyClientConfig.getCheckAliveInterval());
} catch (InterruptedException exx) {
LOGGER.error(exx.getMessage());
}
rmChannel = channels.get(serverAddress);
if (rmChannel != null && rmChannel.isActive()) {
return rmChannel;
}
}
if (i == NettyClientConf