5、Skywalking的埋點(diǎn)-插件化架構(gòu)設(shè)計(jì)

插件化架構(gòu)設(shè)計(jì)

插件化架構(gòu)另一種叫法是微內(nèi)核架構(gòu),是一種面向功能進(jìn)行拆分的可擴(kuò)展性架構(gòu),通常用于存在多個(gè)版本、需要下載安裝或激活才能使用的客戶端應(yīng)用;包含兩類組件:核心系統(tǒng)(core system)和插件模塊(plug-in modules)

  • 核心系統(tǒng) Core System 功能比較穩(wěn)定,不會(huì)因?yàn)闃I(yè)務(wù)功能擴(kuò)展而不斷修改,通常負(fù)責(zé)和具體業(yè)務(wù)功能無(wú)關(guān)的通用功能,例如模塊加載等
  • 插件模塊負(fù)責(zé)實(shí)現(xiàn)具體的業(yè)務(wù)邏輯,可以根據(jù)業(yè)務(wù)功能的需要不斷地?cái)U(kuò)展,將變化部分封裝在插件里面,從而達(dá)到快速靈活擴(kuò)展的目的,而又不影響整體系統(tǒng)的穩(wěn)定

如下圖所示:

Skywalking的插件化實(shí)現(xiàn)

Skywalking中每個(gè)組件的埋點(diǎn)實(shí)現(xiàn)就是一個(gè)插件,針對(duì)有差異的版本也可能一個(gè)組件有多個(gè)實(shí)現(xiàn),分別應(yīng)對(duì)不同的版本。

組件加載管理的核心流程

Skywalking是對(duì)這些組件埋點(diǎn)插件的加載管理的大致流程如下:

  1. 初始化配置,并明確插件所在的路徑。
  2. 在給定的路徑下查找并解析 skywalking-plugin.def 插件文件。
  3. 通過(guò)獨(dú)立的類加載器AgentClassLoader 加載插件類。
  4. 通過(guò)PluginFinder對(duì)插件進(jìn)行管理分類。
  5. 使用 Byte Buddy 字節(jié)碼增強(qiáng)庫(kù)創(chuàng)建 AgentBuilder,其會(huì)根據(jù)已加載的插件動(dòng)態(tài)增強(qiáng)目標(biāo)類,插入埋點(diǎn)邏輯。
  6. 使用 JDK的SPI 加載并啟動(dòng) BootService 服務(wù)。BootService就理解為通常我們編寫(xiě)的Service服務(wù),就是功能的內(nèi)聚封裝。
  7. 添加一個(gè) JVM 鉤子,在 JVM 退出時(shí)關(guān)閉所有 BootService 服務(wù)。

下邊通過(guò)關(guān)鍵技術(shù)點(diǎn)的拆解,進(jìn)一步理解上述的流程。

1. 初始化配置

這里有3層配置,其過(guò)程以及覆蓋原理如下:

  1. 解析/agent/config/agent.config,獲取配置,填充到Config中
  2. 遍歷環(huán)境變量(即 System.getProperties() 集合),查找"skywalking." 開(kāi)頭的配置 更新Config中的值
  3. 解析 Java Agent 的參數(shù),更新Config中的值
2. 自定義ClassLoader

SkyWalking 的Agent 加載插件時(shí)使用到一個(gè)自定義的ClassLoader :AgentClassLoader,有了這個(gè)AgentClassLoader,就不會(huì)在應(yīng)用的 Classpath 中引入 SkyWalking 的插件 jar 包,來(lái)達(dá)到對(duì)插件的管理讓?xiě)?yīng)用無(wú)依賴、無(wú)感知的目的。

AgentClassLoader掃描并加載指定Agent目錄下的plugins和 activations 目錄中的插件jar包。

3. 解析插件定義

當(dāng)自定義類加載器掃描到插件jar,除了要加載類之外,還有最重要的一個(gè)目的,要明確的知道這個(gè)插件jar要增強(qiáng)組件中的哪些類以及如何增強(qiáng),而承載這些信息的類被skywalking約定在每個(gè)插件jar包的resource目錄下skywalking-plugin.def 文件中,其中其中每一行都是一個(gè)插件類的定義,如tomcat-7.x-8.x-plugin 插件中 skywalking-plugin.def 文件的內(nèi)容如下:

tomcat-7.x/8.x=org.apache.skywalking.apm.plugin.tomcat78x.define 
.TomcatInstrumentation

tomcat-7.x/8.x=org.apache.skywalking.apm.plugin.tomcat78x.define
.ApplicationDispatcherInstrumentation

插件類中指定了待增強(qiáng)的類、方法,以及增強(qiáng)的邏輯,體現(xiàn)在AbstractClassEnhancePluginDefine類以及其內(nèi)部的幾個(gè)方法上:

  • enhanceClass() 方法:返回的 ClassMatch,用于匹配當(dāng)前插件要增強(qiáng)的目標(biāo)類。
  • define() :插件類增強(qiáng)邏輯的入口,采用了模板方法的設(shè)計(jì)模式,實(shí)現(xiàn)中會(huì)調(diào)用下面的 enhance() 方法和 witnessClass() 方法。
  • enhance() :真正執(zhí)行增強(qiáng)邏輯的地方。
  • witnessClass() :一個(gè)開(kāi)源組件可能有多個(gè)版本,通過(guò)該方法識(shí)別組件的不同版本,防止對(duì)不兼容的版本進(jìn)行增強(qiáng)。
  • getConstructorsInterceptPoints() :構(gòu)造方法的切入點(diǎn),并指定增強(qiáng)的邏輯實(shí)現(xiàn)
  • getInstanceMethodsInterceptPoints():實(shí)例方法切入點(diǎn),并指定增強(qiáng)的邏輯實(shí)現(xiàn)
  • getStaticMethodsInterceptPoints():靜態(tài)方法切入點(diǎn),并指定增強(qiáng)的邏輯實(shí)現(xiàn)
