本文涉及源碼都在 這里。
Apache Skywalking(Incubator)簡(jiǎn)介
Apache Skywalking(Incubator) 專(zhuān)門(mén)為微服務(wù)架構(gòu)和云原生架構(gòu)系統(tǒng)而設(shè)計(jì)并且支持分布式鏈路追蹤的APM系統(tǒng)。Apache Skywalking(Incubator)通過(guò)加載探針的方式收集應(yīng)用調(diào)用鏈路信息,并對(duì)采集的調(diào)用鏈路信息進(jìn)行分析,生成應(yīng)用間關(guān)系和服務(wù)間關(guān)系以及服務(wù)指標(biāo)。Apache Skywalking (Incubating)目前支持多種語(yǔ)言,其中包括Java,.Net Core,Node.js和Go語(yǔ)言。
目前Skywalking已經(jīng)支持從6個(gè)可視化維度剖析分布式系統(tǒng)的運(yùn)行情況??傆[視圖是應(yīng)用和組件的全局視圖,其中包括組件和應(yīng)用數(shù)量,應(yīng)用的告警波動(dòng),慢服務(wù)列表以及應(yīng)用吞吐量;拓?fù)鋱D從應(yīng)用依賴(lài)關(guān)系出發(fā),展現(xiàn)整個(gè)應(yīng)用的拓?fù)潢P(guān)系;應(yīng)用視圖則是從單個(gè)應(yīng)用的角度,展現(xiàn)應(yīng)用的上下游關(guān)系,TopN的服務(wù)和服務(wù)器,JVM的相關(guān)信息以及對(duì)應(yīng)的主機(jī)信息。服務(wù)視圖關(guān)注單個(gè)服務(wù)入口的運(yùn)行情況以及此服務(wù)的上下游依賴(lài)關(guān)系,依賴(lài)度,幫助用戶(hù)針對(duì)單個(gè)服務(wù)的優(yōu)化和監(jiān)控;調(diào)用鏈展現(xiàn)了調(diào)用的單次請(qǐng)求經(jīng)過(guò)的所有埋點(diǎn)以及每個(gè)埋點(diǎn)的執(zhí)行時(shí)長(zhǎng);告警視圖根據(jù)配置閾值針對(duì)應(yīng)用、服務(wù)器、服務(wù)進(jìn)行實(shí)時(shí)告警。
英文版文檔:https://github.com/apache/skywalking/blob/master/docs/README.md
中文版文檔:https://skyapm.github.io/document-cn-translation-of-skywalking/
下載并安裝
下載
從 官網(wǎng) 下載合適的壓縮包,如果下載失敗(不知道為啥我下載下來(lái)的是個(gè)空包),可以直接在這個(gè) 鏡像網(wǎng)站 下載。.zip 格式是 Windows 版本,.tar.gz 是 Linux 版本, Mac 也用 .tar.gz 。
本次使用的是目前最新穩(wěn)定版
v6.6.0,而且到時(shí)使用Mysql做數(shù)據(jù)存儲(chǔ),所以我下載的是這個(gè) 壓縮包 。
解壓
解壓壓縮包:
tar -zxvf apache-skywalking-apm-6.6.0.tar.gz
大致目錄樹(shù)結(jié)構(gòu)如下:

