[Интерпретация исходного кода Seata распределенной транзакции 1] Процесс запуска на стороне сервера

Основные моменты реализации распределенных транзакций:

  1. Необходимо сохранять устойчивость транзакции, различные состояния транзакции, различные состояния участников транзакции, когда экземпляр не работает, транзакцию можно откатить или отправить на основе постоянных данных для достижения максимальной согласованности.
  2. Временная обработка незавершенных транзакций с течением времени (продолжение попыток фиксации или отката), то есть достижение окончательной согласованности транзакции с помощью механизма повтора.
  3. Распространение распределенных транзакций между экземплярами служб. Когда распределенные транзакции охватывают несколько экземпляров, необходимо реализовать распространение транзакций. Как правило, необходимо адаптировать различные структуры rpc.
  4. Уровень изоляции транзакции: для большинства распределенных транзакций для повышения производительности уровень изоляции по умолчанию считывается незафиксированным.
  5. Идемпотентность: для распределенных транзакций, таких как XA или seata AT, идемпотентность реализована по умолчанию, в то время как распределенные транзакции, реализованные на уровне интерфейса TCC и Saga, требуют от бизнес-разработчиков реализации идемпотентности. Секс.

Эта статья в основном знакомит с исходным кодом seata-server с точки зрения процесса запуска seata-server. Блок-схема запуска выглядит следующим образом:

Вставьте описание изображения сюда

1. Запустите сервер класса

Входной класс seata-server находится в классе Server. Исходный код выглядит следующим образом:

public static void main(String[] args) throws IOException {
    // 从环境变量或运行时参数中获取监听端口,默认端口8091
    int port = PortHelper.getPort(args);
    
    // 把监听端口设置到SystemProperty中,Logback的LoggerContextListener实现类
    // SystemPropertyLoggerContextListener会把Port写入到Logback的Context中,
    // 在logback.xml文件中会使用Port变量来构建日志文件名称。
    System.setProperty(ConfigurationKeys.SERVER_PORT, Integer.toString(port));

    // 创建Logger
    final Logger logger = LoggerFactory.getLogger(Server.class);
    if (ContainerHelper.isRunningInContainer()) {
        logger.info("The server is running in container.");
    }

    // 解析启动以及配置文件的各种配置参数
    ParameterParser parameterParser = new ParameterParser(args);

    // metrics相关,这里是使用SPI机制获取Registry实例对象
    MetricsManager.get().init();
    
	// 把从配置文件中读取到的storeMode写入SystemProperty中,方便其他类使用。
    System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());
    
	// 创建NettyRemotingServer实例,NettyRemotingServer是一个基于Netty实现的Rpc框架,
	// 此时并没有初始化,NettyRemotingServer负责与客户端SDK中的TM、RM进行网络通信。
     nettyRemotingServer = new NettyRemotingServer(WORKING_THREADS);
    
    // 设置监听端口
    nettyRemotingServer.setListenPort(parameterParser.getPort());
    
	// UUIDGenerator初始化,UUIDGenerator基于雪花算法实现,
	// 用于生成全局事务、分支事务的id。
	// 多个Server实例配置不同的ServerNode,保证id的唯一性
    UUIDGenerator.init(parameterParser.getServerNode());
    
	// SessionHodler负责事务日志(状态)的持久化存储,
	// 当前支持file、db、redis三种存储模式,集群部署模式要使用db或redis模式
    SessionHolder.init(parameterParser.getStoreMode());
    
  	// 创建初始化DefaultCoordinator实例,DefaultCoordinator是TC的核心事务逻辑处理类,
  	// 底层包含了AT、TCC、SAGA等不同事务类型的逻辑处理。
    DefaultCoordinator coordinator = new DefaultCoordinator(nettyRemotingServer);
    coordinator.init();
    nettyRemotingServer.setHandler(coordinator);
    // register ShutdownHook
    ShutdownHook.getInstance().addDisposable(coordinator);
    ShutdownHook.getInstance().addDisposable(nettyRemotingServer);

    // 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(nettyRemotingServer.getListenPort());

    try {
        // 初始化Netty,开始监听端口并阻塞在这里,等待程序关闭
        nettyRemotingServer.init();
    } catch (Throwable e) {
        logger.error("nettyServer init error:{}", e.getMessage(), e);
        System.exit(-1);
    }

    System.exit(0);
}

