全鏈路監(jiān)控框架SkyWalking源代碼解讀

全鏈路監(jiān)控熟吏,想說愛你并不容易

當(dāng)系統(tǒng)上線后你沒有這樣的經(jīng)歷?

  • 客戶反饋系統(tǒng)慢夫否,你確束手無策
  • 系統(tǒng)報(bào)出了異常殖熟,你確分析不出源頭在哪里
  • 系統(tǒng)可能面臨突發(fā)流量局待,你確不知道是否能支撐得住
  • 問題只在正式重現(xiàn),測試環(huán)境缺無法復(fù)現(xiàn)
  • 每次出現(xiàn)問題無法預(yù)警菱属,問題出現(xiàn)問題后事后檢討钳榨,而沒有事前預(yù)警
    ......

如果你有上面的困擾,說明你的系統(tǒng)缺少可觀測性纽门,缺少一個(gè)全鏈路監(jiān)控系統(tǒng)薛耻。系統(tǒng)越復(fù)雜,我們發(fā)現(xiàn)出現(xiàn)問題時(shí)越來越無法駕馭赏陵,各種問題層出不窮饼齿,問題越來越多,為了掌握系統(tǒng)的運(yùn)行狀態(tài)蝙搔,確保系統(tǒng)正常對(duì)外提供服務(wù)候醒,需要一些手段去監(jiān)控系統(tǒng),以了解系統(tǒng)行為杂瘸,分析系統(tǒng)的性能,或在系統(tǒng)出現(xiàn)故障時(shí)伙菊,能發(fā)現(xiàn)問題败玉、記錄問題并發(fā)出告警敌土,從而幫助運(yùn)維人員發(fā)現(xiàn)問題、定位問題运翼。也可以根據(jù)監(jiān)控?cái)?shù)據(jù)發(fā)現(xiàn)系統(tǒng)瓶頸返干,提前感知故障,預(yù)判系統(tǒng)負(fù)載能力等血淌。

那么我們?nèi)绾稳プ鼍厍罚吭缭?010年谷歌發(fā)表了一篇論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》介紹了分布式追蹤的概念,之后很多互聯(lián)網(wǎng)公司都開始根據(jù)這篇論文打造自己的分布式鏈路追蹤系統(tǒng)悠夯。前面提到的 APM 系統(tǒng)的核心技術(shù)就是分布式鏈路追蹤癌淮。

為了追蹤錯(cuò)綜復(fù)雜的調(diào)用關(guān)系,我們需要一些手段去輔助完成沦补,最簡單的方式就是畫圖乳蓄,如下圖的場景

客戶端請(qǐng)求經(jīng)過負(fù)載均衡,負(fù)載均衡提供了三種服務(wù)

  • RPC
  • Web服務(wù)
  • 資源管理
    上面的方式雖然直觀夕膀,但是隨著系統(tǒng)的復(fù)雜性增加導(dǎo)致我們很清楚的查看調(diào)用關(guān)系虚倒,所以有沒有更好的表達(dá)方式?

上面的方式就是 OpenTracing 規(guī)范推薦給我們的方案产舞。

其實(shí)Tracing只是全鏈路很小的一部分魂奥,我們來看看全貌

  • Logging 就是記錄系統(tǒng)行為的離散事件,例如易猫,服務(wù)在處理某個(gè)請(qǐng)求時(shí)打印的錯(cuò)誤日志耻煤,我們可以將這些日志信息記錄到 ElasticSearch 或是其他存儲(chǔ)中,然后通過 Kibana 或是其他工具來分析這些日志了解服務(wù)的行為和狀態(tài)擦囊。大多數(shù)情況下违霞,日志記錄的數(shù)據(jù)很分散,并且相互獨(dú)立瞬场,比如錯(cuò)誤日志买鸽、請(qǐng)求處理過程中關(guān)鍵步驟的日志等等。

  • Metrics 是系統(tǒng)在一段時(shí)間內(nèi)某一方面的某個(gè)度量贯被,例如眼五,電商系統(tǒng)在一分鐘內(nèi)的請(qǐng)求次數(shù)。我們常見的監(jiān)控系統(tǒng)中記錄的數(shù)據(jù)都屬于這個(gè)范疇彤灶,例如 Promethus看幼、Open-Falcon 等,這些監(jiān)控系統(tǒng)最終給運(yùn)維人員展示的是一張張二維的折線圖幌陕。Metrics 是可以聚合的诵姜,例如,為電商系統(tǒng)中每個(gè) HTTP 接口添加一個(gè)計(jì)數(shù)器搏熄,計(jì)算每個(gè)接口的 QPS棚唆,之后我們就可以通過簡單的加和計(jì)算得到系統(tǒng)的總負(fù)載情況暇赤。

  • Tracing 即我們常說的分布式鏈路追蹤。在微服務(wù)架構(gòu)系統(tǒng)中一個(gè)請(qǐng)求會(huì)經(jīng)過很多服務(wù)處理宵凌,調(diào)用鏈路會(huì)非常長鞋囊,要確定中間哪個(gè)服務(wù)出現(xiàn)異常是非常麻煩的一件事。通過分布式鏈路追蹤瞎惫,運(yùn)維人員就可以構(gòu)建一個(gè)請(qǐng)求的視圖溜腐,這個(gè)視圖上展示了一個(gè)請(qǐng)求從進(jìn)入系統(tǒng)開始到返回響應(yīng)的整個(gè)流程。這樣瓜喇,就可以從中了解到所有服務(wù)的異常情況挺益、網(wǎng)絡(luò)調(diào)用,以及系統(tǒng)的性能瓶頸等欠橘。

