分布式事务框架(seata1.5.0)源码分析-通信模型

本文详细解析了Seata框架中Client端RM/TM的初始化过程,以及TM/RM如何通过NettyClientChannelManager进行Channel注册、报文编码解码、请求发送与响应接收的机制。同时概述了Server端TC的启动流程和通信处理策略。
摘要由CSDN通过智能技术生成

目录

Client端

TM / RM初始化

TM / RM注册Channel

NettyClientChannelManager

seata报文传输协议

解码-ProtocolV1Decoder

编码-ProtocolV1Encoder

TM / RM发送请求

TM / RM接收请求/响应

Server端

TC浅析


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
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值