Skywalking分布式鏈路追蹤入門
今天帶大家了解一款分布式鏈路追蹤軟件,為什么要介紹鏈路追蹤呢?
當(dāng)前互聯(lián)網(wǎng)行業(yè)發(fā)展紅火,業(yè)務(wù)也越來(lái)越復(fù)雜、龐大,單機(jī)應(yīng)用已經(jīng)無(wú)法滿足日常需求,分布式、微服務(wù)架構(gòu)應(yīng)運(yùn)而生。在微服務(wù)的環(huán)境中,存在日常系統(tǒng)的層層調(diào)用,會(huì)不停的在各個(gè)服務(wù)中進(jìn)行,如果沒(méi)有一個(gè)調(diào)用鏈路的完整記錄,排查問(wèn)題將會(huì)異常困難。
APM(應(yīng)用性能管理)
針對(duì)上面描述的情況,apm給大家?guī)?lái)了解決方案,目前業(yè)界常見(jiàn)的一些 APM 工具主要有: Cat、Zipkin、Pinpoint、SkyWalking。
本文主要介紹 SkyWalking ,它是一款優(yōu)秀的國(guó)產(chǎn) APM 工具,并且已經(jīng)成為了apache基金會(huì)的頂級(jí)項(xiàng)目,它包括了分布式追蹤、性能指標(biāo)分析、應(yīng)用和服務(wù)依賴分析等。
skywalking入門
軟件安裝不做描述,大家可以自行查閱資料。
官方地址:https://skywalking.apache.org/
先來(lái)看下軟件的運(yùn)行界面,如下圖


介紹下skywalking中重要的三個(gè)概念
- 服務(wù)(Service):指服務(wù)集群
- 端點(diǎn)(Endpoint):對(duì)外的接口
- 實(shí)例(Instance):指集群中的實(shí)例
skywalking架構(gòu)圖

可以將skywalking看成三大塊,第一塊為數(shù)據(jù)采集,第二塊則是skywalking服務(wù),第三塊是數(shù)據(jù)存儲(chǔ)。
如何將項(xiàng)目接入skywalking呢?
skywalking的接入非常簡(jiǎn)單,只需要指定java啟動(dòng)參數(shù)即可,如下圖

- // 指定運(yùn)行的java agent
- -javaagent:D:\soft\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar
- // 設(shè)置該程序,在skywalking中的名字
- -Dskywalking.agent.service_name=stressTest
- // skywalking管理端口
- -Dskywalking.collector.backend_service=localhost:11800
skywalking原理
大家看到上面的應(yīng)用案例中,有下面的代碼
- -javaagent:/path/to/skywalking-agent.jar
如果對(duì)javaagent了解的話,就知道了,其實(shí)skywalking的原理就是使用java agent(java探針)。Java agent是java命令的一個(gè)參數(shù)。參數(shù) javaagent 可以用于指定一個(gè) jar 包。
- 這個(gè) jar 包的 MANIFEST.MF 文件必須指定 Premain-Class 項(xiàng)。
- Premain-Class 指定的那個(gè)類必須實(shí)現(xiàn) premain() 方法。
當(dāng)Java 虛擬機(jī)啟動(dòng)時(shí),在執(zhí)行 main 函數(shù)之前,JVM 會(huì)先運(yùn)行 -javaagent 所指定 jar 包內(nèi) Premain Class 這個(gè)類的 premain 方法 。
自己實(shí)現(xiàn)Java agent
下面我們簡(jiǎn)單寫(xiě)一個(gè)java agent
agent代碼
- public class MyAgent {
- /**
- * agentArgs 是 premain 函數(shù)得到的程序參數(shù),隨同 “– javaagent”一起傳入。
- * Inst 是一個(gè) java.lang.instrument.Instrumentation 的實(shí)例,由 JVM 自動(dòng)傳入。
- */
- public static void premain(String agentArgs, Instrumentation inst) {
- System.out.println("=========premain方法執(zhí)行1========");
- System.out.println(agentArgs); }
- /**
- * 如果不存在 premain(String agentArgs, Instrumentation inst)
- * 則會(huì)執(zhí)行 premain(String agentArgs)
- */
- public static void premain(String agentArgs) {
- System.out.println("=========premain方法執(zhí)行2========");
- System.out.println(agentArgs);
- }
- }
為了不去手動(dòng)寫(xiě)MANIFREST.MF文件,我們引入maven插件
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <version>3.1.0</version>
- <configuration>
- <archive>
- <!--自動(dòng)添加META-INF/MANIFEST.MF -->
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- <manifestEntries>
- <Premain-Class>com.example.agent.PreMainAgent</Premain-Class>
- </manifestEntries>
- </archive>
- </configuration>
- </plugin>
執(zhí)行mvn clean package打包程序,會(huì)得到myAgent.jar如下圖

編寫(xiě)主程序
- public class Test {
- public static void main(String[] args) {
- System.out.println("主程序...");
- }
- }
idea啟動(dòng)時(shí)指定agent,如下圖

執(zhí)行主程序結(jié)果如下:
- =========premain方法執(zhí)行1========
- null
- 主程序...
主程序...
可以看到premain方法執(zhí)行了,且沒(méi)有傳入?yún)?shù),如果需要傳入?yún)?shù)javagent屬性如下設(shè)置即可:
- -javaagent:/Users/ganhuojun/code/myagent/target/myAgent.jar=abc