簡(jiǎn)單說(shuō)一下這幾個(gè)目錄的作用:
- webapp: UI 前端(
web監(jiān)控頁(yè)面)的jar包和配置文件; - oap-libs: 后臺(tái)應(yīng)用的
jar包,以及它的依賴(lài)jar包,里邊有一個(gè)server-starter-*.jar就是啟動(dòng)程序; - config: 啟動(dòng)后臺(tái)應(yīng)用程序的配置文件,是使用的各種配置
- bin: 各種啟動(dòng)腳本,一般使用腳本
startup.*來(lái)啟動(dòng)web頁(yè)面 和對(duì)應(yīng)的 后臺(tái)應(yīng)用;- oapService.*: 默認(rèn)使用的后臺(tái)程序的啟動(dòng)腳本;(使用的是默認(rèn)模式啟動(dòng),還支持其他模式,各模式區(qū)別見(jiàn) 啟動(dòng)模式)
- oapServiceInit.*: 使用
init模式啟動(dòng);在此模式下,OAP服務(wù)器啟動(dòng)以執(zhí)行初始化工作,然后退出 - oapServiceNoInit.*: 使用
no init模式啟動(dòng);在此模式下,OAP服務(wù)器不進(jìn)行初始化。 - webappService.*: UI 前端的啟動(dòng)腳本;
- startup.*: 組合腳本,同時(shí)啟動(dòng)
oapService.*:、webappService.*腳本;
- agent:
- skywalking-agent.jar: 代理服務(wù)
jar包 - config: 代理服務(wù)啟動(dòng)時(shí)使用的配置文件
- plugins: 包含多個(gè)插件,代理服務(wù)啟動(dòng)時(shí)會(huì)加載改目錄下的所有插件(實(shí)際是各種
jar包) - optional-plugins: 可選插件,當(dāng)需要支持某種功能時(shí),比如
SpringCloud Gateway,則需要把對(duì)應(yīng)的jar包拷貝到plugins目錄下;
- skywalking-agent.jar: 代理服務(wù)
啟動(dòng)后端服務(wù)和前端UI
Skywalking 的后端服務(wù)默認(rèn)使用的數(shù)據(jù)庫(kù)是 h2,而我們需要使用的是 Mysql,所以得修改部分配置。該配置文件是目錄 config 下的 application.yml 文件,將 h2 數(shù)據(jù)庫(kù)相關(guān)配置注釋掉,然后 Mysql 部分去掉注釋?zhuān)?shù)據(jù)庫(kù)名、賬號(hào)密碼修改一下。修改完大致如下:
storage:
... 省略部分
# h2:
# driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
# url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
# user: ${SW_STORAGE_H2_USER:sa}
# metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
mysql:
properties:
jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/skywalking"}
dataSource.user: ${SW_DATA_SOURCE_USER:root}
dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}
dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
注:如果沒(méi)有創(chuàng)建
skywalking數(shù)據(jù)庫(kù),還需要手動(dòng)創(chuàng)建。
因?yàn)?oap-libs 目錄下缺少 mysql 的驅(qū)動(dòng)程序,所以還需要下載 mysql-connector-java-*.jar 放到 oap-libs 目錄下,這里我使用的版本是 5.1.46。一般該 jar 包在本地的 maven 倉(cāng)庫(kù)都有,直接拷貝過(guò)去即可,一般在目錄 ~/.m2/repository/mysql/mysql-connector-java/5.1.46 下。
$ cd apache-skywalking-apm-bin/bin
# 啟動(dòng)
$ ./startup.sh
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!
# 查看啟動(dòng)的服務(wù)
$ jps
17716 RemoteMavenServer
16005 Launcher
4295 OAPServerStartUp
18266 Jps
4301 skywalking-webapp.jar
...
如果看到 OAPServerStartUp 和 skywalking-webapp.jar,那么代表2個(gè)服務(wù)都啟動(dòng)成功。
這時(shí)訪(fǎng)問(wèn) http://localhost:8080/ 即可看到如下頁(yè)面:

至此,Skywalking 的監(jiān)控跟蹤服務(wù)就準(zhǔn)備完畢。
跟蹤分布式服務(wù)
從 這里 克隆到本地,本文用到的子項(xiàng)目為 spring-cloud-advance-skywalking,進(jìn)入該目錄,可以看到包含如下服務(wù):

- sca-skywalking-discovery:服務(wù)發(fā)現(xiàn)
- sca-skywalking-gateway:網(wǎng)關(guān)
- sca-skywalking-licence:
licence服務(wù)。里邊部分接口回調(diào)用organization服務(wù)的接口。 - sca-skywalking-organization:
organization服務(wù)。
啟動(dòng)服務(wù)
在 安裝Java agent 中,提到了在啟動(dòng)應(yīng)用之前,需要配置JVM參數(shù),添加 -javaagent:/path/to/skywalking-package/agent/skywalking-agent.jar。為了方便這里以在 IDEA 中啟動(dòng)服務(wù)為例:


