seata server启动源码

版本:1.2.0

Seata主要包括三大组件:TC、TM和RM。TC(Transaction Coordinator)主要负责全局事务的提交和回滚,是seata的关键组件。对可用性及性能都有着较高的要求。

seata TC实现源码Server的各个包:

  • coordinator:协调器核心模块
  • event:事件管理模块
  • lock:资源锁模块
  • metrics: metrics指标模块
  • session:session通信模块
  • storage:事务信息存储模块,file和DB
  • store:存储配置模块
  • transaction:事务模块

Server启动流程

server启动的入口是Server.main方法

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     * @throws IOException the io exception
     */
    public static void main(String[] args) throws IOException {
        //初始化参数解析器
        ParameterParser parameterParser = new ParameterParser(args);

        //初始化度量指标metrics
        MetricsManager.get().init();
        //设置日志存储模式 file/Db
        System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());
        //创建nettyserver
        RpcServer rpcServer = new RpcServer(WORKING_THREADS);
        //server port
        rpcServer.setListenPort(parameterParser.getPort());
        UUIDGenerator.init(parameterParser.getServerNode());
        //sessionholder 初始化
        SessionHolder.init(parameterParser.getStoreMode());
        //创建默认协调器
        DefaultCoordinator coordinator = new DefaultCoordinator(rpcServer);
        coordinator.init();
        rpcServer.setHandler(coordinator);
        // 注册关闭钩子
        ShutdownHook.getInstance().addDisposable(coordinator);
        ShutdownHook.getInstance().addDisposable(rpcServer);

        //127.0.0.1 and 0.0.0.0 are not valid here.
        if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
            XID.setIpAddress(parameterParser.getHost());
        } else {
            XID.setIpAddress(NetUtil.getLocalIp());
        }
        XID.setPort(rpcServer.getListenPort());

        try {
            //启动
            rpcServer.init();
        } catch (Throwable e) {
            LOGGER.error("rpcServer init error:{}", e.getMessage(), e);
            System.exit(-1);
        }

        System.exit(0);
    }

主要流程:

  • 1.解析启动参数
  • 2.初始化度量
  • 3.初始化netty server
  • 4.初始化sessionholder
  • 5.初始化默认协调器
  • 6.启动netty server
参数解析

ParameterParser parameterParser = new ParameterParser(args);

    public ParameterParser(String[] args) {
        this.init(args);
    }

    private void init(String[] args) {
        try {
            boolean inContainer = this.isRunningInContainer();
            //判断是否使用了容器Kubernetes/docker
            if (inContainer) {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("The server is running in container.");
                }
                //多配置环境
                this.seataEnv = StringUtils.trimToNull(System.getenv(ENV_SYSTEM_KEY));
                //host地址
                this.host = StringUtils.trimToNull(System.getenv(ENV_SEATA_IP_KEY));
                //server节点id
                this.serverNode = NumberUtils.toInt(System.getenv(ENV_SERVER_NODE_KEY), SERVER_DEFAULT_NODE);
                //端口号
                this.port = NumberUtils.toInt(System.getenv(ENV_SEATA_PORT_KEY), SERVER_DEFAULT_PORT);
                //存储模式
                this.storeMode = StringUtils.trimToNull(System.getenv(ENV_STORE_MODE_KEY));
            } else {
                //JCommander 解析参数
                JCommander jCommander = JCommander.newBuilder().addObject(this).build();
                jCommander.parse(args);
                if (help) {
                    jCommander.setProgramName(PROGRAM_NAME);
                    jCommander.usage();
                    System.exit(0);
                }
            }
            if (StringUtils.isNotBlank(seataEnv)) {
                System.setProperty(ENV_PROPERTY_KEY, seataEnv);
            }
            if (StringUtils.isBlank(storeMode)) {
                storeMode = ConfigurationFactory.getInstance().getConfig(ConfigurationKeys.STORE_MODE,
                    SERVER_DEFAULT_STORE_MODE);
            }
        } catch (ParameterException e) {
            printError(e);
        }

    }

主要解析参数中的存储模式、环境配置,ip端口。

初始化server

RpcServer rpcServer = new RpcServer(WORKING_THREADS);

构造器初始化父类构造器

    public AbstractRpcRemotingServer(final ThreadPoolExecutor messageExecutor, NettyServerConfig nettyServerConfig) {
        super(messageExecutor);
        //初始化RpcServer
        serverBootstrap = new RpcServerBootstrap(nettyServerConfig);
    }

