当ServerApplication的run方法启动的时候会调用到run方法的callRunners方法中对实现了CommandLineRunner接口的类进行run方法的加载 而在seata中ServerRunner实现了CommandLineRunner接口所以会加载到ServerRunner 的run方法中实现seata服务端的启动
@Override
public void run(String... args) {
try {
long start = System.currentTimeMillis();
//SeataServer启动
Server.start(args);
started = true;
long cost = System.currentTimeMillis() - start;
//记录启动时间
LOGGER.info("seata server started in {} millSeconds", cost);
} catch (Throwable e) {
started = Boolean.FALSE;
LOGGER.error("seata server start error: {} ", e.getMessage(), e);
System.exit(-1);
}
}
public class Server {
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void start(String[] args) {
// create logger
final Logger logger = LoggerFactory.getLogger(Server.class);
//initialize the parameter parser
//Note that the parameter parser should always be the first line to execute.
//Because, here we need to parse the parameters needed for startup.
// 1. 对配置文件做参数解析:包括registry.conf、file.conf的解析
ParameterParser parameterParser = new ParameterParser(args);
// 2、初始化监控,做metric指标采集
MetricsManager.get().init();
// 将Store资源持久化方式放到系统的环境变量store.mode中
System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());
// seata server里netty server 的io线程池(核心线程数50,最大线程数100)
ThreadPoolExecutor workingThreads = new ThreadPoolExecutor(NettyServerConfig.getMinServerPoolSize(),
NettyServerConfig.getMaxServerPoolSize(),
NettyServerConfig.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(NettyServerConfig.getMaxTaskQueueSize()),
new NamedThreadFactory("ServerHandlerThread", NettyServerConfig.getMaxServerPoolSize()), new ThreadPoolExecutor.CallerRunsPolicy());
// 3、创建TC与RM/TM通信的RPC服务器--netty
NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(workingThreads);
// 4、初始化UUID生成器(雪花算法)
UUIDGenerator.init(parameterParser.getServerNode());
//log store mode : file, db, redis
// 5、设置事务会话的持久化方式,有三种类型可选:file/db/redis
SessionHolder.init(parameterParser.getSessionStoreMode());
LockerManagerFactory.init(parameterParser.getLockStoreMode());
// 6、创建并初始化事务协调器,创建时后台会启动一堆线程
DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer);
coordinator.init();
// 将DefaultCoordinator作为Netty Server的transactionMessageHandler;
// 用于做AT、TCC、SAGA等不同事务类型的逻辑处理
nettyRemotingServer.setHandler(coordinator);
// let ServerRunner do destroy instead ShutdownHook, see https://github.com/seata/seata/issues/4028
// 7、注册ServerRunner销毁(Spring容器销毁)的回调钩子函数
ServerRunner.addDisposable(coordinator);
//127.0.0.1 and 0.0.0.0 are not valid here.
if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
XID.setIpAddress(parameterParser.getHost());
} else {
String preferredNetworks = ConfigurationFactory.getInstance().getConfig(REGISTRY_PREFERED_NETWORKS);
if (StringUtils.isNotBlank(preferredNetworks)) {
XID.setIpAddress(NetUtil.getLocalIp(preferredNetworks.split(REGEX_SPLIT_CHAR)));
} else {
XID.setIpAddress(NetUtil.getLocalIp());
}
}
// 8、启动netty Server,用于接收TM/RM的请求
nettyRemotingServer.init();
}
}
ParameterParser
public ParameterParser(String... args) {
this.init(args);
}
private void init(String[] args) {
try {
//解析运行期间的参数 默认为啥都没有
getCommandParameters(args);
//读取host、port、server节点以及StoreMode存储模式
getEnvParameters();
if (StringUtils.isNotBlank(seataEnv)) {
System.setProperty(ENV_PROPERTY_KEY, seataEnv);
}
if (StringUtils.isBlank(storeMode)) {
storeMode = CONFIG.getConfig(ConfigurationKeys.STORE_MODE, SERVER_DEFAULT_STORE_MODE);
}
if (StringUtils.isBlank(sessionStoreMode)) {
sessionStoreMode = CONFIG.getConfig(ConfigurationKeys.STORE_SESSION_MODE, storeMode);
}
if (StringUtils.isBlank(lockStoreMode)) {
lockStoreMode = CONFIG.getConfig(ConfigurationKeys.STORE_LOCK_MODE, storeMode);
}
} catch (ParameterException e) {
printError(e);
}
}
private void getEnvParameters() {
// 设置seata的环境
if (StringUtils.isBlank(seataEnv)) {
seataEnv = ContainerHelper.getEnv();
}
// 设置Host
if (StringUtils.isBlank(host)) {
host = ContainerHelper.getHost();
}
// 设置端口号
if (port == 0) {
port = ContainerHelper.getPort();
}
if (serverNode == null) {
serverNode = ContainerHelper.getServerNode();
}
if (StringUtils.isBlank(storeMode)) {
storeMode = ContainerHelper.getStoreMode();
}
if (StringUtils.isBlank(sessionStoreMode)) {
sessionStoreMode = ContainerHelper.getSessionStoreMode();
}
if (StringUtils.isBlank(lockStoreMode)) {
lockStoreMode = ContainerHelper.getLockStoreMode();
}
}
MetricsManager
public void init() {
boolean enabled = ConfigurationFactory.getInstance().getBoolean(
ConfigurationKeys.METRICS_PREFIX + ConfigurationKeys.METRICS_ENABLED, false);
if (enabled) {
registry = RegistryFactory.getInstance();
if (registry != null) {
List<Exporter> exporters = ExporterFactory.getInstanceList();
//only at least one metrics exporter implement had imported in pom then need register MetricsSubscriber
if (exporters.size() != 0) {
exporters.forEach(exporter -> exporter.setRegistry(registry));
EventBusManager.get().register(new MetricsSubscriber(registry));
}
}
}
}
这里是基于Netty去构建的
NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(workingThreads);
public NettyRemotingServer(ThreadPoolExecutor messageExecutor) {
super(messageExecutor, new NettyServerConfig());
}
public AbstractNettyRemotingServer(ThreadPoolExecutor messageExecutor, NettyServerConfig nettyServerConfig) {
super(messageExecutor);
serverBootstrap = new NettyServerBootstrap(nettyServerConfig);
//设置header 去接受客户端的请求
serverBootstrap.setChannelHandlers(new ServerHandler());
}
UUID底层采用雪花算法,其用于生成全局事务id和分支事务id;
UUIDGenerator.init(parameterParser.getServerNode());
SessionHolder负责事务会话Session的持久化,一个session对应一个事务,事务又分为全局事务和分支事务;
SessionHolder支持db,file和redis的持久化方式,其中redis和db支持集群模式,项目上推荐使用redis或db模式
SessionHolder.init(parameterParser.getSessionStoreMode());
// 用于管理所有的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;
// 用于管理分布式锁
private static DistributedLocker DISTRIBUTED_LOCKER;
LockerManagerFactory.init(parameterParser.getLockStoreMode());
这里用到了双重检查锁机制
public static void init(String lockMode) {
if (LOCK_MANAGER == null) {
synchronized (LockerManagerFactory.class) {
if (LOCK_MANAGER == null) {
if (StringUtils.isBlank(lockMode)) {
lockMode = CONFIG.getConfig(ConfigurationKeys.STORE_LOCK_MODE,
CONFIG.getConfig(ConfigurationKeys.STORE_MODE, SERVER_DEFAULT_STORE_MODE));
}
if (StoreMode.contains(lockMode)) {
LOCK_MANAGER = EnhancedServiceLoader.load(LockManager.class, lockMode);
}
}
}
}
}
DefaultCoordinator是事务协调的核心,比如:开启、提交、回滚全局事务,注册、提交、回滚分支事务都是通过DefaultCoordinator进行协调处理的。
DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer);
coordinator.init();
双重检查锁确保这是单例的
public static DefaultCoordinator getInstance(RemotingServer remotingServer) {
if (null == instance) {
synchronized (DefaultCoordinator.class) {
if (null == instance) {
instance = new DefaultCoordinator(remotingServer);
}
}
}
return instance;
}
private DefaultCoordinator(RemotingServer remotingServer) {
if (remotingServer == null) {
throw new IllegalArgumentException("RemotingServer not allowed be null.");
}
this.remotingServer = remotingServer;
this.core = new DefaultCore(remotingServer);
}
public DefaultCore(RemotingServer remotingServer) {
List<AbstractCore> allCore = EnhancedServiceLoader.loadAll(AbstractCore.class,
new Class[] {RemotingServer.class}, new Object[] {remotingServer});
if (CollectionUtils.isNotEmpty(allCore)) {
for (AbstractCore core : allCore) {
// coreMap 代表 seata事务的四种模式 AT、TCC、XA、Saga
coreMap.put(core.getHandleBranchType(), core);
}
}
}
除定时清理undo_log外,其余定时任务的处理逻辑基本都是:
首先获取所有可回滚的全局事务会话Session,如果可回滚的分支事务为空,则直接返回;
否者,遍历所有的可回滚Session;为了防止重复回滚,如果session的状态是正在回滚中并且session不是死亡的,则直接返回;
如果Session重试回滚超时,从缓存中删除已经超时的回滚Session;
发布session回滚完成事件给到Metric,对回滚中的Session添加Session生命周期的监听;
使用DefaultCoordinator组合的DefaultCore执行全局回滚。
public void init() {
//处理重试回滚
retryRollbacking.scheduleAtFixedRate(
() -> SessionHolder.distributedLockAndExecute(RETRY_ROLLBACKING, this::handleRetryRollbacking), 0,
ROLLBACKING_RETRY_PERIOD, TimeUnit.MILLISECONDS);
//处理重试提交
retryCommitting.scheduleAtFixedRate(
() -> SessionHolder.distributedLockAndExecute(RETRY_COMMITTING, this::handleRetryCommitting), 0,
COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS);
//处理异步提交
asyncCommitting.scheduleAtFixedRate(
() -> SessionHolder.distributedLockAndExecute(ASYNC_COMMITTING, this::handleAsyncCommitting), 0,
ASYNC_COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS);
//做超时检查
timeoutCheck.scheduleAtFixedRate(
() -> SessionHolder.distributedLockAndExecute(TX_TIMEOUT_CHECK, this::timeoutCheck), 0,
TIMEOUT_RETRY_PERIOD, TimeUnit.MILLISECONDS);
//undo——log 日志的删除
undoLogDelete.scheduleAtFixedRate(
() -> SessionHolder.distributedLockAndExecute(UNDOLOG_DELETE, this::undoLogDelete),
UNDO_LOG_DELAY_DELETE_PERIOD, UNDO_LOG_DELETE_PERIOD, TimeUnit.MILLISECONDS);
}
ServerRunner.addDisposable(coordinator);
nettyRemotingServer.init();
@Override
public void init() {
// 注册处理器
registerProcessor();
if (initialized.compareAndSet(false, true)) {
//没有初始化进行初始化
super.init();
}
}
消息处理器是用来处理消息的,其根据消息的不同类型选择不同的消息处理器来处理消息(属于典型的策略模式)
private void registerProcessor() {
// 1. registry on request message processor
ServerOnRequestProcessor onRequestProcessor =
new ServerOnRequestProcessor(this, getHandler());
ShutdownHook.getInstance().addDisposable(onRequestProcessor);
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. registry on response message processor
ServerOnResponseProcessor onResponseProcessor =
new ServerOnResponseProcessor(getHandler(), getFutures());
super.registerProcessor(MessageType.TYPE_BRANCH_COMMIT_RESULT, onResponseProcessor, branchResultMessageExecutor);
super.registerProcessor(MessageType.TYPE_BRANCH_ROLLBACK_RESULT, onResponseProcessor, branchResultMessageExecutor);
// 3. registry rm message processor
RegRmProcessor regRmProcessor = new RegRmProcessor(this);
super.registerProcessor(MessageType.TYPE_REG_RM, regRmProcessor, messageExecutor);
// 4. registry tm message processor
RegTmProcessor regTmProcessor = new RegTmProcessor(this);
super.registerProcessor(MessageType.TYPE_REG_CLT, regTmProcessor, null);
// 5. registry heartbeat message processor
ServerHeartbeatProcessor heartbeatMessageProcessor = new ServerHeartbeatProcessor(this);
super.registerProcessor(MessageType.TYPE_HEARTBEAT_MSG, heartbeatMessageProcessor, null);
}
所谓的注册消息处理器本质上就是将处理器RemotingProcessor和处理消息的线程池ExecutorService包装成一个Pair,然后将Pair作为Value,messageType作为key放入一个Map(processorTable)中;
@Override
public void registerProcessor(int messageType, RemotingProcessor processor, ExecutorService executor) {
Pair<RemotingProcessor, ExecutorService> pair = new Pair<>(processor, executor);
this.processorTable.put(messageType, pair);
}
init方法的作用每3秒遍历futures,查询过期的MessageFuture,并将其从futures中清除。
public void init() {
timerExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//遍历消息futures,处理过期的消息
for (Map.Entry<Integer, MessageFuture> entry : futures.entrySet()) {
MessageFuture future = entry.getValue();
if (future.isTimeout()) {
futures.remove(entry.getKey());
RpcMessage rpcMessage = future.getRequestMessage();
future.setResultMessage(new TimeoutException(String
.format("msgId: %s ,msgType: %s ,msg: %s ,request timeout", rpcMessage.getId(), String.valueOf(rpcMessage.getMessageType()), rpcMessage.getBody().toString())));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("timeout clear future: {}", entry.getValue().getRequestMessage().getBody());
}
}
}
nowMills = System.currentTimeMillis();
}
}, TIMEOUT_CHECK_INTERVAL, TIMEOUT_CHECK_INTERVAL, TimeUnit.MILLISECONDS);
}
这里其实就是启动的Netty去处理和客户端的交互 当有消息到来时会走到 ServerHandler的channelRead方法中去进行消息的处理
@Override
public void start() {
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(getListenPort()))
.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 {
this.serverBootstrap.bind(getListenPort()).sync();
XID.setPort(getListenPort());
LOGGER.info("Server started, service listen port: {}", getListenPort());
RegistryFactory.getInstance().register(new InetSocketAddress(XID.getIpAddress(), XID.getPort()));
initialized.set(true);
} catch (SocketException se) {
throw new RuntimeException("Server start failed, the listen port: " + getListenPort(), se);
} catch (Exception exx) {
throw new RuntimeException("Server start failed", exx);
}
}
1.解析registry.conf、file.conf等配置文件
2.创建一个监控,做metric指标采集
3.创建SeataNettyServer服务端(TC事务协调器) 并设置一个Handler用来处理AT、TCC、SAGA等不同事务类型的逻辑处理
4.设置事务持久化方式
5.设置全局锁的管理器
6.启动Seata服务端 建立和客户端的通道 默认端口为8091