分布式事务框架TX-LCN(三)TM启动流程

TM启动流程

TM启动初始化,执行下面的TxLcnInitializer类实现,并且调用初始化方法:
在这里插入图片描述

TMRpcServer

TMRpcServer的init方法,这个方法主要是调用rpcServerInitializer的init方法:

@Override
public void init() {
    // 1. 配置
    if (rpcConfig.getWaitTime() <= 5) {
        rpcConfig.setWaitTime(1000);
    }
    if (rpcConfig.getAttrDelayTime() < 0) {
        rpcConfig.setAttrDelayTime(txManagerConfig.getDtxTime());
    }

    // 2. 初始化RPC Server
    ManagerProperties managerProperties = new ManagerProperties();
    managerProperties.setCheckTime(txManagerConfig.getHeartTime());
    // 默认127.0.0.1
    managerProperties.setRpcPort(txManagerConfig.getPort());
    // 默认8070   因为application.properties中server.port=7970
    managerProperties.setRpcHost(txManagerConfig.getHost());
    rpcServerInitializer.init(managerProperties);
}

上面的txManagerConfig.getPort()是由application.properties中server.port + 100 取得,代码如下:

@Autowired
public TxManagerConfig(ServerProperties serverProperties) {
    this.port = Objects.requireNonNull(serverProperties.getPort(), "TM http port not configured?") +
            PORT_CHANGE_VALUE;
}

再重新回过头看一下rpcServerInitializer的init方法,启动netty server端,监听ip:8070端口默认。代码如下:

@Override
public void init(ManagerProperties managerProperties) {
    NettyContext.type = NettyType.server;
    NettyContext.params = managerProperties;

    nettyRpcServerChannelInitializer.setManagerProperties(managerProperties);

    int port = managerProperties.getRpcPort();
    bossGroup = new NioEventLoopGroup();
    workerGroup = new NioEventLoopGroup();
    try {
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 100)
                .handler(new LoggingHandler(LogLevel.INFO))
                // netty server的handler  主要处理逻辑在这里
                .childHandler(nettyRpcServerChannelInitializer);

        // 启动netty server监听.
        if (StringUtils.hasText(managerProperties.getRpcHost())) {
            b.bind(managerProperties.getRpcHost(), managerProperties.getRpcPort());
        } else {
            b.bind(port);
        }
        log.info("Socket started on {}:{} ",
                StringUtils.hasText(managerProperties.getRpcHost()) ? managerProperties.getRpcHost() : "0.0.0.0", port);

    } catch (Exception e) {
        // Shut down all event loops to terminate all threads.
        e.printStackTrace();
    }
}

学习一下ChannelInitializer
https://www.cnblogs.com/stevenczp/p/7597903.html
https://www.jianshu.com/p/7ae37f4c1f14

接下来看一下NettyRpcServerChannelInitializer类:

@Component
public class NettyRpcServerChannelInitializer extends ChannelInitializer<Channel> {

    @Autowired
    private RpcAnswerHandler rpcAnswerHandler;

    @Autowired
    private SocketManagerInitHandler socketManagerInitHandler;

    @Autowired
    private RpcCmdDecoder rpcCmdDecoder;


    private ManagerProperties managerProperties;

    public void setManagerProperties(ManagerProperties managerProperties) {
        this.managerProperties = managerProperties;
    }

    @Override
    protected void initChannel(Channel ch) throws Exception {
        // 解决半包 黏包问题
        ch.pipeline().addLast(new LengthFieldPrepender(4, false));
        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));

		// 心跳监控
        ch.pipeline().addLast(new IdleStateHandler(managerProperties.getCheckTime(),
                managerProperties.getCheckTime(), managerProperties.getCheckTime(), TimeUnit.MILLISECONDS));

		// 序列化对象编解码
        ch.pipeline().addLast(new ObjectSerializerEncoder());
        ch.pipeline().addLast(new ObjectSerializerDecoder());

		// TM实现的ChannelHandler
        ch.pipeline().addLast(rpcCmdDecoder);
        ch.pipeline().addLast(new RpcCmdEncoder());
        ch.pipeline().addLast(socketManagerInitHandler);
        ch.pipeline().addLast(rpcAnswerHandler);
    }
}