更復(fù)雜的是我們要分析日志之間的血緣關(guān)系矩肩,然后根據(jù)大數(shù)據(jù)進(jìn)行計(jì)算和預(yù)警,輔助我們判斷可能要發(fā)生的系統(tǒng)故障事件肃续。

常見的APM系統(tǒng)有

  • CAT: 由國內(nèi)美團(tuán)點(diǎn)評(píng)開源的黍檩,基于 Java 語言開發(fā),目前提供 Java始锚、C/C++刽酱、Node.js、Python瞧捌、Go 等語言的客戶端棵里,監(jiān)控?cái)?shù)據(jù)會(huì)全量統(tǒng)計(jì)。國內(nèi)很多公司在用姐呐,例如美團(tuán)點(diǎn)評(píng)殿怜、攜程、拼多多等曙砂。CAT 需要開發(fā)人員手動(dòng)在應(yīng)用程序中埋點(diǎn)头谜,對(duì)代碼侵入性比較強(qiáng)。

  • Zipkin: 由 Twitter 公司開發(fā)并開源鸠澈,Java 語言實(shí)現(xiàn)柱告。侵入性相對(duì)于 CAT 要低一點(diǎn),需要對(duì)web.xml 等相關(guān)配置文件進(jìn)行修改笑陈,但依然對(duì)系統(tǒng)有一定的侵入性际度。Zipkin 可以輕松與 Spring Cloud 進(jìn)行集成,也是 Spring Cloud 推薦的 APM 系統(tǒng)涵妥。

  • Pinpoint: 韓國團(tuán)隊(duì)開源的 APM 產(chǎn)品乖菱,運(yùn)用了字節(jié)碼增強(qiáng)技術(shù),只需要在啟動(dòng)時(shí)添加啟動(dòng)參數(shù)即可實(shí)現(xiàn) APM 功能,對(duì)代碼無侵入窒所。目前支持 Java 和 PHP 語言娜氏,底層采用 HBase 來存儲(chǔ)數(shù)據(jù),探針收集的數(shù)據(jù)粒度非常細(xì)墩新,但性能損耗較大,因其出現(xiàn)的時(shí)間較長窟坐,完成度也很高海渊,文檔也較為豐富,應(yīng)用的公司較多哲鸳。

  • SkyWalking: 國人開源的產(chǎn)品臣疑,2019 年 4 月 17 日 SkyWalking 從 Apache 基金會(huì)的孵化器畢業(yè)成為頂級(jí)項(xiàng)目。目前 SkyWalking 支持 Java徙菠、.Net讯沈、Node.js 等探針,數(shù)據(jù)存儲(chǔ)支持MySQL婿奔、ElasticSearch等缺狠。 SkyWalking 與 Pinpoint 相同,Java 探針采用字節(jié)碼增強(qiáng)技術(shù)實(shí)現(xiàn)萍摊,對(duì)業(yè)務(wù)代碼無侵入挤茄。探針采集數(shù)據(jù)粒度相較于 Pinpoint 來說略粗,但性能表現(xiàn)優(yōu)秀冰木。目前穷劈,SkyWalking 增長勢頭強(qiáng)勁,社區(qū)活躍踊沸,中文文檔齊全歇终,沒有語言障礙,支持多語言探針逼龟,這些都是 SkyWalking 的優(yōu)勢所在评凝,還有就是 SkyWalking 支持很多框架,包括很多國產(chǎn)框架审轮,例如肥哎,Dubbo、gRPC疾渣、SOFARPC 等等篡诽,也有很多開發(fā)者正在不斷向社區(qū)提供更多插件以支持更多組件無縫接入 SkyWalking。

