文章23 | 阅读 16362 | 点赞0
本文基于seata 1.3.0版本
文章《Seata解析-seata部署启动初体验》介绍了seata的功能。seata提供四种方式解决了分布式事务问题,seata使用客户端-服务器模式,TM和RM作为客户端,TC作为事务协调者部署在服务端。
seata的服务端独立部署,功能相对简单,本文先来简单分析一下服务端,先尝尝鲜。
seata服务端启动需要使用启动脚本,启动脚本位于bin目录下:
第一个文件是Windows系统使用,第二个文件是Linux系统使用。两个文件都是设置一些启动参数,然后执行java的启动类。我们来看一下seata-server.sh文件的最后一部分:
exec "$JAVACMD" $JAVA_OPTS -server -XX:MaxDirectMemorySize=1024M \
-classpath "$CLASSPATH" \
-Dapp.name="seata-server" \
-Dapp.pid="$$" \
-Dapp.repo="$REPO" \
-Dapp.home="$BASEDIR" \
-Dbasedir="$BASEDIR" \
io.seata.server.Server \
"$@"
seata-server.sh文件前面的内容是设置参数BASEDIR、REPO和CLASSPATH的值,有兴趣的可以看一下。从上面的代码可以看出,seata-server.sh设置了直接内存大小。而且最重要的指定了服务端的启动类io.seata.server.Server。下一节来分析一下这个启动类。
Server类的启动入口为其main方法。
首先介绍一下main方法的流程:
从流程上可以看到,服务端最重要的组件是: NettyRemotingServer和协调器、会话管理器,后面会详细介绍它们的作用。
下面看一下代码:
public static void main(String[] args) throws IOException {
// 从启动参数里面获取端口号,这个端口号用于logback打印日志文件使用,默认值8091
// 具体参见类SystemPropertyLoggerContextListener
int port = PortHelper.getPort(args);
System.setProperty(ConfigurationKeys.SERVER_PORT, Integer.toString(port));
// create logger
final Logger logger = LoggerFactory.getLogger(Server.class);
//判断当前是否是在docker容器中运行
if (ContainerHelper.isRunningInContainer()) {
logger.info("The server is running in container.");
}
//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.
//解析参数,参数解析指的是在seata-server.sh命令后面跟的启动参数
ParameterParser parameterParser = new ParameterParser(args);
//初始化统计模块,以后用单独的文章分析
MetricsManager.get().init();
//设置事务日志的存储模式,可以是db或者file、redis,在seata中,事务叫做会话(session)
//存储模式既可以通过启动参数设置也可以通过file.conf文件设置
System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());
//创建NettyRemotingServer
NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(WORKING_THREADS);
//server port
//设置服务端的监听端口,默认是8091
nettyRemotingServer.setListenPort(parameterParser.getPort());
//ServerNode可以理解为是机器码,用一个数字代表一个服务节点,该值既可以标示一台服务节点,也用作生成UUID
//如果不设置该值的话,默认使用雪花算法生成
UUIDGenerator.init(parameterParser.getServerNode());
//log store mode : file, db, redis
//创建会话管理器,也就是事务管理器,根据存储模式的不同,会话管理器也不同
//会话管理器:存储了全局会话和分支会话
//会话管理器分为:根会话管理器、异步提交会话管理器、重试提交会话管理器、重试会话管理器
SessionHolder.init(parameterParser.getStoreMode());
//创建协调器,协调器用于处理nettyRemotingServer转发的请求,之后再调用核心模块DefaultCore,可以开启事务,回滚事务,提交事务等
DefaultCoordinator coordinator = new DefaultCoordinator(nettyRemotingServer);
//初始化,创建四个定时器,
//分别用于检测回滚重试、提交重试、异步提交、超时检测等事务会话
coordinator.init();
//设置nettyRemotingServer的transactionMessageHandler属性,
//当nettyRemotingServer收到请求后,可以将请求转发给协调器
nettyRemotingServer.setHandler(coordinator);
// register ShutdownHook
// 注册JVM的关闭钩子
ShutdownHook.getInstance().addDisposable(coordinator);
ShutdownHook.getInstance().addDisposable(nettyRemotingServer);
//127.0.0.1 and 0.0.0.0 are not valid here.
// 校验IP地址,启动参数设置127.0.0.1和0.0.0.0 会导致启动失败
if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
XID.setIpAddress(parameterParser.getHost());
} else {
XID.setIpAddress(NetUtil.getLocalIp());
}
XID.setPort(nettyRemotingServer.getListenPort());
try {
// 注册处理器,并启动Netty的服务端,执行完init方法后,服务端可以接收外部请求
// 处理器的作用是:每个处理器只处理指定类型的请求报文或者响应报文,处理器将报文再转发给协调器,最终由协调器处理
nettyRemotingServer.init();
} catch (Throwable e) {
logger.error("nettyServer init error:{}", e.getMessage(), e);
System.exit(-1);
}
//如果服务端的socket不关闭,那么这行代码永远不会执行。
//System.exit可以确保JVM关闭
System.exit(0);
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_38308374/article/details/108175686
内容来源于网络,如有侵权,请联系作者删除!