根据配置判断初始化EventLoopGroup

    public RpcServerBootstrap(NettyServerConfig nettyServerConfig) {

        this.nettyServerConfig = nettyServerConfig;
        //根据配置判断初始化根据配置判断初始化EventLoopGroup
        if (NettyServerConfig.enableEpoll()) {
            this.eventLoopGroupBoss = new EpollEventLoopGroup(nettyServerConfig.getBossThreadSize(),
                new NamedThreadFactory(nettyServerConfig.getBossThreadPrefix(), nettyServerConfig.getBossThreadSize()));
            this.eventLoopGroupWorker = new EpollEventLoopGroup(nettyServerConfig.getServerWorkerThreads(),
                new NamedThreadFactory(nettyServerConfig.getWorkerThreadPrefix(),
                    nettyServerConfig.getServerWorkerThreads()));
        } else {
            this.eventLoopGroupBoss = new NioEventLoopGroup(nettyServerConfig.getBossThreadSize(),
                new NamedThreadFactory(nettyServerConfig.getBossThreadPrefix(), nettyServerConfig.getBossThreadSize()));
            this.eventLoopGroupWorker = new NioEventLoopGroup(nettyServerConfig.getServerWorkerThreads(),
                new NamedThreadFactory(nettyServerConfig.getWorkerThreadPrefix(),
                    nettyServerConfig.getServerWorkerThreads()));
        }

        // 构造设置端口,防止端口为空
        setListenPort(nettyServerConfig.getDefaultListenPort());
    }
SessionHolder初始化

SessionHolder.init(parameterParser.getStoreMode());

根据持久化配置file/db,去初始化sessionManager 进行session管理和持久化,主要包括下面四种

  • ROOT_SESSION_MANAGER root session manager
  • ASYNC_COMMITTING_SESSION_MANAGER异步提交session manager
  • RETRY_COMMITTING_SESSION_MANAGER重试提交session manager
  • RETRY_ROLLBACKING_SESSION_MANAGER重试回滚session manager
    public static void init(String mode) throws IOException {
        if (StringUtils.isBlank(mode)) {
            mode = CONFIG.getConfig(ConfigurationKeys.STORE_MODE);
        }
        StoreMode storeMode = StoreMode.get(mode);
        //DB 方式
        if (StoreMode.DB.equals(storeMode)) {
            //初始化四种sessionmanager
            ...
        // File 方式
        } else if (StoreMode.FILE.equals(storeMode)) {
            //初始化四种sessionmanager
            ...
        } else {
            throw new IllegalArgumentException("unknown store mode:" + mode);
        }
        //reload是否需要进行回滚或提交
        //处理未完成的事务
        reload();
    }
TC协调器初始化

DefaultCoordinator coordinator = new DefaultCoordinator(rpcServer);
coordinator.init();

创建默认的TC协调器,并将server与其组合,主要看init方法

    public void init() {
        retryRollbacking.scheduleAtFixedRate(() -> {
            try {
                handleRetryRollbacking();
            } catch (Exception e) {
                LOGGER.info("Exception retry rollbacking ... ", e);
            }
        }, 0, ROLLBACKING_RETRY_PERIOD, TimeUnit.MILLISECONDS);

        retryCommitting.scheduleAtFixedRate(() -> {
            try {
                handleRetryCommitting();
            } catch (Exception e) {
                LOGGER.info("Exception retry committing ... ", e);
            }
        }, 0, COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS);

        asyncCommitting.scheduleAtFixedRate(() -> {
            try {
                handleAsyncCommitting();
            } catch (Exception e) {
                LOGGER.info("Exception async committing ... ", e);
            }
        }, 0, ASYNC_COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS);

        timeoutCheck.scheduleAtFixedRate(() -> {
            try {
                timeoutCheck();
            } catch (Exception e) {
                LOGGER.info("Exception timeout checking ... ", e);
            }
        }, 0, TIMEOUT_RETRY_PERIOD, TimeUnit.MILLISECONDS);

        undoLogDelete.scheduleAtFixedRate(() -> {
            try {
                undoLogDelete();
            } catch (Exception e) {
                LOGGER.info("Exception undoLog deleting ... ", e);
            }
        }, UNDO_LOG_DELAY_DELETE_PERIOD, UNDO_LOG_DELETE_PERIOD, TimeUnit.MILLISECONDS);
    }

init方法主要是添加定时任务,处理提交回滚删除日志等操作

启动server

rpcServer.init();

    public void init() {
        //实例化默认的服务消息监听器,包括事务消息、RM注册消息、TM注册消息、检查消息
        DefaultServerMessageListenerImpl defaultServerMessageListenerImpl =
            new DefaultServerMessageListenerImpl(getTransactionMessageHandler());
        //初始化日志处理线程池
        defaultServerMessageListenerImpl.init();
        defaultServerMessageListenerImpl.setServerMessageSender(this);
        super.setServerMessageListener(defaultServerMessageListenerImpl);
        //添加channelhandler
        super.setChannelHandlers(new ServerHandler());
        //核心方法
        super.init();
    }

