1. 概述
本文主要分享 SkyWalking Collector 啟動初始化的過程。在分享的過程中,我們會簡單介紹 Collector 每個子產品及其用途。
ps :Collector 是 SkyWalking 的 Server 端。整體如下圖 :
FROM https://github.com/apache/incubating-skywalking
2. CollectorBootStartUp
org.skywalking.apm.collector.boot.CollectorBootStartUp
,在
apm-sniffer/apm-agent
Maven 子產品項目裡,SkyWalking Collector 啟動入口。
#main(args)
方法,啟動 Collector ,代碼如下 :
- 第 45 行 :調用
方法,加載 Collector 配置。ApplicationConfiguration#load()
- 第 47 行 :調用
方法,初始化 Collector 元件們。ModuleManager#init(...)
- 第 60 行 :調用
方法,等待 Collector 内嵌的 Jetty Server 啟動完成。Thread#sleep(60000)
2. ApplicationConfigLoader
org.skywalking.apm.collector.boot.config.ApplicationConfigLoader
,實作
org.skywalking.apm.collector.boot.config.ConfigLoader
接口,Collector 配置(
org.skywalking.apm.collector.core.module.ApplicationConfiguration
)加載器。
在看具體代碼實作之前,我們先了解下 ApplicationConfiguration 整體類結構。如下圖所示 :
- Collector 使用元件管理器( ModuleManager ),管理多個元件( Module )。
- 一個元件有多種元件服務提供者( ModuleProvider ),同時一個元件隻允許使用一個元件服務提供者。這塊下面會有代碼解析說明。
- Collector 使用一個應用配置類( ApplicationConfiguration )。
- 一個應用配置類包含多個元件配置類( ModuleConfiguration )。每個元件對應一個元件配置類。
- 一個元件配置類包含多個元件服務提供者配置( ProviderConfiguration )。每個元件服務提供者對應一個元件配置類。注意:因為一個元件隻允許同時使用一個元件服務提供者,是以一個元件配置類隻設定一個元件服務提供者配置。
- 整個配置檔案,對應應用配置類。綠框部分,對應一個元件配置類。紅框部分,對應一個元件服務提供者配置類。
下面,我們來看看
ApplicationConfigLoader#load()
方法,代碼如下 :
- 第 47 行 :調用
方法,從#loadConfig()
的apm-collector-core
加載自定義配置。application.yml
- 第 49 行 :調用
方法,從#loadDefaultConfig()
的apm-collector-core
加載預設配置。application-default.yml
- 兩個方法邏輯基本一緻,已經添加代碼注釋,胖友自己閱讀了解。
3. ModuleManager
org.skywalking.apm.collector.core.module.ModuleManager
,元件管理器,負責元件的管理與初始化。
#init()
方法,初始化元件們,代碼如下 :
- 第 51 至 53 行 :調用
方法,加載所有 Module 實作類的執行個體數組。ServiceManager 基于 SPI (Service Provider Interface) 機制,在每個java.util.ServiceLoader#load(Module.class)
項目的apm-collector-xxx-define
檔案裡,定義了該項目 Module 的實作類。如果胖友對 SPI 機制不熟悉,可以看下如下文章 :/resources/META-INF.services/org.skywalking.apm.collector.core.module.Module
- 《SPI 和 ServiceLoader》
- 《跟我學Dubbo系列之Java SPI機制簡介》
- 第 55 至 75 行 :周遊所有 Module 實作類的執行個體數組,建立在配置中的 Module 實作類的執行個體,并執行 Module 準備階段的邏輯,後添加到加載的元件執行個體的映射(
)。loadedModules
- 第 59 至 67 行 :建立 Module 對象。
- 第 69 行 :調用
方法,執行 Module 準備階段的邏輯。在改方法内部,會建立 Module 對應的 ModuleProvider 。在 「3.1 Module」 詳細解析。Module#prepare(...)
- 第 71 行 :添加到
。loadedModules
- 第 77 至 80 行 :校驗在配置中的 Module 實作類的執行個體都建立了,否則抛出異常。
- 第 84 行 :調用
方法,執行 Module 啟動邏輯。「3.4 BootstrapFlow」 詳細解析。BootstrapFlow#start(...)
- 第 86 行 :調用
方法,執行 Module 啟動完成,通知 ModuleProvider 。「3.4 BootstrapFlow」 詳細解析。BootstrapFlow#notifyAfterCompleted()
- 總的來說,Module 初始化的過程,可以了解成三個階段,如下圖所示 :
3.1 Module
org.skywalking.apm.collector.core.module.Module
,元件抽象類。通過實作 Module 抽象類,實作不同功能的元件。目前 Collector 的 Module 實作類如下圖 :
#name()
抽象方法,獲得元件名。目前元件名有 :
#providers()
方法,獲得 ModuleProvider 數組。實際上,一個 Module 同時隻能有一個 ModuleProvider ,參見
#provider()
方法。
#services()
抽象方法,獲得 Service 類數組。具體 Service 對象,在 ModuleProvider 對象裡擷取,參見
#getService(serviceType)
方法。
#prepare(...)
方法,執行 Module 準備階段的邏輯,代碼如下 :
- 第 69 行 :調用
方法,加載所有 ModuleProvider 實作類的執行個體數組。ServiceManager 基于 SPI (Service Provider Interface) 機制,在每個java.util.ServiceLoader#load(ModuleProvider.class)
項目的apm-collector-xxx-yyy-provider
檔案裡,定義了該項目 ModuleProvider 的實作類。/resources/META-INF.services/org.skywalking.apm.collector.core.module.ModuleProvider
- 第 72 至 93 行 :周遊所有 ModuleProvider 實作類的執行個體數組,建立在配置中的 ModuleProvider 實作類的執行個體,後添加到加載的元件服務提供者執行個體的映射(
)。loadedProviders
- 第 95 至 98 行 :校驗有 ModuleProvider 初始化,否則抛出異常。
- 第 100 至 104 行 :調用
方法,執行 ModuleProvider 準備階段的邏輯。在改方法内部,會建立 ModuleProvider 對應的 Service 。在 「3.2 ModuleProvider」 詳細解析。ModuleProvider#prepare(...)
3.2 ModuleProvider
org.skywalking.apm.collector.core.module.ModuleProvider
,元件服務提供者抽象類。通過實作 ModuleProvider 抽象類,實作不同功能的元件服務提供者。目前 Collector 的 ModuleProvider 實作類如下圖 :
#name()
抽象方法,獲得元件服務提供者名。目前元件服務提供者名有 :
#module()
抽象方法,獲得 ModuleProvider 對應的 Module 類。注意,ModuleProvider 的名字可以重複,例如上圖的
jetty
,通過對應的 Module 類來區分。
#requiredModules()
抽象方法,獲得 ModuleProvider 依賴的 Module 名字數組。
———- Service 相關方法 Begin ———-
#registerServiceImplementation(Class<? extends Service>, Service)
方法,注冊 Service 對象。一個 ModuleProvider 可以有 0 到 N 個 Service 對象。
#getService(Class<T>)
方法,獲得 Service 對象。
#requiredCheck(...)
方法,校驗 ModuleProvider 包含的 Service 們都建立成功。
- 方法參數,從
方法獲得。Module#services()
- 該方法會被
方法調用,在 「3.4 BootstrapFlow」 詳細解析。BootstrapFlow#start()
———- Service 相關方法 End ———-
#prepare(Properties)
抽象方法,執行 ModuleProvider 準備階段的邏輯:Service 的建立,私有變量的建立等等。例如,
StorageModuleH2Provider#prepare(Properties)
。
#start(Properties)
抽象方法,執行 ModuleProvider 啟動階段的邏輯:私有變量的初始化等等。例如,
StorageModuleH2Provider#start(Properties)
。
- 該方法會被
方法調用,在 「3.4 BootstrapFlow」 詳細解析。BootstrapFlow#start()
#notifyAfterCompleted()
抽象方法,執行 ModuleProvider 啟動完成階段的邏輯:私有變量的初始化等等。例如,
StorageModuleEsProvider#notifyAfterCompleted(Properties)
。
- 該方法會被
方法調用,在 「3.4 BootstrapFlow」 詳細解析。BootstrapFlow#notifyAfterCompleted()
3.3 Service
org.skywalking.apm.collector.core.module.Service
,服務接口。通過實作 Service 接口,實作不同功能的服務。目前 Collector 的 Service 實作類如下圖 :
這裡有一點要注意下,實際上 Module 是與 Service “直接” 一對多的關系。中間 有一層 ModuleProvider 存在的原因是,相同 Module 可以有多種 ModuleProvider 實作,而 ModuleProvider 提供提供相同功能的 Service ,但是實作不同。
以
apm-collector-storage
舉例子,如下圖所示 :
- StorageModuleEsProvider / StorageModuleH2Provider 分别基于 ES / H2 實作,其提供存儲相同資料的不同實作。例如 :
一般
collector-xxx-define
的
service
包下,會定義目前子產品提供的 Service 接口,如下圖所示 :
這也是為什麼有
Module#services()
和
#requiredCheck(Class<? extends Service>[])
這樣的方法涉及的原因。
另外,如下是 Service 接口的解釋:
The
Service
implementation is a service provided by its own modules.
And every {@link ModuleProvider} must provide all the given services of the {@link Module}.
3.4 BootstrapFlow
org.skywalking.apm.collector.core.module.BootstrapFlow
,元件啟動流程。
BootstrapFlow 構造方法,調用
#makeSequence()
方法,獲得 ModuleProvider 啟動順序,這個是該類的重點。
#start()
方法,執行 Module 啟動邏輯。
- 第 54 至 63 行 :校驗依賴 Module 已經都存在。
- 第 67 行 :校驗 ModuleProvider 包含的 Service 們都建立成功。
- 第 70 行 :調用
方法,執行 ModuleProvider 啟動階段邏輯。ModuleProvider#start(...)
#notifyAfterCompleted()
方法,調用
ModuleProvider#notifyAfterCompleted()
方法,執行 ModuleProvider 啟動完成階段的邏輯。