Seata解析-seata服务端启动初探

x33g5p2x  于2021-12-21 转载在 其他  
字(3.6k)|赞(0)|评价(0)|浏览(1023)

本文基于seata 1.3.0版本

文章《Seata解析-seata部署启动初体验》介绍了seata的功能。seata提供四种方式解决了分布式事务问题,seata使用客户端-服务器模式,TM和RM作为客户端,TC作为事务协调者部署在服务端。
seata的服务端独立部署,功能相对简单,本文先来简单分析一下服务端,先尝尝鲜。

一、服务端的启动脚本

seata服务端启动需要使用启动脚本,启动脚本位于bin目录下:

第一个文件是Windows系统使用,第二个文件是Linux系统使用。两个文件都是设置一些启动参数,然后执行java的启动类。我们来看一下seata-server.sh文件的最后一部分:

  1. exec "$JAVACMD" $JAVA_OPTS -server -XX:MaxDirectMemorySize=1024M \
  2. -classpath "$CLASSPATH" \
  3. -Dapp.name="seata-server" \
  4. -Dapp.pid="$$" \
  5. -Dapp.repo="$REPO" \
  6. -Dapp.home="$BASEDIR" \
  7. -Dbasedir="$BASEDIR" \
  8. io.seata.server.Server \
  9. "$@"

seata-server.sh文件前面的内容是设置参数BASEDIR、REPO和CLASSPATH的值,有兴趣的可以看一下。从上面的代码可以看出,seata-server.sh设置了直接内存大小。而且最重要的指定了服务端的启动类io.seata.server.Server。下一节来分析一下这个启动类。

二、服务端启动类Server

Server类的启动入口为其main方法。
首先介绍一下main方法的流程:

  1. 解析启动参数,启动参数指的是seata-server.sh命令后面跟的参数;
  2. 初始化统计模块;
  3. 创建NettyRemotingServer对象,并设置端口号;
  4. 初始化UUID生成器;
  5. 创建会话管理器,在seata中,一个会话就代表了一个事务;
  6. 创建协调器,并初始化,将NettyRemotingServer对象与协调器关联起来,当NettyRemotingServer收到请求后会转发给协调器处理;
  7. 注册JVM关闭钩子;
  8. 设置生成XID的参数;
  9. 初始化NettyRemotingServer对象,该对象初始化完毕之后便可以接收客户端的请求,main方法的处理也到此为止。

从流程上可以看到,服务端最重要的组件是: NettyRemotingServer和协调器、会话管理器,后面会详细介绍它们的作用。
下面看一下代码:

  1. public static void main(String[] args) throws IOException {
  2. // 从启动参数里面获取端口号,这个端口号用于logback打印日志文件使用,默认值8091
  3. // 具体参见类SystemPropertyLoggerContextListener
  4. int port = PortHelper.getPort(args);
  5. System.setProperty(ConfigurationKeys.SERVER_PORT, Integer.toString(port));
  6. // create logger
  7. final Logger logger = LoggerFactory.getLogger(Server.class);
  8. //判断当前是否是在docker容器中运行
  9. if (ContainerHelper.isRunningInContainer()) {
  10. logger.info("The server is running in container.");
  11. }
  12. //initialize the parameter parser
  13. //Note that the parameter parser should always be the first line to execute.
  14. //Because, here we need to parse the parameters needed for startup.
  15. //解析参数,参数解析指的是在seata-server.sh命令后面跟的启动参数
  16. ParameterParser parameterParser = new ParameterParser(args);
  17. //初始化统计模块,以后用单独的文章分析
  18. MetricsManager.get().init();
  19. //设置事务日志的存储模式,可以是db或者file、redis,在seata中,事务叫做会话(session)
  20. //存储模式既可以通过启动参数设置也可以通过file.conf文件设置
  21. System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());
  22. //创建NettyRemotingServer
  23. NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(WORKING_THREADS);
  24. //server port
  25. //设置服务端的监听端口,默认是8091
  26. nettyRemotingServer.setListenPort(parameterParser.getPort());
  27. //ServerNode可以理解为是机器码,用一个数字代表一个服务节点,该值既可以标示一台服务节点,也用作生成UUID
  28. //如果不设置该值的话,默认使用雪花算法生成
  29. UUIDGenerator.init(parameterParser.getServerNode());
  30. //log store mode : file, db, redis
  31. //创建会话管理器,也就是事务管理器,根据存储模式的不同,会话管理器也不同
  32. //会话管理器:存储了全局会话和分支会话
  33. //会话管理器分为:根会话管理器、异步提交会话管理器、重试提交会话管理器、重试会话管理器
  34. SessionHolder.init(parameterParser.getStoreMode());
  35. //创建协调器,协调器用于处理nettyRemotingServer转发的请求,之后再调用核心模块DefaultCore,可以开启事务,回滚事务,提交事务等
  36. DefaultCoordinator coordinator = new DefaultCoordinator(nettyRemotingServer);
  37. //初始化,创建四个定时器,
  38. //分别用于检测回滚重试、提交重试、异步提交、超时检测等事务会话
  39. coordinator.init();
  40. //设置nettyRemotingServer的transactionMessageHandler属性,
  41. //当nettyRemotingServer收到请求后,可以将请求转发给协调器
  42. nettyRemotingServer.setHandler(coordinator);
  43. // register ShutdownHook
  44. // 注册JVM的关闭钩子
  45. ShutdownHook.getInstance().addDisposable(coordinator);
  46. ShutdownHook.getInstance().addDisposable(nettyRemotingServer);
  47. //127.0.0.1 and 0.0.0.0 are not valid here.
  48. // 校验IP地址,启动参数设置127.0.0.1和0.0.0.0 会导致启动失败
  49. if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
  50. XID.setIpAddress(parameterParser.getHost());
  51. } else {
  52. XID.setIpAddress(NetUtil.getLocalIp());
  53. }
  54. XID.setPort(nettyRemotingServer.getListenPort());
  55. try {
  56. // 注册处理器,并启动Netty的服务端,执行完init方法后,服务端可以接收外部请求
  57. // 处理器的作用是:每个处理器只处理指定类型的请求报文或者响应报文,处理器将报文再转发给协调器,最终由协调器处理
  58. nettyRemotingServer.init();
  59. } catch (Throwable e) {
  60. logger.error("nettyServer init error:{}", e.getMessage(), e);
  61. System.exit(-1);
  62. }
  63. //如果服务端的socket不关闭,那么这行代码永远不会执行。
  64. //System.exit可以确保JVM关闭
  65. System.exit(0);
  66. }

相关文章