TMAutoCluster

@Override
public void init() throws Exception {

    // 1. 通知 TC 建立连接
    List<TMProperties> tmList = fastStorage.findTMProperties().stream()
            .filter(tmProperties ->
                    !tmProperties.getHost().equals(txManagerConfig.getHost()) || !tmProperties.getTransactionPort().equals(txManagerConfig.getPort()))
            .collect(Collectors.toList());
    for (TMProperties properties : tmList) {
    	// 封装NotifyConnectParams 把自己的ip和port设置进去,传给已存在TM节点处理
        NotifyConnectParams notifyConnectParams = new NotifyConnectParams();
        notifyConnectParams.setHost(txManagerConfig.getHost());
        notifyConnectParams.setPort(txManagerConfig.getPort());
        String url = String.format(MANAGER_REFRESH_URL, properties.getHost(), properties.getHttpPort());
        try {
            ResponseEntity<Boolean> res = restTemplate.postForEntity(url, notifyConnectParams, Boolean.class);
            if (res.getStatusCode().equals(HttpStatus.OK) || res.getStatusCode().is5xxServerError()) {
                log.info("manager auto refresh res->{}", res);
                break;
            } else {
                fastStorage.removeTMProperties(properties.getHost(), properties.getTransactionPort());
            }
        } catch (Exception e) {
            log.error("manager auto refresh error: {}", e.getMessage());
            //check exception then remove.
            if (e instanceof ResourceAccessException) {
                ResourceAccessException resourceAccessException = (ResourceAccessException) e;
                if (resourceAccessException.getCause() != null && resourceAccessException.getCause() instanceof ConnectException) {
                    //can't access .
                    fastStorage.removeTMProperties(properties.getHost(), properties.getTransactionPort());
                }
            }
        }
    }

    // 2. 保存TM 到快速存储
    if (StringUtils.hasText(txManagerConfig.getHost())) {
        TMProperties tmProperties = new TMProperties();
        tmProperties.setHttpPort(ApplicationInformation.serverPort(serverProperties));
        tmProperties.setHost(txManagerConfig.getHost());
        tmProperties.setTransactionPort(txManagerConfig.getPort());
        fastStorage.saveTMProperties(tmProperties);
    }
}

当前TM(A服务)启动成功,通过redis缓存TMProperties信息快照,当下一个TM节点(B服务)启动的时候,就会循环存储的TM配置快照信息(A服务)发送(B服务的连接信息)让A服务通知已经与之相连TC端Channel与B服务进行连接,达到了如果新增TM节点,无需重新配置TM的连接信息,重新启动。通过RestTemplate http调用,拼接url=http://%s:%s/manager/refresh,我们查看一下这个rest接口代码:

@RestController
@RequestMapping("/manager")
public class TxManagerController {
    @Autowired
    private ManagerService managerService;

    @PostMapping("/refresh")
    public boolean refresh(@RequestBody NotifyConnectParams notifyConnectParams) throws RpcException {
        return managerService.refresh(notifyConnectParams);
    }
}

// service方法
@Override
public boolean refresh(NotifyConnectParams notifyConnectParams) throws RpcException {
     List<String> keys = rpcClient.loadAllRemoteKey();
     if (keys != null && keys.size() > 0) {
         for (String key : keys) {
         	 // 通知所有与之连接的Tc端连接新TM节点
             rpcClient.send(key, MessageCreator.newTxManager(notifyConnectParams));
         }
     }
     return true;
 }

@Override
public RpcResponseState send(String remoteKey, MessageDto msg) throws RpcException {
    RpcCmd rpcCmd = new NettyRpcCmd();
    rpcCmd.setMsg(msg);
    rpcCmd.setRemoteKey(remoteKey);
    return send(rpcCmd);
}

@Override
public RpcResponseState send(RpcCmd rpcCmd) throws RpcException {
    return SocketManager.getInstance().send(rpcCmd.getRemoteKey(), rpcCmd);
}

待完善…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值