2. Разберите конфигурацию

Код реализации анализа параметров находится в классе ParameterParser, а исходный код метода инициализации выглядит следующим образом:

private void init(String[] args) {
   try {
   	   // 判断是否运行在容器中,如果运行在容器中则配置从环境变量中获取
       if (ContainerHelper.isRunningInContainer()) {
           this.seataEnv = ContainerHelper.getEnv();
           this.host = ContainerHelper.getHost();
           this.port = ContainerHelper.getPort();
           this.serverNode = ContainerHelper.getServerNode();
           this.storeMode = ContainerHelper.getStoreMode();
       } else {
           // 基于JCommander获取启动应用程序时配置的参数,
           // JCommander通过注解、反射的方式把参数赋值到当前类的字段上。
           JCommander jCommander = JCommander.newBuilder().addObject(this).build();
           jCommander.parse(args);
           if (help) {
               jCommander.setProgramName(PROGRAM_NAME);
               jCommander.usage();
               System.exit(0);
           }
       }
       // serverNode用于雪花算中的实例的唯一标识,需要保证唯一。
       // 如果没有指定基于当前服务器的I随机生成一个
       if (this.serverNode == null) {
           this.serverNode = IdWorker.initWorkerId();
       }
       if (StringUtils.isNotBlank(seataEnv)) {
           System.setProperty(ENV_PROPERTY_KEY, seataEnv);
       }
       if (StringUtils.isBlank(storeMode)) {
           // 这里牵扯到一个重要的Configuration类,ParameterParser只负责获取ip、port、storeMode等核心参数,
           // 其他的参数都是从Configuration中获取的。这里如果没有启动参数没有指定storeMode,
           // 就从Configuration类中获取。
           storeMode = ConfigurationFactory.getInstance().getConfig(ConfigurationKeys.STORE_MODE,
               SERVER_DEFAULT_STORE_MODE);
       }
   } catch (ParameterException e) {
       printError(e);
   }

}

ConfigurationFactory.getInstance () вызывается в первый раз в методе инициализации ParameterParser для инициализации одноэлементного объекта Configuration, а Configuration отвечает за инициализацию всей другой информации о параметрах конфигурации. Из исходного кода Seata Server мы видим два файла конфигурации file.conf и registry.conf. Так в чем разница между этими двумя файлами конфигурации? Оба файла необходимы? Продолжаем смотреть на код.

Метод ConfigurationFactory.getInstance фактически предназначен для получения одноэлементного объекта, ядро ​​находится в методе buildConfiguration, но перед методом buidlConfiguration сначала будет выполнен статический блок кода класса ConfigurationFactory.

// 获取Configuration的单例对象
public static Configuration getInstance() {
    if (instance == null) {
        synchronized (Configuration.class) {
            if (instance == null) {
                instance = buildConfiguration();
            }
        }
    }
    return instance;
}

// ConfigurationFactory的static代码块
static {
    // 获取配置文件的名称,默认为registry.conf
    String seataConfigName = System.getProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME);
    if (seataConfigName == null) {
        seataConfigName = System.getenv(ENV_SEATA_CONFIG_NAME);
    }
    if (seataConfigName == null) {
        seataConfigName = REGISTRY_CONF_PREFIX;
    }
    String envValue = System.getProperty(ENV_PROPERTY_KEY);
    if (envValue == null) {
        envValue = System.getenv(ENV_SYSTEM_KEY);
    }
    
    // 读取registry.conf文件的配置,构建基础的Configuration对象
    Configuration configuration = (envValue == null) ? new FileConfiguration(seataConfigName + REGISTRY_CONF_SUFFIX,
        false) : new FileConfiguration(seataConfigName + "-" + envValue + REGISTRY_CONF_SUFFIX, false);
    Configuration extConfiguration = null;
    try {
        // ExtConfigurationProvider当前只有一个SpringBootConfigurationProvider实现类
        // 用于支持客户端SDK SpringBoot的配置文件方式,对于Server端来说这段逻辑可以忽略。
        extConfiguration = EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("load Configuration:{}", extConfiguration == null ? configuration.getClass().getSimpleName()
                : extConfiguration.getClass().getSimpleName());
        }
    } catch (EnhancedServiceNotFoundException ignore) {

    } catch (Exception e) {
        LOGGER.error("failed to load extConfiguration:{}", e.getMessage(), e);
    }
    CURRENT_FILE_INSTANCE = extConfiguration == null ? configuration : extConfiguration;
}