儀表盤(pán)(Dashboard)
啟動(dòng)4個(gè)服務(wù)后,再次訪(fǎng)問(wèn) http://localhost:8080/ ,可以看到類(lèi)似如下:

拓?fù)鋱D(Topology)
再看下拓?fù)鋱D:

Your_Application_Name: 服務(wù)名
localhost-1: 數(shù)據(jù)庫(kù)。因?yàn)榉?wù) licence-service, organization 使用了 H2 數(shù)據(jù)庫(kù)
User: 暫時(shí)不知道是干啥的,以后知道了再補(bǔ)充(難道是skywalking的用戶(hù)服務(wù)?)
那么問(wèn)題來(lái)了,為什么啟動(dòng)了4個(gè)服務(wù),這里只有一個(gè) Your_Application_Name 服務(wù)?
其實(shí)在 安裝Java agent 中,有提到需要配置 config/agent.config 中的 agent.service_name。但我們這里需要啟動(dòng)的服務(wù)有多個(gè),直接配置在文件中肯定不合適,難道啟動(dòng)一個(gè)服務(wù)改一次?
我們先來(lái)看下 config/agent.config 中的 agent.service_name 配置,如下:
# The service name in UI
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
... 省略前后其他配置
可以看到,屬性 agent.service_name 的 value 其實(shí)是占位符,優(yōu)先使用 SW_AGENT_NAME 的值,那這個(gè)到底是什么呢?其實(shí)是環(huán)境變量,如果啟動(dòng)時(shí)環(huán)境變量 SW_AGENT_NAME 有值的話(huà),那么使用它,否則使用默認(rèn)值 Your_ApplicationName。
所以這就不難解釋在拓?fù)鋱D中看到的只有一個(gè) Your_ApplicationName,因?yàn)樗蟹?wù)啟動(dòng)時(shí),都使用了同一份 agent.config 配置,skywalking 認(rèn)為這4個(gè)服務(wù)都是服務(wù)名為 Your_ApplicationName 的4個(gè)實(shí)例。
所以我們可以在啟動(dòng)時(shí)配置一下環(huán)境變量即可。如下:

把4個(gè)服務(wù)都配置了 SW_AGENT_NAME 環(huán)境變量后,重新啟動(dòng)。
再看下拓?fù)鋱D,會(huì)變成下面這樣:

這樣就比較符合我們的預(yù)期了。因?yàn)?skywalking 有一定緩存機(jī)制,當(dāng)服務(wù)不可用后,不會(huì)立即刪除(Your_ApplicationName),等過(guò)一段時(shí)間后會(huì)自動(dòng)清清除。
請(qǐng)求追蹤
多次訪(fǎng)問(wèn) http://localhost:3100/licence/1,然后切到 追蹤 標(biāo)簽頁(yè),可以看到類(lèi)似如下:

正常的請(qǐng)求長(zhǎng)這樣:

可以看到,一個(gè)請(qǐng)求的所有調(diào)用鏈都被記錄下來(lái),包括 Spring MVC 的內(nèi)部轉(zhuǎn)發(fā)、跨服務(wù)的 http 調(diào)用以及數(shù)據(jù)庫(kù)查詢(xún),都完整的記錄下來(lái),而且也記錄了整個(gè)請(qǐng)求以及各個(gè)子步驟的耗時(shí)。
但是,有2個(gè)問(wèn)題,第一,為啥沒(méi)有記錄網(wǎng)關(guān)層的調(diào)用鏈?第二,我剛剛其實(shí)只請(qǐng)求了幾次,為什么會(huì)有151頁(yè)數(shù)據(jù)?帶著這2個(gè)問(wèn)題,我們繼續(xù)挖掘 Skywalking 的新特性。
使用 optional-plugins
兼容 SpringCloud Gateway
前面提到,agent 目錄下有 plugins 和 optional-plugins 2個(gè)目錄,skywalking-agent.jar 在啟動(dòng)時(shí)會(huì)加載 plugins 下的所有插件,但不會(huì)加載 optional-plugins 下的,其實(shí)看目錄名就知道了,可選插件 就是可有可沒(méi)有,需要等需要的時(shí)候再加到 plugins 下即可。
我們看到, optional-plugins 下就有跟 SpringCloud Gateway 相關(guān)的插件,那就它了,把它丟到 plugins 目錄下。