還有很多不開源的 APM 系統(tǒng)榴捡,例如杈女,淘寶鷹眼、Google Dapper 等等,不再展開介紹了达椰。

在選擇一款A(yù)PM系統(tǒng)對(duì)系統(tǒng)的侵入是我們需要首要考慮的問題翰蠢,其次是性能問題,所以SkyWalking是我們的最常見選擇啰劲。

那么SkyWalking能為我們做什么梁沧?

  • 服務(wù)、服務(wù)實(shí)例蝇裤、端點(diǎn)指標(biāo)分析廷支。

  • 服務(wù)拓?fù)鋱D分析

  • 服務(wù)、服務(wù)實(shí)例和端點(diǎn)(Endpoint)SLA 分析

  • 慢查詢檢測

  • 告警

SkyWalking的整體架構(gòu)包括三部分

  • Agent(探針):Agent 運(yùn)行在各個(gè)服務(wù)實(shí)例中栓辜,負(fù)責(zé)采集服務(wù)實(shí)例的 Trace 恋拍、Metrics 等數(shù)據(jù),然后通過 gRPC 方式上報(bào)給 SkyWalking 后端藕甩。

  • OAP:SkyWalking 的后端服務(wù)施敢,其主要責(zé)任有兩個(gè)。

    • 一個(gè)是負(fù)責(zé)接收 Agent 上報(bào)上來的 Trace狭莱、Metrics 等數(shù)據(jù)僵娃,交給 Analysis Core (涉及 SkyWalking OAP 中的多個(gè)模塊)進(jìn)行流式分析,最終將分析得到的結(jié)果寫入持久化存儲(chǔ)中贩毕。SkyWalking 可以使用 ElasticSearch悯许、H2、MySQL 等作為其持久化存儲(chǔ)辉阶,一般線上使用 ElasticSearch 集群作為其后端存儲(chǔ)先壕。

    • 另一個(gè)是負(fù)責(zé)響應(yīng) SkyWalking UI 界面發(fā)送來的查詢請(qǐng)求,將前面持久化的數(shù)據(jù)查詢出來谆甜,組成正確的響應(yīng)結(jié)果返回給 UI 界面進(jìn)行展示垃僚。

  • UI 界面:SkyWalking 前后端進(jìn)行分離,該 UI 界面負(fù)責(zé)將用戶的查詢操作封裝為 GraphQL 請(qǐng)求提交給 OAP 后端觸發(fā)后續(xù)的查詢操作规辱,待拿到查詢結(jié)果之后會(huì)在前端負(fù)責(zé)展示谆棺。

SkyWalking 源代碼解讀

SkyWalking使用java agent技術(shù)實(shí)現(xiàn),對(duì)于agent如何無侵入實(shí)現(xiàn)日志記錄和監(jiān)控可以看我之前寫得這篇文章,了解了基礎(chǔ)原理之后我們需要搭建調(diào)試環(huán)境來學(xué)習(xí)源代碼罕袋,可以參考這篇進(jìn)行環(huán)境搭建改淑,最后搭建好的項(xiàng)目結(jié)構(gòu)如下圖

skywalkdingdebug.PNG

上面apm模塊為SkyWalking服務(wù)端,java-agent為客戶端浴讯,另外一個(gè)是演示項(xiàng)目朵夏。

體驗(yàn)微內(nèi)核之美

可以說SkyWalking的服務(wù)端和客戶端都是采用微內(nèi)核設(shè)計(jì),客戶端的入口是SkyWalkingAgent

客戶端代碼解讀

