使用 SpringCloud(Gateway) + Skywalking + Mysql 做分布式跟蹤

本文涉及源碼都在 這里

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 CoreNode.jsGo語(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.gzLinux 版本, 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é)構(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 目錄下;

啟動(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
...

如果看到 OAPServerStartUpskywalking-webapp.jar,那么代表2個(gè)服務(wù)都啟動(dòng)成功。

這時(shí)訪(fǎng)問(wèn) http://localhost:8080/ 即可看到如下頁(yè)面:

監(jiān)控頁(yè)面

至此,Skywalking 的監(jiān)控跟蹤服務(wù)就準(zhǔn)備完畢。

跟蹤分布式服務(wù)

這里 克隆到本地,本文用到的子項(xiàng)目為 spring-cloud-advance-skywalking,進(jìn)入該目錄,可以看到包含如下服務(wù):

目錄結(jié)構(gòu)

  • 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ù)為例:

edit configurations

add jvm params

儀表盤(pán)(Dashboard)

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

dashboard

拓?fù)鋱D(Topology)

再看下拓?fù)鋱D:


topology

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_namevalue 其實(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)境變量即可。如下:


add env variables

把4個(gè)服務(wù)都配置了 SW_AGENT_NAME 環(huán)境變量后,重新啟動(dòng)。

再看下拓?fù)鋱D,會(huì)變成下面這樣:


topology

這樣就比較符合我們的預(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)似如下:

trace with failed request

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

可以看到,一個(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 目錄下有 pluginsoptional-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 目錄下。

image.png

但是又有一個(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,可以看到如下:

trace with springcloud gateway

這樣,第一個(gè)問(wèn)題就解決了。

自定義忽略追蹤部分請(qǐng)求

首先,我們不妨跳到50頁(yè),如下:


image.png

可以看到所有都是跟 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,可以看到如下:

ignore path

可以看到清爽很多,沒(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

最后編輯于
?著作權(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)容