但是又有一個(gè)問(wèn)題,為什么 SpringCloud Gateway 這么特殊呢,為啥沒(méi)一個(gè)類(lèi)似 apm-spring-cloud-zuul-plugin-6.6.0.jar 的插件呢?這2個(gè)網(wǎng)關(guān)有啥本質(zhì)上的區(qū)別嗎?肯定有的啦,一個(gè)是同步的,另一個(gè)是異步(底層用了 netty,還依賴(lài) spring-webflux)。另外,我們還注意到另一個(gè)插件 apm-spring-webflux-5.x-plugin-6.6.0.jar,把它也丟到 plugins 目錄下。
最后,重啟4個(gè)服務(wù),再訪(fǎng)問(wèn) http://localhost:3100/licence/1,可以看到如下:

這樣,第一個(gè)問(wèn)題就解決了。
自定義忽略追蹤部分請(qǐng)求
首先,我們不妨跳到50頁(yè),如下:

可以看到所有都是跟 eureka 相關(guān),看到這里,如果你比較熟悉 eureka 的底層邏輯,那么基本就能猜出來(lái)啥原因了:EurekaClient 每隔一段時(shí)間都會(huì)向 EurekaServer 請(qǐng)求續(xù)約,也可以理解為心跳,還有定時(shí)從 EurekaServer 拉取最新的可用的服務(wù)清單。
這種記錄這些請(qǐng)求對(duì)我們來(lái)說(shuō)用處不大,而且還會(huì)造成大量垃圾數(shù)據(jù),所以應(yīng)該避免追蹤,但 Skywalking 并不能自己識(shí)別出來(lái),拿只能我們教它怎么分辨了。
注意到,optional-plugins 中有這樣的插件 apm-trace-ignore-plugin-6.6.0.jar,把它丟到 plugins 目錄下先。
加上插件只是讓 Skywalking 擁有忽略某些請(qǐng)求的能力,但還需要我們指定哪些需要忽略。下載 配置文件,然后把它丟到 /agent/config/ 目錄下,增加過(guò)濾規(guī)則。里邊的內(nèi)容如下:
# If the operation name of the first span is matching, this segment should be ignored
# ant path match style
# /path/? Match any single character
# /path/* Match any number of characters
# /path/** Match any number of characters and support multilevel directories
# Multiple path comma separation, like trace.ignore_path=/eureka/**,/consul/**
#trace.ignore_path=${SW_AGENT_TRACE_IGNORE_PATH:/eureka/**}
可以看到插件的開(kāi)發(fā)者已經(jīng)幫我們考慮到 eureka 這種情況了,直接去掉最后一行的注釋即可,當(dāng)然,也可以跟服務(wù)名一樣使用環(huán)境變量配置。另外,eureka-server 因?yàn)椴皇俏覀兊臉I(yè)務(wù)服務(wù),所以可以考慮不對(duì)它進(jìn)行代理,即去掉 JVM 參數(shù)配置。
最后,重啟4個(gè)服務(wù),再訪(fǎng)問(wèn) http://localhost:3100/licence/1,可以看到如下:

可以看到清爽很多,沒(méi)有太多冗余的請(qǐng)求。
相關(guān)配置可參考:支持忽略自定義的traceSupport custom trace ignore
相關(guān)鏈接
官網(wǎng):https://skywalking.apache.org/
英文版文檔:https://github.com/apache/skywalking/blob/master/docs/README.md
中文版文檔:https://skyapm.github.io/document-cn-translation-of-skywalking/
配置覆蓋:https://skyapm.github.io/document-cn-translation-of-skywalking/zh/master/setup/service-agent/java-agent/Setting-override.html