进入init方法,AbstractRpcRemotingServer.init()

    public void init() {
        //启动超时消息定时任务
        super.init();
        //启动服务
        serverBootstrap.start();
    }

跟入serverBootstrap.start();,这里就是服务的初始化

    public void start() {
        //设置channel参数
        this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupWorker)
            .channel(nettyServerConfig.SERVER_CHANNEL_CLAZZ)
            .option(ChannelOption.SO_BACKLOG, nettyServerConfig.getSoBackLogSize())
            .option(ChannelOption.SO_REUSEADDR, true)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childOption(ChannelOption.TCP_NODELAY, true)
            .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSendBufSize())
            .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketResvBufSize())
            .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
                new WriteBufferWaterMark(nettyServerConfig.getWriteBufferLowWaterMark(),
                    nettyServerConfig.getWriteBufferHighWaterMark()))
            .localAddress(new InetSocketAddress(listenPort))
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) {
                    ch.pipeline().addLast(new IdleStateHandler(nettyServerConfig.getChannelMaxReadIdleSeconds(), 0, 0))
                        .addLast(new ProtocolV1Decoder())
                        .addLast(new ProtocolV1Encoder());
                    if (null != channelHandlers) {
                        addChannelPipelineLast(ch, channelHandlers);
                    }

                }
            });

        try {
            ChannelFuture future = this.serverBootstrap.bind(listenPort).sync();
            LOGGER.info("Server started ... ");
            //高可用注册
            RegistryFactory.getInstance().register(new InetSocketAddress(XID.getIpAddress(), XID.getPort()));
            initialized.set(true);
            future.channel().closeFuture().sync();
        } catch (Exception exx) {
            throw new RuntimeException(exx);
        }

    }

主要是netty参数的配置并启动,到这里也就完成了SeataServer的初始化及启动。通过seata-server的源码看出,其内部使用netty作为服务器,并且用到大量线程池和定时任务去提高性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以通过以下步骤下载 seata server 1.5 的源码: 1. 打开你的浏览器,访问 seata 官方的 GitHub 仓库网址:https://github.com/seata/seata 2. 在仓库首页上可以看到一个绿色的按钮,上面写着 "Code",点击这个按钮。 3. 在弹出的菜单中,你可以选择 "Download ZIP" 。点击这个选项后,会自动下载一个 ZIP 压缩文件。 4. 把下载的 ZIP 文件解压到你想要保存源码的位置。 5. 解压后你会得到一个名为 "seata-seata-1.5" 的文件夹,进入该文件夹。 6. 在该文件夹中,你可以找到 seata server 1.5 的所有源码文件。 通过这样的步骤,你就可以成功地下载并获取 seata server 1.5 的源码。希望对你有帮助! ### 回答2: 要下载Seata Server 1.5的源码,可以按照以下步骤进行: 1. 打开Seata的官方仓库:https://github.com/seata/seata 2. 在页面上方可以看到一个绿色的按钮,上面写着"Code",点击这个按钮。 3. 点击后,会弹出一个下拉菜单,选择"Download ZIP"选项。 4. 选择"Download ZIP"后,浏览器会自动开始下载一个名为"seata-master.zip"的压缩文件。 5. 下载完成后,解压缩该压缩文件到你想要保存Seata Server源码的文件夹。 这样就成功下载并解压缩了Seata Server 1.5的源码。你可以进入解压缩后的文件夹,开始查看和修改源代码进行自己的开发。 ### 回答3: 要下载 seata server 1.5 的源码,可以按照以下步骤进行: 1. 打开 seata 的官方网站。可以通过搜索引擎输入 "seata 官方网站" 来找到相应的链接。 2. 进入官方网站后,查找 "Downloads" 或者 "下载" 相关的选项,并点击进入。 3. 在下载页面中,找到 seata server 1.5 版本对应的源码下载链接。通常会有不同的源码格式可供选择,比如 zip、tar.gz 等。 4. 点击源码下载链接,开始下载 seata server 1.5 的源码压缩包。 5. 下载完成后,解压源码压缩包到指定的文件夹中。可以使用常见的解压软件,如 WinRAR、7-Zip 等。 6. 打开解压后的源码文件夹,可以查看到 seata server 1.5 的所有源代码文件。 7. 根据需要,可以使用开发工具(如 IntelliJ IDEA、Eclipse 等)来导入源码,并进行源码分析、修改或编译等操作。 通过以上步骤,可以成功下载 seata server 1.5 的源码,并进行后续的开发或学习工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值