它其實(shí)是一個(gè)java agent的入口類榆纽,需要實(shí)現(xiàn)一個(gè)靜態(tài)的premain方法仰猖,如下


 /**
     * Main entrance. Use byte-buddy transform to enhance all classes, which define in plugins.
     */
    public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
        final PluginFinder pluginFinder;
        try {
            SnifferConfigInitializer.initializeCoreConfig(agentArgs);
        } catch (Exception e) {
            // try to resolve a new logger, and use the new logger to write the error log here
            LogManager.getLogger(SkyWalkingAgent.class)
                    .error(e, "SkyWalking agent initialized failure. Shutting down.");
            return;
        } finally {
            // refresh logger again after initialization finishes
            LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
        }

        try {
            pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
        } catch (AgentPackageNotFoundException ape) {
            LOGGER.error(ape, "Locate agent.jar failure. Shutting down.");
            return;
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent initialized failure. Shutting down.");
            return;
        }

        final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));

        AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(
                nameStartsWith("net.bytebuddy.")
                        .or(nameStartsWith("org.slf4j."))
                        .or(nameStartsWith("org.groovy."))
                        .or(nameContains("javassist"))
                        .or(nameContains(".asm."))
                        .or(nameContains(".reflectasm."))
                        .or(nameStartsWith("sun.reflect"))
                        .or(allSkyWalkingAgentExcludeToolkit())
                        .or(ElementMatchers.isSynthetic()));

        JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
        try {
            agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
            return;
        }

        try {
            agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);
        } catch (Exception e) {
            LOGGER.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down.");
            return;
        }

        if (Config.Agent.IS_CACHE_ENHANCED_CLASS) {
            try {
                agentBuilder = agentBuilder.with(new CacheableTransformerDecorator(Config.Agent.CLASS_CACHE_MODE));
                LOGGER.info("SkyWalking agent class cache [{}] activated.", Config.Agent.CLASS_CACHE_MODE);
            } catch (Exception e) {
                LOGGER.error(e, "SkyWalking agent can't active class cache.");
            }
        }

        agentBuilder.type(pluginFinder.buildMatch())
                    .transform(new Transformer(pluginFinder))
                    .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                    .with(new RedefinitionListener())
                    .with(new Listener())
                    .installOn(instrumentation);

        PluginFinder.pluginInitCompleted();

        try {
            ServiceManager.INSTANCE.boot();
        } catch (Exception e) {
            LOGGER.error(e, "Skywalking agent boot failure.");
        }

        Runtime.getRuntime()
                .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
    }

上面代碼做了以下幾件事件

  • SnifferConfigInitializer.initializeCoreConfig 用來加載客戶端的配置捏肢,這個(gè)類里面有個(gè)全局靜態(tài)Map,后面其它地方可以通用它來使用配置
  • 初始化PluginFinder饥侵,這個(gè)是用來精確匹配需要加載的類
  • 使用BootstrapInstrumentBoost.inject來動(dòng)態(tài)加載應(yīng)用程序依賴類鸵赫,使應(yīng)用程序無感知,其內(nèi)部使用的是框架自己擴(kuò)展的class loader加載類 AgentClassLoader
  • ServiceManager.INSTANCE.boot() 最后遍歷加載服務(wù)類躏升,并啟動(dòng)服務(wù)

我們來看一下ServiceManager.INSTANCE.boot()方法


    public void boot() {
        bootedServices = loadAllServices();

        prepare();
        startup();
        onComplete();
    }

其實(shí)代碼很清晰

  • loadAllServices 加載所有服務(wù)
  • prepare做一些服務(wù)啟動(dòng)前的準(zhǔn)備工作辩棒,其實(shí)是調(diào)用服務(wù)實(shí)現(xiàn)類的prepare方法
  • startup 是調(diào)用服務(wù)類的boot方法來啟動(dòng)服務(wù)
  • onComlete是在服務(wù)啟動(dòng)后給服務(wù)做一些回調(diào)

loadAllServices使用的是JDK SPI加載機(jī)制來加載服務(wù)類,資源文件在resource目錄下面膨疏,加載的服務(wù)有

pictureservice.png

我們來看一下最簡單的JVMService的實(shí)現(xiàn)

JVMService.PNG

可以發(fā)現(xiàn)JVMService其實(shí)是一個(gè)實(shí)現(xiàn)了Runnable接口的實(shí)現(xiàn)類盗温,它的boot方法其實(shí)只是開啟了兩個(gè)定時(shí)調(diào)度的線程池,真正做事情的是run方法成肘,那么run方法如何調(diào)用的呢?


