本文涉及源碼都在 這里。
Apache Skywalking(Incubator)簡介
Apache Skywalking(Incubator) 專門為微服務架構和云原生架構系統而設計并且支持分布式鏈路追蹤的APM系統。Apache Skywalking(Incubator)通過加載探針的方式收集應用調用鏈路信息,并對采集的調用鏈路信息進行分析,生成應用間關系和服務間關系以及服務指標。Apache Skywalking (Incubating)目前支持多種語言,其中包括Java,.Net Core,Node.js和Go語言。
目前Skywalking已經支持從6個可視化維度剖析分布式系統的運行情況。總覽視圖是應用和組件的全局視圖,其中包括組件和應用數量,應用的告警波動,慢服務列表以及應用吞吐量;拓撲圖從應用依賴關系出發,展現整個應用的拓撲關系;應用視圖則是從單個應用的角度,展現應用的上下游關系,TopN的服務和服務器,JVM的相關信息以及對應的主機信息。服務視圖關注單個服務入口的運行情況以及此服務的上下游依賴關系,依賴度,幫助用戶針對單個服務的優化和監控;調用鏈展現了調用的單次請求經過的所有埋點以及每個埋點的執行時長;告警視圖根據配置閾值針對應用、服務器、服務進行實時告警。
英文版文檔:https://github.com/apache/skywalking/blob/master/docs/README.md
中文版文檔:https://skyapm.github.io/document-cn-translation-of-skywalking/
下載并安裝
下載
從 官網 下載合適的壓縮包,如果下載失敗(不知道為啥我下載下來的是個空包),可以直接在這個 鏡像網站 下載。.zip
格式是 Windows
版本,.tar.gz
是 Linux
版本, Mac
也用 .tar.gz
。
本次使用的是目前最新穩定版
v6.6.0
,而且到時使用Mysql
做數據存儲,所以我下載的是這個 壓縮包 。
解壓
解壓壓縮包:
tar -zxvf apache-skywalking-apm-6.6.0.tar.gz
大致目錄樹結構如下:
簡單說一下這幾個目錄的作用:
- webapp: UI 前端(
web
監控頁面)的jar
包和配置文件; - oap-libs: 后臺應用的
jar
包,以及它的依賴jar
包,里邊有一個server-starter-*.jar
就是啟動程序; - config: 啟動后臺應用程序的配置文件,是使用的各種配置
- bin: 各種啟動腳本,一般使用腳本
startup.*
來啟動web
頁面 和對應的 后臺應用;- oapService.*: 默認使用的后臺程序的啟動腳本;(使用的是默認模式啟動,還支持其他模式,各模式區別見 啟動模式)
- oapServiceInit.*: 使用
init
模式啟動;在此模式下,OAP服務器啟動以執行初始化工作,然后退出 - oapServiceNoInit.*: 使用
no init
模式啟動;在此模式下,OAP服務器不進行初始化。 - webappService.*: UI 前端的啟動腳本;
- startup.*: 組合腳本,同時啟動
oapService.*:
、webappService.*
腳本;
- agent:
- skywalking-agent.jar: 代理服務
jar
包 - config: 代理服務啟動時使用的配置文件
- plugins: 包含多個插件,代理服務啟動時會加載改目錄下的所有插件(實際是各種
jar
包) - optional-plugins: 可選插件,當需要支持某種功能時,比如
SpringCloud Gateway
,則需要把對應的jar
包拷貝到plugins
目錄下;
- skywalking-agent.jar: 代理服務
啟動后端服務和前端UI
Skywalking
的后端服務默認使用的數據庫是 h2
,而我們需要使用的是 Mysql
,所以得修改部分配置。該配置文件是目錄 config
下的 application.yml
文件,將 h2
數據庫相關配置注釋掉,然后 Mysql
部分去掉注釋,并將數據庫名、賬號密碼修改一下。修改完大致如下:
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}
注:如果沒有創建
skywalking
數據庫,還需要手動創建。
因為 oap-libs
目錄下缺少 mysql
的驅動程序,所以還需要下載 mysql-connector-java-*.jar
放到 oap-libs
目錄下,這里我使用的版本是 5.1.46
。一般該 jar
包在本地的 maven
倉庫都有,直接拷貝過去即可,一般在目錄 ~/.m2/repository/mysql/mysql-connector-java/5.1.46
下。
$ cd apache-skywalking-apm-bin/bin
# 啟動
$ ./startup.sh
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!
# 查看啟動的服務
$ jps
17716 RemoteMavenServer
16005 Launcher
4295 OAPServerStartUp
18266 Jps
4301 skywalking-webapp.jar
...
如果看到 OAPServerStartUp
和 skywalking-webapp.jar
,那么代表2個服務都啟動成功。
這時訪問 http://localhost:8080/ 即可看到如下頁面:
至此,Skywalking
的監控跟蹤服務就準備完畢。
跟蹤分布式服務
從 這里 克隆到本地,本文用到的子項目為 spring-cloud-advance-skywalking
,進入該目錄,可以看到包含如下服務:
- sca-skywalking-discovery:服務發現
- sca-skywalking-gateway:網關
- sca-skywalking-licence:
licence
服務。里邊部分接口回調用organization
服務的接口。 - sca-skywalking-organization:
organization
服務。
啟動服務
在 安裝Java agent 中,提到了在啟動應用之前,需要配置JVM參數,添加 -javaagent:/path/to/skywalking-package/agent/skywalking-agent.jar
。為了方便這里以在 IDEA
中啟動服務為例:
儀表盤(Dashboard)
啟動4個服務后,再次訪問 http://localhost:8080/ ,可以看到類似如下:
拓撲圖(Topology)
再看下拓撲圖:
Your_Application_Name: 服務名
localhost-1: 數據庫。因為服務 licence-service
, organization
使用了 H2
數據庫
User: 暫時不知道是干啥的,以后知道了再補充(難道是skywalking的用戶服務?)
那么問題來了,為什么啟動了4個服務,這里只有一個 Your_Application_Name
服務?
其實在 安裝Java agent 中,有提到需要配置 config/agent.config
中的 agent.service_name
。但我們這里需要啟動的服務有多個,直接配置在文件中肯定不合適,難道啟動一個服務改一次?
我們先來看下 config/agent.config
中的 agent.service_name
配置,如下:
# The service name in UI
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
... 省略前后其他配置
可以看到,屬性 agent.service_name
的 value
其實是占位符,優先使用 SW_AGENT_NAME
的值,那這個到底是什么呢?其實是環境變量,如果啟動時環境變量 SW_AGENT_NAME
有值的話,那么使用它,否則使用默認值 Your_ApplicationName
。
所以這就不難解釋在拓撲圖中看到的只有一個 Your_ApplicationName
,因為所有服務啟動時,都使用了同一份 agent.config
配置,skywalking
認為這4個服務都是服務名為 Your_ApplicationName
的4個實例。
所以我們可以在啟動時配置一下環境變量即可。如下:
把4個服務都配置了 SW_AGENT_NAME
環境變量后,重新啟動。
再看下拓撲圖,會變成下面這樣:
這樣就比較符合我們的預期了。因為 skywalking
有一定緩存機制,當服務不可用后,不會立即刪除(Your_ApplicationName
),等過一段時間后會自動清清除。
請求追蹤
多次訪問 http://localhost:3100/licence/1,然后切到 追蹤 標簽頁,可以看到類似如下:
正常的請求長這樣:
可以看到,一個請求的所有調用鏈都被記錄下來,包括 Spring MVC
的內部轉發、跨服務的 http
調用以及數據庫查詢,都完整的記錄下來,而且也記錄了整個請求以及各個子步驟的耗時。
但是,有2個問題,第一,為啥沒有記錄網關層的調用鏈?第二,我剛剛其實只請求了幾次,為什么會有151頁數據?帶著這2個問題,我們繼續挖掘 Skywalking
的新特性。
使用 optional-plugins
兼容 SpringCloud Gateway
前面提到,agent
目錄下有 plugins
和 optional-plugins
2個目錄,skywalking-agent.jar
在啟動時會加載 plugins
下的所有插件,但不會加載 optional-plugins
下的,其實看目錄名就知道了,可選插件 就是可有可沒有,需要等需要的時候再加到 plugins
下即可。
我們看到, optional-plugins
下就有跟 SpringCloud Gateway
相關的插件,那就它了,把它丟到 plugins
目錄下。
但是又有一個問題,為什么 SpringCloud Gateway
這么特殊呢,為啥沒一個類似 apm-spring-cloud-zuul-plugin-6.6.0.jar
的插件呢?這2個網關有啥本質上的區別嗎?肯定有的啦,一個是同步的,另一個是異步(底層用了 netty
,還依賴 spring-webflux
)。另外,我們還注意到另一個插件 apm-spring-webflux-5.x-plugin-6.6.0.jar
,把它也丟到 plugins
目錄下。
最后,重啟4個服務,再訪問 http://localhost:3100/licence/1,可以看到如下:
這樣,第一個問題就解決了。
自定義忽略追蹤部分請求
首先,我們不妨跳到50頁,如下:
可以看到所有都是跟 eureka
相關,看到這里,如果你比較熟悉 eureka
的底層邏輯,那么基本就能猜出來啥原因了:EurekaClient
每隔一段時間都會向 EurekaServer
請求續約,也可以理解為心跳,還有定時從 EurekaServer
拉取最新的可用的服務清單。
這種記錄這些請求對我們來說用處不大,而且還會造成大量垃圾數據,所以應該避免追蹤,但 Skywalking
并不能自己識別出來,拿只能我們教它怎么分辨了。
注意到,optional-plugins
中有這樣的插件 apm-trace-ignore-plugin-6.6.0.jar
,把它丟到 plugins
目錄下先。
加上插件只是讓 Skywalking
擁有忽略某些請求的能力,但還需要我們指定哪些需要忽略。下載 配置文件,然后把它丟到 /agent/config/
目錄下,增加過濾規則。里邊的內容如下:
# 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/**}
可以看到插件的開發者已經幫我們考慮到 eureka
這種情況了,直接去掉最后一行的注釋即可,當然,也可以跟服務名一樣使用環境變量配置。另外,eureka-server
因為不是我們的業務服務,所以可以考慮不對它進行代理,即去掉 JVM
參數配置。
最后,重啟4個服務,再訪問 http://localhost:3100/licence/1,可以看到如下:
可以看到清爽很多,沒有太多冗余的請求。
相關鏈接
官網: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