Блок статического кода в ConfigurationFactory считывает информацию о конфигурации из registry.conf. Есть две информации о конфигурации в registry.conf , то реестр и источник конфигурации . Источник конфигурации используется , чтобы указать другие более детальные элементы конфигурации , такие как file.conf или другие источники конфигурации , такие как аполлон. Следовательно, необходим файл конфигурации registry.conf, а другие подробные источники конфигурации указаны в файле конфигурации registry.conf. Текущий источник конфигурации поддерживает файлы, zk, apollo, nacos, etcd3 и т. Д. Следовательно, файл file.conf не нужен. Содержимое файла file.conf будет считываться только в том случае, если в качестве источника конфигурации задан тип файла.

Затем buildConfiguration в ConfigurationFactory загружает дополнительные элементы конфигурации в соответствии с источником конфигурации, заданным в registry.conf.

private static Configuration buildConfiguration() {
    ConfigType configType;
    String configTypeName;
    try {
    	// 从registry.conf配置文件中读取config.type字段值,并解析为枚举ConfigType
        configTypeName = CURRENT_FILE_INSTANCE.getConfig(
            ConfigurationKeys.FILE_ROOT_CONFIG + ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR
                + ConfigurationKeys.FILE_ROOT_TYPE);

        if (StringUtils.isBlank(configTypeName)) {
            throw new NotSupportYetException("config type can not be null");
        }

        configType = ConfigType.getType(configTypeName);
    } catch (Exception e) {
        throw e;
    }
    Configuration extConfiguration = null;
    Configuration configuration;
    if (ConfigType.File == configType) {
    	// 如果配置文件为file类型,则从registry.conf中读取config.file.name配置项,
    	// 即file类型配置文件的路径,示例中默认为file.conf
        String pathDataId = String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR,
            ConfigurationKeys.FILE_ROOT_CONFIG, FILE_TYPE, NAME_KEY);
        String name = CURRENT_FILE_INSTANCE.getConfig(pathDataId);
        
        // 根据file配置文件的路径构建FileConfuguration对象
        configuration = new FileConfiguration(name);
        try {
        	// configuration的额外扩展,也是只对客户端SpringBoot的SDK才生效
            extConfiguration = EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("load Configuration:{}", extConfiguration == null
                    ? configuration.getClass().getSimpleName() : extConfiguration.getClass().getSimpleName());
            }
        } catch (EnhancedServiceNotFoundException ignore) {

        } catch (Exception e) {
            LOGGER.error("failed to load extConfiguration:{}", e.getMessage(), e);
        }
    } else {
    	// 如果配置文件的类型不是file,如:nacos、zk等,
    	// 则通过SPI的方式生成对应的ConfigurationProvider对象
        configuration = EnhancedServiceLoader
            .load(ConfigurationProvider.class, Objects.requireNonNull(configType).name()).provide();
    }
    try {
    	// ConfigurationCache是对Configuration做了一次层代理内存缓存,提升获取配置的性能
        Configuration configurationCache;
        if (null != extConfiguration) {
            configurationCache = ConfigurationCache.getInstance().proxy(extConfiguration);
        } else {
            configurationCache = ConfigurationCache.getInstance().proxy(configuration);
        }
        if (null != configurationCache) {
            extConfiguration = configurationCache;
        }
    } catch (EnhancedServiceNotFoundException ignore) {

    } catch (Exception e) {
        LOGGER.error("failed to load configurationCacheProvider:{}", e.getMessage(), e);
    }
    return null == extConfiguration ? configuration : extConfiguration;
}

3. Инициализировать UUIDGenerator.