@Override
    public void boot() throws Throwable {
        collectMetricFuture = Executors.newSingleThreadScheduledExecutor(
            new DefaultNamedThreadFactory("JVMService-produce"))
                                       .scheduleAtFixedRate(new RunnableWithExceptionProtection(
                                           this,
                                           new RunnableWithExceptionProtection.CallbackWhenException() {
                                               @Override
                                               public void handle(Throwable t) {
                                                   LOGGER.error("JVMService produces metrics failure.", t);
                                               }
                                           }
                                       ), 0, 1, TimeUnit.SECONDS);
        sendMetricFuture = Executors.newSingleThreadScheduledExecutor(
            new DefaultNamedThreadFactory("JVMService-consume"))
                                    .scheduleAtFixedRate(new RunnableWithExceptionProtection(
                                        sender,
                                        new RunnableWithExceptionProtection.CallbackWhenException() {
                                            @Override
                                            public void handle(Throwable t) {
                                                LOGGER.error("JVMService consumes and upload failure.", t);
                                            }
                                        }
                                    ), 0, 1, TimeUnit.SECONDS);
    }

我們發(fā)現(xiàn)線程池真正調(diào)用的是RunnableWithExceptionProtection斧蜕,傳入的第一個(gè)參數(shù)是this,所以我們猜測就是這個(gè)方法調(diào)用的run方法双霍,結(jié)果確實(shí)如此


public class RunnableWithExceptionProtection implements Runnable {
    private Runnable run;
    private CallbackWhenException callback;

    public RunnableWithExceptionProtection(Runnable run, CallbackWhenException callback) {
        this.run = run;
        this.callback = callback;
    }

    @Override
    public void run() {
        try {
            run.run();
        } catch (Throwable t) {
            callback.handle(t);
        }
    }

    public interface CallbackWhenException {
        void handle(Throwable t);
    }
}
服務(wù)端代碼解讀

服務(wù)端的啟動(dòng)類是OAPServerStartUp,調(diào)用的是OAPServerBootstrap.start方法


/**
 * Starter core. Load the core configuration file, and initialize the startup sequence through {@link ModuleManager}.
 */
@Slf4j
public class OAPServerBootstrap {
    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);

            log.info("Version of OAP: {}", Version.CURRENT);

            if (RunningMode.isInitMode()) {
                log.info("OAP starts up in init mode successfully, exit now...");
                System.exit(0);
            }
        } catch (Throwable t) {
            log.error(t.getMessage(), t);
            System.exit(1);
        }
    }
}

上面的代碼其實(shí)做了三件事情

  • 使用ApplicationConfigLoader加載服務(wù)端配置
  • 將請(qǐng)求委托給ModuleManager處理
  • 使用MetricsCreator上傳服務(wù)啟動(dòng)數(shù)據(jù)

那么ModuleManager又是什么批销?

OAP 使用 ModuleManager(組件管理器)管理多個(gè) Module(組件)洒闸,一個(gè) Module 可以對(duì)應(yīng)多個(gè) ModuleProvider(組件服務(wù)提供者),ModuleProvider 是 Module 底層真正的實(shí)現(xiàn)均芽。
在 OAP 服務(wù)啟動(dòng)時(shí)丘逸,一個(gè) Module 只能選擇使用一個(gè) ModuleProvider 對(duì)外提供服務(wù)。一個(gè) ModuleProvider 可能支撐了一個(gè)非常復(fù)雜的大功能掀宋,在一個(gè) ModuleProvider 中深纲,可以包含多個(gè) Service ,一個(gè) Service 實(shí)現(xiàn)了一個(gè) ModuleProvider 中的一部分功能劲妙,通過將多個(gè) Service 進(jìn)行組裝集成湃鹊,可以得到 ModuleProvider 的完整功能。

OAP.png

ModuleManager就是微內(nèi)核的啟動(dòng)管理類镣奋,ModuleProvider是對(duì)Service進(jìn)行劃分管理币呵,真正的服務(wù)是Service,我們來看一下ModuleManager的init方法


    /**
     * Init the given modules
     */
    public void init(
        ApplicationConfiguration applicationConfiguration) throws ModuleNotFoundException, ProviderNotFoundException, ServiceNotProvidedException, CycleDependencyException, ModuleConfigException, ModuleStartException {
        String[] moduleNames = applicationConfiguration.moduleList();
        ServiceLoader<ModuleDefine> moduleServiceLoader = ServiceLoader.load(ModuleDefine.class);
        ServiceLoader<ModuleProvider> moduleProviderLoader = ServiceLoader.load(ModuleProvider.class);

        HashSet<String> moduleSet = new HashSet<>(Arrays.asList(moduleNames));
        for (ModuleDefine module : moduleServiceLoader) {
            if (moduleSet.contains(module.name())) {
                module.prepare(this, applicationConfiguration.getModuleConfiguration(module.name()), moduleProviderLoader);
                loadedModules.put(module.name(), module);
                moduleSet.remove(module.name());
            }
        }
        // Finish prepare stage
        isInPrepareStage = false;

        if (moduleSet.size() > 0) {
            throw new ModuleNotFoundException(moduleSet.toString() + " missing.");
        }

        BootstrapFlow bootstrapFlow = new BootstrapFlow(loadedModules);

        bootstrapFlow.start(this);
        bootstrapFlow.notifyAfterCompleted();
    }