4. PluginFinder

JavaAgent 啟動(dòng)時(shí)掛在的運(yùn)行機(jī)制是當(dāng)一個(gè)類被首次加載的時(shí)候,會(huì)給我們機(jī)會(huì)進(jìn)行字節(jié)碼增強(qiáng)處理,即回調(diào)transform方法,在這個(gè)方法中傳入被加載,待增強(qiáng)類,sw需找到跟這個(gè)類匹配的所有的插件類,這個(gè)工作就由PluginFinder來(lái)完成。簡(jiǎn)單來(lái)說(shuō)就是根據(jù)傳入的新加載的類,查找與其匹配的執(zhí)行增強(qiáng)處理的 AbstractClassEnhancePluginDefine 集合。

5. AgentBuilder

AgentBuilder 是 Byte Buddy 庫(kù)專門(mén)用來(lái)支持 Java Agent 的一個(gè) API,其作用是方便使用者配置增強(qiáng)哪些類,忽略哪些package,對(duì)于要增強(qiáng)的類,回傳給指定的transform方法執(zhí)行增強(qiáng),在這個(gè)transform方法中會(huì)調(diào)用PluginFinder的查找增強(qiáng)類的功能,找到增強(qiáng)類,然后通過(guò)其define方法對(duì)目標(biāo)類執(zhí)行增強(qiáng)。

6. BootService

Skywalking的Agent端,也需要跟OAPServer之間進(jìn)行各種交互以提供豐富完善的功能,比如trace數(shù)據(jù)的上傳,Metric數(shù)據(jù)上傳,配置的拉取等等。skywalking中約定,這些功能邏輯要內(nèi)聚后,封裝到不同的BootService中,比如:

  • ConfigurationDiscoveryService //檢測(cè)配置更新
  • KafkaJVMMetricsSender//向Kafka發(fā)送Metric
  • KafkaTraceSegmentServiceClient//通過(guò)Kafka發(fā)送Trace
  • TraceSegmentServiceClient//通過(guò)gRPC發(fā)送Trace

BootService是在Skywalking中由ServiceManager通過(guò)SPI的方式進(jìn)行管理,在META-INF.services中可以看到BootService全限定名的文件,文件中列出了當(dāng)前Jar包中的所有的暴露出去提供服務(wù)的BootService的實(shí)現(xiàn)類。

image.png

org.apache.skywalking.apm.agent.core.remote.TraceSegmentServiceClient
org.apache.skywalking.apm.agent.core.context.ContextManager
org.apache.skywalking.apm.agent.core.sampling.SamplingService
org.apache.skywalking.apm.agent.core.remote.GRPCChannelManager
org.apache.skywalking.apm.agent.core.jvm.JVMMetricsSender
org.apache.skywalking.apm.agent.core.jvm.JVMService
org.apache.skywalking.apm.agent.core.remote.ServiceManagementClient
org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService
org.apache.skywalking.apm.agent.core.commands.CommandService
org.apache.skywalking.apm.agent.core.commands.CommandExecutorService
org.apache.skywalking.apm.agent.core.profile.ProfileTaskChannelService
org.apache.skywalking.apm.agent.core.profile.ProfileSnapshotSender
org.apache.skywalking.apm.agent.core.profile.ProfileTaskExecutionService
org.apache.skywalking.apm.agent.core.meter.MeterService
org.apache.skywalking.apm.agent.core.meter.MeterSender
org.apache.skywalking.apm.agent.core.context.status.StatusCheckService
org.apache.skywalking.apm.agent.core.remote.LogReportServiceClient
org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService
org.apache.skywalking.apm.agent.core.remote.EventReportServiceClient
org.apache.skywalking.apm.agent.core.ServiceInstanceGenerator

Skywalking中可以定義默認(rèn)的服務(wù)并且可以定義新的服務(wù)來(lái)覆蓋默認(rèn)的服務(wù),通過(guò)= BootService 上的 @DefaultImplementor@OverrideImplementor 注解來(lái)實(shí)現(xiàn):

  1. @DefaultImplementor 注解用于標(biāo)識(shí) BootService 接口的默認(rèn)實(shí)現(xiàn)。
  2. @OverrideImplementor 注解用于覆蓋默認(rèn) BootService 實(shí)現(xiàn),通過(guò)其 value 字段指定要覆蓋的默認(rèn)實(shí)現(xiàn),比如KafkaJVMMetricsSender覆蓋JVMMetricsSender
@OverrideImplementor(JVMMetricsSender.class)
public class KafkaJVMMetricsSender extends JVMMetricsSender 

ServiceManager 將統(tǒng)一初始化 BootServices 集合中的 BootService 實(shí)現(xiàn),同樣是在 ServiceManager#boot 方法中,會(huì)逐個(gè)調(diào)用 BootService實(shí)現(xiàn)的 prepare()、startup()onComplete()方法

在 JVM 退出時(shí),通過(guò)鉤子關(guān)閉所有 BootService 服務(wù),通過(guò)調(diào)用ServiceManagershutdown方法,遍歷其熟悉bootServices集合,并調(diào)用他們shutdown方法來(lái)關(guān)閉所有的BootService`。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容