UUIDGenertor инициализирует и получает параметр serverNode. UUIDGenertor в настоящее время использует алгоритм снежинки для генерации уникального идентификатора. ServerNode используется, чтобы гарантировать, что уникальные идентификаторы, сгенерированные несколькими экземплярами seata-server, не повторяются.

public class UUIDGenerator {

    /**
     * Generate uuid long.
     *
     * @return the long
     */
    public static long generateUUID() {
        return IdWorker.getInstance().nextId();
    }

    /**
     * Init.
     *
     * @param serverNode the server node id
     */
    public static void init(Long serverNode) {
        IdWorker.init(serverNode);
    }
}

UUIDGenerator инкапсулирует IdWorker, основная логика реализации уникального идентификатора находится в классе IdWoker, а IdWorker реализуется с помощью алгоритма снежинки. Здесь IdWorker - еще один синглтон

public class IdWorker
/**
     * Constructor
     *
     * @param workerId就是上面提到的ServerNode, 取值范围在0·1023,也就是在64位的UUID中占10位
     */
    public IdWorker(long workerId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(
                String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        this.workerId = workerId;
    }

    /**
     * Get the next ID (the method is thread-safe)
     *
     * @return SnowflakeId
     */
    public long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format(
                "clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        synchronized (this) {
            if (lastTimestamp == timestamp) {
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0L;
            }
            lastTimestamp = timestamp;
        }
        //雪花算法64位唯一id组成:第一位0 + 41位时间戳 + 10位workerId + 12位自增序列化(同一时间戳内自增)
        return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
    }

4. Инициализация SessionHolder

SessionHolder отвечает за сохранение сеанса. Объект сеанса соответствует транзакции. Существует два типа транзакций: GlobalSession и BranchSession. SessionHolder поддерживает два метода сохранения: file и db, среди которых db поддерживает режим кластера, и рекомендуется db. Четыре основных поля в SessionHolder следующие:

// ROOT_SESSION_MANAGER用于获取所有的Setssion,以及Session的创建、更新、删除等。
private static SessionManager ROOT_SESSION_MANAGER;
// 用于获取、更新所有的异步commit的Session
private static SessionManager ASYNC_COMMITTING_SESSION_MANAGER;
// 用于获取、更新所有需要重试commit的Session
private static SessionManager RETRY_COMMITTING_SESSION_MANAGER;
// 用于获取、更新所有需要重试rollback的Session
private static SessionManager RETRY_ROLLBACKING_SESSION_MANAGER;

Метод инициализации SessionHolder

public static void init(String mode) throws IOException {
    if (StringUtils.isBlank(mode)) {
        mode = CONFIG.getConfig(ConfigurationKeys.STORE_MODE);
    }
    StoreMode storeMode = StoreMode.get(mode);
    if (StoreMode.DB.equals(storeMode)) {
        // 这里又用到了SPI的方式加载SessionManager,
        // 其实下面获取的四个SessionManager实例都是同一个类DataBaseSessionManager的不同实例,
        // 只是给DataBaseSessionManager的构造函数传参不同。
        ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName());
        ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName(),
            new Object[] {ASYNC_COMMITTING_SESSION_MANAGER_NAME});
        RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName(),
            new Object[] {RETRY_COMMITTING_SESSION_MANAGER_NAME});
        RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName(),
            new Object[] {RETRY_ROLLBACKING_SESSION_MANAGER_NAME});
    } else if (StoreMode.FILE.equals(storeMode)) {
        //file模式可以先不关心
        ...
    } else {
        throw new IllegalArgumentException("unknown store mode:" + mode);
    }
    // reload方法对于db模式可以忽略
    reload();
}

Как вы можете видеть выше, четыре SessionManager в SessionHolder по сути являются экземплярами класса DataBaseSessionManager, но они различаются по передаче параметров конструктору. Посмотрите определение DataBaseSessionManager:

public DataBaseSessionManager(String name) {
	super();
	this.taskName = name;
}

