源码角度了解Skywalking之服务端OAP的启动流程

Skywalking的服务端OAP的逻辑对应oap-server模块,入口是server-starter子模块的OAPServerStartUp类,直接调用了server-bootstrap子模块的OAPServerBootstrap的start()方法

OAPServerBootstrap的start()方法:

public static void start() {
    String mode = System.getProperty("mode");
    RunningMode.setMode(mode);

    ApplicationConfigLoader configLoader = new ApplicationConfigLoader();
    ModuleManager manager = new ModuleManager();
    try {
        ApplicationConfiguration applicationConfiguration = configLoader.load();
        manager.init(applicationConfiguration);

        manager.find(TelemetryModule.NAME).provider().getService(MetricsCreator.class).createGauge("uptime",
            "oap server start up time", MetricsTag.EMPTY_KEY, MetricsTag.EMPTY_VALUE)
            // Set uptime to second
            .setValue(System.currentTimeMillis() / 1000d);

        if (RunningMode.isInitMode()) {
            logger.info("OAP starts up in init mode successfully, exit now...");
            System.exit(0);
        }
    } catch (Throwable t) {
        logger.error(t.getMessage(), t);
        System.exit(1);
    }
}
  1. 读取系统配置的mode值,如果值为init表示初始化模式,做所有初始化的事情。如果值是no-init,表示非初始化模式,不进行存储初始化
  2. 创建ApplicationConfiguration对象,通过load()方法加载配置文件,具体是读取resources文件夹下的application.yml文件,然后读取系统配置,覆盖读取的application.yml文件的值
  3. 初始化给定的模块
  4. 查找指定Module中的获取相应Service,创建仪表类型指标实例标记启动时间。
  5. 如果是初始化模式,初始化成功后会退出OAP服务

我们具体看一下初始化模块

初始化模块

ModuleManager负责在收集器中的所有ModuleDefine

ModuleManager的init()方法:

  1. 获取配置所有的模块集合,配置文件中配置的都是模块名,这些都是在ModuleDefine的实现类中定义了,比如配置文件中的core对应的是ModuleDefine实现类CoreModule
  2. 通过SPI机制加载ModuleDefine的实现类
  3. 通过SPI机制加载ModuleProvider的实现类
  4. 遍历所有的ModuleDefine实现类,与配置文件中定义的实现类匹配,匹配成功调用prepare()方法进行初始化,否则放入map集合loadedModules中进行记录
  5. 添加完成准备阶段的标记
  6. 创建BootstrapFlow对象,启动ModuleManager对象,完成后调用notifyAfterCompleted()方法通知所有的ModuleProvider实例,表示可以对外提供服务了

ModuleDefine的准备阶段

ModuleDefine实例的prepare()方法是运行模块的准备阶段,这个方法中也会找到所有潜在的提供者,让他们也进入准备阶段

ModuleDefine的prepare()方法:

  1. 遍历SPI机制加载的moduleProviderLoader实现类,与配置文件中模块定义的实现类匹配,匹配成功设置ModuleProvider实例的ModuleManager和当前ModuleDefine
  2. 调用ModuleProvider的prepare()方法让提供者也进入准备状态,prepare()方法是ModuleProvider的抽象方法,具体方法由它的子类来实现,每个模块的prepare()方法也不同,每个模块仅对应一个ModuleProvider

BootstrapFlow创建、启动与通知

在初始化过程中,创建BootstrapFlow对象,BootstrapFlow的构造方法中创建LinkedList对象用链表集合记录模块的启动顺序,模块之间可能存在依赖,所以需要调用makeSequence()方法设定模块的加载顺序。

BootstrapFlow的start()方法:

void start(
        ModuleManager moduleManager) throws ModuleNotFoundException, ServiceNotProvidedException, ModuleStartException {
        for (ModuleProvider provider : startupSequence) {
            String[] requiredModules = provider.requiredModules();
            if (requiredModules != null) {
                for (String module : requiredModules) {
                    if (!moduleManager.has(module)) {
                        throw new ModuleNotFoundException(module + " is required by " + provider.getModuleName()
                            + "." + provider.name() + ", but not found.");
                    }
                }
            }
            logger.info("start the provider {} in {} module.", provider.name(), provider.getModuleName());
            provider.requiredCheck(provider.getModule().services());

            provider.start();
        }
    }

遍历所有的ModuleProvider:

  1. 根据ModuleProvider需要的模块名判断是否ModuleProvider中是否有需要的模块,如果没有抛出异常
  2. 检测模块的service是否实现了,如果没有会抛出异常
  3. 启动ModuleProvider

所有的ModuleProvider依次启动后回调执行notifyAfterCompleted()方法

总结

这篇文章主要讲了Skywalking的服务端OAP的启动流程,入口是server-starter模块的OAPServerStartUp类的main()方法,这一启动过程主要做的是加载server-bootstrap模块中的application.yml定义的模块定义、模块配置,然后相对应的ModuleProvider依次按顺序进行启动

❤️ 感谢大家

如果你觉得这篇内容对你挺有有帮助的话:

  1. 欢迎关注我❤️,点赞👍🏻,评论🤤,转发🙏
  2. 有不当之处欢迎批评指正。