使用模塊管理的好處是便于服務(wù)管理,同一類服務(wù)可以同時(shí)啟動(dòng)侨颈,服務(wù)與服務(wù)之間可以使用線程隔離余赢,上面的方法其實(shí)只做了兩件事情

  • 使用SPI加載根據(jù)配置加載模塊ModuleProvider和Service,將ModuleDefine加到集合里面
  • 調(diào)用ModuleDefine的prepare方法哈垢,其實(shí)它本質(zhì)是調(diào)用ModuleProvider的prepare方法
  • 將模塊委托給BootstrapFlow進(jìn)行加載啟動(dòng)

我們可以在server-core項(xiàng)目的resource目錄下找到定義的模塊

org.apache.skywalking.oap.server.core.storage.StorageModule
org.apache.skywalking.oap.server.core.cluster.ClusterModule
org.apache.skywalking.oap.server.core.CoreModule
org.apache.skywalking.oap.server.core.query.QueryModule
org.apache.skywalking.oap.server.core.alarm.AlarmModule
org.apache.skywalking.oap.server.core.exporter.ExporterModule

以及ModuleProvider,其實(shí)只有一個(gè)

org.apache.skywalking.oap.server.core.CoreModuleProvider

其實(shí)是CoreModuleProvider是OAP的真正啟動(dòng)類妻柒,這個(gè)類異常復(fù)雜加載了服務(wù)端所有需要注冊和啟動(dòng)的服務(wù),這個(gè)模塊只是核心加載模塊温赔,其它模塊通過loadedProvider屬性持有這個(gè)核心加載模塊的引用

最后我們來看一下BootstrapFlow的start方法


    @SuppressWarnings("unchecked")
    void start(
        ModuleManager moduleManager) throws ModuleNotFoundException, ServiceNotProvidedException, ModuleStartException {
        for (ModuleProvider provider : startupSequence) {
            log.info("start the provider {} in {} module.", provider.name(), provider.getModuleName());
            provider.requiredCheck(provider.getModule().services());

            provider.start();
        }
    }

其實(shí)調(diào)用的是就是ModuleProvider的start方法蛤奢,最后我們看一下coreModuleProvider全貌

coreModuleProvider.PNG

其中prepare和start方法我們剛才都有提到鬼癣,其中start方法啟動(dòng)的是RemoteClientManager這個(gè)service類,其它方面限于篇幅啤贩,有興趣的讀者可以自行研究待秃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痹屹,隨后出現(xiàn)的幾起案子章郁,更是在濱河造成了極大的恐慌,老刑警劉巖志衍,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暖庄,死亡現(xiàn)場離奇詭異,居然都是意外死亡楼肪,警方通過查閱死者的電腦和手機(jī)培廓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來春叫,“玉大人肩钠,你說我怎么就攤上這事≡葜常” “怎么了价匠?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呛每。 經(jīng)常有香客問我踩窖,道長,這世上最難降的妖魔是什么晨横? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任洋腮,我火速辦了婚禮,結(jié)果婚禮上手形,老公的妹妹穿的比我還像新娘徐矩。我一直安慰自己,他們只是感情好叁幢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布滤灯。 她就那樣靜靜地躺著,像睡著了一般曼玩。 火紅的嫁衣襯著肌膚如雪鳞骤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天黍判,我揣著相機(jī)與錄音豫尽,去河邊找鬼。 笑死顷帖,一個(gè)胖子當(dāng)著我的面吹牛美旧,可吹牛的內(nèi)容都是我干的渤滞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼榴嗅,長吁一口氣:“原來是場噩夢啊……” “哼妄呕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗽测,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤绪励,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后唠粥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疏魏,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年晤愧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了大莫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡官份,死狀恐怖葵硕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贯吓,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布蜀变,位于F島的核電站悄谐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏库北。R本人自食惡果不足惜爬舰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寒瓦。 院中可真熱鬧情屹,春花似錦、人聲如沸杂腰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喂很。三九已至惜颇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間少辣,已是汗流浹背凌摄。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漓帅,地道東北人锨亏。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓痴怨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親器予。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浪藻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容