// 根据实例的taskName来决定allSessions返回的事务列表,
// 如taskName等于ASYNC_COMMITTING_SESSION_MANAGER_NAME的
// 就返回所有状态为AsyncCommitting的事务。
public Collection<GlobalSession> allSessions() {
	// get by taskName
	if (SessionHolder.ASYNC_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) {
			return findGlobalSessions(new SessionCondition(GlobalStatus.AsyncCommitting));
	} else if (SessionHolder.RETRY_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) {
			return findGlobalSessions(new SessionCondition(new GlobalStatus[] {GlobalStatus.CommitRetrying}));
	} else if (SessionHolder.RETRY_ROLLBACKING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) {
			return findGlobalSessions(new SessionCondition(new GlobalStatus[] {GlobalStatus.RollbackRetrying,
					GlobalStatus.Rollbacking, GlobalStatus.TimeoutRollbacking, GlobalStatus.TimeoutRollbackRetrying}));
	} else {
		// taskName为null,则对应ROOT_SESSION_MANAGER,即获取所有状态的事务
		return findGlobalSessions(new SessionCondition(new GlobalStatus[] {
				GlobalStatus.UnKnown, GlobalStatus.Begin,
				GlobalStatus.Committing, GlobalStatus.CommitRetrying, GlobalStatus.Rollbacking,
				GlobalStatus.RollbackRetrying,
				GlobalStatus.TimeoutRollbacking, 
				GlobalStatus.TimeoutRollbackRetrying,
				GlobalStatus.AsyncCommitting}));
	}
}

5. Инициализировать DefaultCoordinator.

DefaultCoordinator - это ядро ​​координатора транзакций, например: открытие, фиксация и откат глобальных транзакций, регистрация, фиксация и откат транзакций ветки - все координируются и обрабатываются DefaultCoordinator. DefaultCoordinato связывается с удаленными TM и RM через RpcServer, чтобы реализовать фиксацию и откат транзакций веток.

public DefaultCoordinator(ServerMessageSender messageSender) {
	// 接口messageSender的实现类就是上文提到的RpcServer
	this.messageSender = messageSender;
	
	// DefaultCore封装了AT、TCC、Saga等分布式事务模式的具体实现类
	this.core = new DefaultCore(messageSender);
}

// init方法初始化了5个定时器,主要用于分布式事务的重试机制,
// 因为分布式环境的不稳定性会造成事务处于中间状态,
// 所以要通过不断的重试机制来实现事务的最终一致性。
// 下面的定时器除了undoLogDelete之外,其他的定时任务默认都是1秒执行一次。
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);
    
	// 检查事务的第一阶段已经超时的事务,设置事务状态为TimeoutRollbacking,
	// 该事务会由其他定时任务执行回滚操作
	timeoutCheck.scheduleAtFixedRate(() -> {
		try {
			timeoutCheck();
		} catch (Exception e) {
			LOGGER.info("Exception timeout checking ... ", e);
		}
	}, 0, TIMEOUT_RETRY_PERIOD, TimeUnit.MILLISECONDS);
    
	// 根据unlog的保存天数调用RM删除unlog
	undoLogDelete.scheduleAtFixedRate(() -> {
		try {
			undoLogDelete();
		} catch (Exception e) {
			LOGGER.info("Exception undoLog deleting ... ", e);
		}
	}, UNDO_LOG_DELAY_DELETE_PERIOD, UNDO_LOG_DELETE_PERIOD, TimeUnit.MILLISECONDS);
}

6. Инициализируйте NettyRemotingServer.

NettyRemotingServer - это упрощенная версия сервера Rpc, основанная на реализации Netty. Когда NettyRemotingServer инициализируется, он в основном выполняет две функции:

  1. registerProcessor : Зарегистрируйте процессор, обменивающийся данными с Клиентом.
  2. super.init () : метод super.init () отвечает за инициализацию Netty и регистрацию IP-порта текущего экземпляра в реестре.
public void init() {
    // registry processor
    registerProcessor();
    if (initialized.compareAndSet(false, true)) {
        super.init();
    }
}

private void registerProcessor() {
	// 1. 注册核心的ServerOnRequestProcessor,即与事务处理相关的Processor,
	// 如:全局事务开始、提交,分支事务注册、反馈当前状态等。
	// ServerOnRequestProcessor的构造函数中传入getHandler()返回的示例,这个handler
	// 就是前面提到的DefaultCoordinator,DefaultCoordinator是分布式事务的核心处理类
	ServerOnRequestProcessor onRequestProcessor =
	    new ServerOnRequestProcessor(this, getHandler());
	super.registerProcessor(MessageType.TYPE_BRANCH_REGISTER, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_BRANCH_STATUS_REPORT, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_GLOBAL_BEGIN, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_GLOBAL_COMMIT, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_GLOBAL_LOCK_QUERY, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_GLOBAL_REPORT, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_GLOBAL_ROLLBACK, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_GLOBAL_STATUS, onRequestProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_SEATA_MERGE, onRequestProcessor, messageExecutor);
	
	// 2.注册ResponseProcessor,ResponseProcessor用于处理当Server端主动发起请求时,
	// Client端回复的消息,即Response。如:Server向Client端发送分支事务提交或者回滚的请求时,
	// Client返回提交/回滚的结果
	ServerOnResponseProcessor onResponseProcessor =
	    new ServerOnResponseProcessor(getHandler(), getFutures());
	super.registerProcessor(MessageType.TYPE_BRANCH_COMMIT_RESULT, onResponseProcessor, messageExecutor);
	super.registerProcessor(MessageType.TYPE_BRANCH_ROLLBACK_RESULT, onResponseProcessor, messageExecutor);
	
	// 3. Client端发起RM注册请求时对应的Processor
	RegRmProcessor regRmProcessor = new RegRmProcessor(this);
	super.registerProcessor(MessageType.TYPE_REG_RM, regRmProcessor, messageExecutor);
	
	// 4. Client端发起TM注册请求时对应的Processor
	RegTmProcessor regTmProcessor = new RegTmProcessor(this);
	super.registerProcessor(MessageType.TYPE_REG_CLT, regTmProcessor, null);
	
	// 5. Client端发送心跳请求时对应的Processor
	ServerHeartbeatProcessor heartbeatMessageProcessor = new ServerHeartbeatProcessor(this);
	super.registerProcessor(MessageType.TYPE_HEARTBEAT_MSG, heartbeatMessageProcessor, null);
}

В NettyRemotingServer есть метод init, который вызывает базовый класс AbstractNettyRemotingServer, код выглядит следующим образом:

public void init() {
	// super.init()方法中启动了一个定时清理超时Rpc请求的定时任务,3S执行一次。
    super.init();
	// 配置Netty Server端,开始监听端口。
    serverBootstrap.start();
}

// serverBootstrap.start();
public void start() {
	// Netty server端的常规配置,其中添加了两个ChannelHandler:
	// ProtocolV1Decoder、ProtocolV1Encoder,
	// 分别对应Seata自定义RPC协议的解码器和编码器
    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 (channelHandlers != null) {
                    addChannelPipelineLast(ch, channelHandlers);
                }

            }
        });

    try {
		// 开始监听配置的端口
        ChannelFuture future = this.serverBootstrap.bind(listenPort).sync();
        LOGGER.info("Server started, listen port: {}", listenPort);
		// Netty启动成功之后把当前实例注册到registry.conf配置文件配置的注册中心上
        RegistryFactory.getInstance().register(new InetSocketAddress(XID.getIpAddress(), XID.getPort()));
        initialized.set(true);
        future.channel().closeFuture().sync();
    } catch (Exception exx) {
        throw new RuntimeException(exx);
    }
}

Оригинал: https://seata.io/zh-cn/blog/seata-sourcecode-server-bootstrap.html

● Самая сильная оптимизация производительности Tomcat8 в истории

Почему Alibaba может противостоять 10 миллиардам за 90 секунд? --Эволюция серверной распределенной архитектуры с высоким уровнем параллелизма.

Платформа электронной коммерции B2B - функция электронных платежей ChinaPay UnionPay.

Изучите распределенную блокировку Zookeeper, пусть интервьюеры смотрят на вас с восхищением.

Всплеск микросервисов в электронной коммерции SpringCloud - решение Redisson с распределенной блокировкой

Ознакомьтесь с другими хорошими статьями, войдите в официальный аккаунт - порадуйте меня - в прошлом отлично

Глубокий и проникновенный публичный отчет 0.0

 

рекомендация

отblog.csdn.net/a1036645146/article/details/108800345
рекомендация