[toc]
一、基礎(chǔ)知識
1.1 為什么要使用分布式追蹤
微服務(wù)在架構(gòu)冠息、敏捷開發(fā)、快速部署孕索、去中心化逛艰、組件化等方面帶來便捷和優(yōu)勢。但是隨著微服務(wù)框架落地搞旭,分布式架構(gòu)和微服務(wù)架構(gòu)給系統(tǒng)性能分析和問題定位帶來非常大挑戰(zhàn)散怖。因此能夠匯聚業(yè)務(wù)系統(tǒng)各處理環(huán)節(jié)的實時數(shù)據(jù),實現(xiàn)對應(yīng)用的全鏈路性能監(jiān)測的微服務(wù)監(jiān)控工具必不可少肄渗。
基于微服務(wù)體系之下構(gòu)建的業(yè)務(wù)系統(tǒng)存在的問題基本上分為三類:
- 故障定位難镇眷,一個簡單操作,其背后可能是由多個微服務(wù)共同完成的翎嫡,這些微服務(wù)也由不同的團隊去負責欠动。一旦出現(xiàn)問題,最壞情況下我們也許需要這十幾個團隊一起來解決問題。
- 鏈路梳理難具伍,應(yīng)用沒有形成應(yīng)用拓撲翅雏,不知道自己的服務(wù)下游會影響其他哪些人。
- 資源浪費多人芽,容量預(yù)估難望几。對于一些服務(wù),其消耗的cpm和memory可能連10%不到萤厅,遠遠沒有充分利用物理機橄抹。這其實和容量預(yù)估關(guān)聯(lián),過大或者過小估算峰值的機器容量惕味,都是浪費楼誓。
APM主要的目的就是解決上面所說的問題,主要的手段是通過收集赦拘、存儲慌随、分析、分布式系統(tǒng)中的調(diào)用事件數(shù)據(jù)躺同,協(xié)助開發(fā)運營人員進行故障診斷阁猜、容量預(yù)估、性能瓶頸定位以及調(diào)用鏈路梳理蹋艺。
市面上APM產(chǎn)品眾多剃袍,選擇合適的APM產(chǎn)品主要從以下需求進行對比選型:
- 代碼的侵入性
- 探針的性能消耗
- 全面的調(diào)用鏈路數(shù)據(jù)分析
- 可擴展性
本文選擇skywalking作為微服務(wù)APM框架,skywalking相當于其他APM產(chǎn)品在性能消耗方面更有優(yōu)勢捎谨,且代碼零入侵民效、可擴展性強并且其支持動態(tài)配置可以很好的和微服務(wù)框架進行集成。
1.2 分布式追蹤實現(xiàn)原理
1.2.1 術(shù)語
- Trace 一次分布式調(diào)用的鏈路
- Span 一次本地或者遠程方法的調(diào)用
- Annotation 附加在 Span 上的日志信息
- Sampling 采樣率(客戶端按照比例將埋點信息提交給服務(wù)端
1.2.2 原理
分布式追蹤理論主要包括以下兩個關(guān)鍵點:
- 為了實現(xiàn)分布式追蹤涛救,當請求發(fā)送到分布式系統(tǒng)的入口端點時畏邢,分布式服務(wù)追蹤框架為該請求創(chuàng)建一個唯一的追蹤標識,同時在分布式系統(tǒng)內(nèi)部流轉(zhuǎn)時检吆,追蹤框架始終保持傳遞該唯一標識舒萎,直到返回給請求方為止,這個唯一標識就是Trace ID蹭沛,而一次完整的調(diào)用鏈路就是Trace臂寝。通過Trace ID我們就能將請求鏈路進行關(guān)聯(lián)起來。
- 為了統(tǒng)計各單位的時間延遲摊灭,當我們請求達到各個服務(wù)組件咆贬、或者處理邏輯到達某個狀態(tài)時,分布式服務(wù)追蹤框架創(chuàng)建一個唯一標識來標記它的開始帚呼、具體過程以及結(jié)束掏缎,該標識就是Span。
1.3 OpenTracing?
1.3.1 OpenTracing簡介
OpenTracing:通過為流行的平臺提供一致的御毅,富有表現(xiàn)力的根欧,==供應(yīng)商中立==的API,OpenTracing使開發(fā)人員可以輕松地通過O(1)配置更改添加(或切換)跟蹤實現(xiàn)端蛆。OpenTracing還為OSS檢測和特定于平臺的跟蹤幫助程序庫提供了通用語言凤粗。OpenTracing盡力讓監(jiān)控一個分布式調(diào)用過程簡單化。通過OpenTracing可以快速配置一個監(jiān)控系統(tǒng)今豆。
1.3.2 OpenTracing規(guī)范
OpenTracing 僅定義了一套開放規(guī)范和API用于在應(yīng)用開發(fā)中設(shè)置埋點嫌拣,實際的抓取存儲日志、分析統(tǒng)計展現(xiàn)都由兼容 OpenTracing 的監(jiān)控產(chǎn)品完成呆躲。
數(shù)據(jù)模型
OpenTracing 設(shè)計圍繞兩個核心概念開展:
- Trace:一條完整的調(diào)用鏈异逐,通過傳遞全局唯一的TraceID追蹤整個調(diào)用過程。
- Span: 記錄調(diào)用鏈某個具體服務(wù)或方法的執(zhí)行情況插掂,通常包含調(diào)用開始時間灰瞻、持續(xù)時間、調(diào)用方辅甥、被調(diào)用方酝润、關(guān)鍵日志、異常璃弄、操作上下文等要销。
下圖為SpringCloud微服務(wù)一次完整調(diào)用鏈,Span的因果關(guān)系圖:
操作間引用
從上圖數(shù)據(jù)模型間關(guān)系可以看出夏块,一個操作可能引用0個或多個具有觸發(fā)關(guān)系的操作上下文疏咐。OpenTracing定義了兩種類型的引用:
- ChildOf: 一個操作可以是另一個操作的子操作,在一個ChildOf引用中脐供,父操作在一定程度上依賴于子操作浑塞。一下場景符合ChildOf關(guān)系:
- 一次Feign調(diào)用的服務(wù)端操作是客戶端操作的子操作
- 一個表示SQL插入的操作是一個ORM save方法的子操作
- 一個父操作可以有多個同步進行(可能是分布式)的父操作,該父操作會在執(zhí)行期限內(nèi)聚合所有子操作的結(jié)果返回給用戶
- FollowsFrom: 有些父操作不以任何方式依賴它們的子操作的結(jié)果政己。在這種場景下酌壕,子操作僅僅由父操作觸發(fā)。
二匹颤、skywalking
2.1 skywalking簡介
skywalking是分布式系統(tǒng)的應(yīng)用性能檢測工具,提供分布式追蹤托猩、服務(wù)網(wǎng)格遙測分析印蓖、度量聚合和可視化一體化解決方案。
2.1.1 skywalking功能
skywalking提供如下核心功能:
- 多種監(jiān)控手斷京腥,支持語言探針和service mesh獲得監(jiān)控數(shù)據(jù)
- 支持多種語言探針赦肃,包括Java、NET、Python和NodeJS等
- 輕量高效他宛,無需大數(shù)據(jù)平臺和服務(wù)支持
- 模塊化船侧。UI、存儲厅各、集群管理有多種機制可選
- 優(yōu)秀的可視化解決方案镜撩。
2.1.2 skywalking架構(gòu)
skywalking整體架構(gòu)可以分為四部分:
- Skywalking Agent:語言探針,通過無侵入的方式收集鏈路數(shù)據(jù)队塘,發(fā)送給OAP Server
- Skywalking OAP: 鏈路數(shù)據(jù)收集器袁梗,負責接收 Agent 發(fā)送的 數(shù)據(jù)信息,然后進行分析(Analysis Core) 憔古,存儲到外部存儲器( Storage )遮怜,最終提供查詢( Query )功能。
- Storage :鏈路追蹤數(shù)據(jù)存儲鸿市。目前支持 ES锯梁、MySQL、Sharding Sphere焰情、TiDB陌凳、H2 等多種存儲器。
- Skywalking UI:可視化平臺烙样,提供一體化解決方案冯遂。
2.2 skywalking 安裝部署
我們使用apache-skywalking-apm-es7-8.7.0 + ES7.x + nacos 配置中心進行skywalking環(huán)境搭建。ES7.x + nacos安裝搭建這里不在贅述谒获。
2.2.1 下載安裝
step1 下載skywalking APM包
# 創(chuàng)建目錄
$ mkdir -p /Users/skywalking
$ cd /Users/skywalking
# 下載
$ wget https://www.apache.org/dyn/closer.cgi/skywalking/java-agent/8.8.0/apache-skywalking-java-agent-8.8.0.tgz
step2 解壓
# 解壓
$ tar -zxvf apache-skywalking-apm-es7-8.7.0.tar.gz
$ cd apache-skywalking-apm-bin-es7
[root@localhost apache-skywalking-apm-bin-es7]# ll
drwxrwxr-x. 9 1001 1002 176 7月 30 21:15 agent # SkyWalking Agent語言探針插件
drwxr-xr-x. 2 root root 241 12月 24 17:13 bin # OAP Server和Web UI執(zhí)行腳本
drwxr-xr-x. 11 root root 4096 12月 29 16:51 config # OAP Server配置文件
drwxr-xr-x. 2 root root 68 12月 24 17:13 config-examples
-rwxrwxr-x. 1 1001 1002 31480 7月 30 20:32 LICENSE
drwxrwxr-x. 3 1001 1002 4096 12月 24 17:13 licenses
drwxr-xr-x. 2 root root 126 1月 12 11:40 logs # 日志目錄
-rwxrwxr-x. 1 1001 1002 32519 7月 30 20:32 NOTICE
drwxrwxr-x. 2 1001 1002 12288 7月 30 21:34 oap-libs # SkyWalking OAP Server
-rw-rw-r--. 1 1001 1002 1951 7月 30 20:32 README.txt
drwxr-xr-x. 3 root root 30 12月 24 17:13 tools
drwxr-xr-x. 2 root root 53 12月 24 17:31 webapp # SkyWalking UI
核心配置
OAP Server 核心配置
OAP Server 配置采用模塊化配置蛤肌,從集群模式、核心Collector批狱、存儲器裸准、Collector Receiver、動態(tài)配置等提供了多種選擇:
-
集群模式(cluster)
Collector支持集群部署赔硫,zookeeper炒俱、kubernetes(如果你的應(yīng)用是部署在容器中的)、consul(GO語言開發(fā)的服務(wù)發(fā)現(xiàn)工具)爪膊、nacos是sw可選的集群管理工具权悟,結(jié)合大家具體的部署方式進行選擇。
cluster:
selector: ${SW_CLUSTER:standalone}
standalone:
# Please check your ZooKeeper is 3.5+, However, it is also compatible with ZooKeeper 3.4.x. Replace the ZooKeeper 3.5+
# library the oap-libs folder with your ZooKeeper 3.4.x library.
zookeeper:
nameSpace: ${SW_NAMESPACE:""}
hostPort: ${SW_CLUSTER_ZK_HOST_PORT:localhost:2181}
# Retry Policy
baseSleepTimeMs: ${SW_CLUSTER_ZK_SLEEP_TIME:1000} # initial amount of time to wait between retries
maxRetries: ${SW_CLUSTER_ZK_MAX_RETRIES:3} # max number of times to retry
# Enable ACL
enableACL: ${SW_ZK_ENABLE_ACL:false} # disable ACL in default
schema: ${SW_ZK_SCHEMA:digest} # only support digest schema
expression: ${SW_ZK_EXPRESSION:skywalking:skywalking}
kubernetes:
namespace: ${SW_CLUSTER_K8S_NAMESPACE:default}
labelSelector: ${SW_CLUSTER_K8S_LABEL:app=collector,release=skywalking}
uidEnvName: ${SW_CLUSTER_K8S_UID:SKYWALKING_COLLECTOR_UID}
consul:
serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"}
# Consul cluster nodes, example: 10.0.0.1:8500,10.0.0.2:8500,10.0.0.3:8500
hostPort: ${SW_CLUSTER_CONSUL_HOST_PORT:localhost:8500}
aclToken: ${SW_CLUSTER_CONSUL_ACLTOKEN:""}
etcd:
# etcd cluster nodes, example: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379
endpoints: ${SW_CLUSTER_ETCD_ENDPOINTS:localhost:2379}
namespace: ${SW_CLUSTER_ETCD_NAMESPACE:/skywalking}
serviceName: ${SW_SCLUSTER_ETCD_ERVICE_NAME:"SkyWalking_OAP_Cluster"}
authentication: ${SW_CLUSTER_ETCD_AUTHENTICATION:false}
user: ${SW_SCLUSTER_ETCD_USER:}
password: ${SW_SCLUSTER_ETCD_PASSWORD:}
nacos:
serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"}
hostPort: ${SW_CLUSTER_NACOS_HOST_PORT:localhost:8848}
# Nacos Configuration namespace
namespace: ${SW_CLUSTER_NACOS_NAMESPACE:"public"}
# Nacos auth username
username: ${SW_CLUSTER_NACOS_USERNAME:""}
password: ${SW_CLUSTER_NACOS_PASSWORD:""}
# Nacos auth accessKey
accessKey: ${SW_CLUSTER_NACOS_ACCESSKEY:""}
secretKey: ${SW_CLUSTER_NACOS_SECRETKEY:""}
-
Collector Core
Collector 核心配置主要提供通信推盛、采樣率峦阁、TTL配置:- 通信方式:collector提供了gRPC和HTTP兩種通信方式,UI使用rest http通信耘成,agent在大多數(shù)場景下使用grpc方式通信榔昔,在語言不支持的情況下會使用http通信驹闰。關(guān)于綁定IP和端口需要注意的一點是,通過綁定IP撒会,agent和collector必須配置對應(yīng)ip才可以正常通信嘹朗。
- downsampling: 采樣匯總統(tǒng)計維度,會分別按照分鐘诵肛、【小時屹培、天、月】(可選)來統(tǒng)計各項指標數(shù)據(jù)曾掂。
- TTL:通過設(shè)置TTL相關(guān)配置項可以對數(shù)據(jù)進行自動清理
詳細配置大家可以去Skywalking官網(wǎng)下載介質(zhì)包進行了解惫谤,這里就不貼出來了。
-
存儲器
SW支持ES珠洗、ES7溜歪、H2、Mysql许蓖、postgrsql等蝴猪,項目可以根據(jù)實際情況選擇合適存儲器。
storage:
selector: elasticsearch7
elasticsearch7:
nameSpace: ${SW_NAMESPACE:"myyshop_monitor"}
clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:192.168.128.34:9200}
protocol: ${SW_STORAGE_ES_HTTP_PROTOCOL:"http"}
connectTimeout: ${SW_STORAGE_ES_CONNECT_TIMEOUT:500}
socketTimeout: ${SW_STORAGE_ES_SOCKET_TIMEOUT:30000}
// 省略許多
-
Collector Receiver
配置監(jiān)控的系統(tǒng)中接受指標數(shù)據(jù)膊爪。支持上傳符合OpenTracing規(guī)范的自定義的監(jiān)控數(shù)據(jù)自阱。 -
配置中心
按照Skywalking官網(wǎng)的客戶端搭建方式,基本采取配置agent.properties文件米酬,或者通過java -D 帶參數(shù)方式(也可以直接使用環(huán)境變量進行配置)沛豌,這些操作辦法都屬于靜態(tài)配置。如果在業(yè)務(wù)高峰期赃额,可能需要調(diào)整采樣率 agent.sample_n_per_3_secs 的數(shù)值加派,只能通過重新啟動或者agent方式更新配置信息。
為了做到通過后臺跳芳,動態(tài)控制agent端的采樣率芍锦、鏈路跨度等配置信息,Skywalking提供了動態(tài)更新功能飞盆。Skywalking支持grpc娄琉、apollo、zookeeper吓歇、etcd孽水、consul、k8s城看、nacos作為動態(tài)更新功能的配置中心女气。詳細配置大家可以去Skywalking官網(wǎng)下載介質(zhì)包進行了解
2.2.2 啟動 OAP Server 和 Web UI
項目采用 standalone模式 + ES7 + nacos配置中心搭建 OAP Server ,配置好application.yml后便可以啟動 OAP Server 和 UI析命。
$ cd apache-skywalking-apm-bin/bin
# 啟動
$ ./startup.sh
SkyWalking OAP started successfully!
SkyWalking Web Application started successfully!
訪問 http://xxxx:8081/ 即可看到如下頁面:
2.3 快速集成
skywalking支持傳統(tǒng)shell和docker模式集成
2.3.1 shell模式
skywalking agent軟件包明細
shell模式需要將agent軟件包拷貝到應(yīng)用部署服務(wù)器主卫,這樣應(yīng)用才能夠使用skywalking agent。
drwxrwxr-x. 2 1001 1002 4096 12月 24 17:13 activations
drwxrwxr-x. 2 1001 1002 85 12月 24 17:13 bootstrap-plugins
drwxrwxr-x. 2 1001 1002 26 12月 24 17:13 config # 配置
drwxrwxr-x. 2 1001 1002 6 7月 30 20:35 logs # 日志
drwxrwxr-x. 2 1001 1002 4096 12月 24 17:13 optional-plugins # 可選插件鹃愤,模式不會運行該目錄下插件簇搅,
如果需要運行,可把對應(yīng)插件拷貝到 /plugins 目錄
drwxrwxr-x. 2 1001 1002 45 12月 24 17:13 optional-reporter-plugins
drwxrwxr-x. 2 1001 1002 8192 12月 24 17:13 plugins # 插件
-rw-rw-r--. 1 1001 1002 19094336 7月 30 20:35 skywalking-agent.jar
如果應(yīng)用服務(wù)器只部署一個服務(wù)软吐,可以直接修改agent/config目錄下配置瘩将,正常情況不建議這樣做,而是通過設(shè)置系統(tǒng)變量(公共配置)或 啟動命名傳參(私有變量)方式凹耙。更多的變量詳情姿现,可以在[/agent/config/agent.config查看。
java啟動腳本
# 通過系統(tǒng)變量方式設(shè)置 SkyWalking Agent 配置
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 # 配置 Collector 地址肖抱。
export SW_AGENT_SPAN_LIMIT=300# 配置鏈路的最大 Span 數(shù)量备典。默認為 300 。
# 通過啟動shell命名傳遞SkyWalking Agent 配置
java -javaagent:D:apache-skywalking-apm-es7-8.8.0/apache-skywalking-apm-bin-es7/agentskywalking-agent.jar -Dskywalking.agent.service_name=當前項目在skywalking顯示的名稱 -jar spring-demo-0.0.1-SNAPSHOT.jar
2.3.2 基于docker集成
基于docker集成skywalking agent意述,官方提供了docker鏡像代理提佣,直接在構(gòu)建應(yīng)用服務(wù)鏡像時使用該鏡像代碼作為基礎(chǔ)鏡像構(gòu)建app。
FROM apache/skywalking-java-agent:8.5.0-jdk8
# ... build your java application
不過鏡像代理不是官方版本荤崇,只是為了方便提供拌屏,推薦的方式還是通過源代碼構(gòu)建鏡像。
通過源代碼方式構(gòu)建應(yīng)用鏡像
- 1. 拷貝/agent 軟件包到應(yīng)用目錄
軟件包和pom.xml在一級目錄术荤,如下圖:
- 2. 修改軟件包/agent/config/agent.config
這里僅貼出項目實際配置的倚喂,更多詳情見軟件包/agent/config/agent.config
agent.service_name=ds-user-center-server
# Logging file_name
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
# Logging level
logging.level=${SW_LOGGING_LEVEL:WARN}
# 歷史日志文件數(shù)量,這里配置保留一個防止日志文件過多瓣戚,默認-1 不限制
logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:1}
ps:軟件包/agent/config/agent.config配置可以不做任何配置端圈,而是在dockerfile腳本中配置參數(shù)。
-
3. 添加DockerFile
這里僅貼出我自己項目的腳本带兜,實際腳本根據(jù)加自己項目調(diào)整
FROM java:8
ADD /app.jar //
# copy arthas
# COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
COPY agent /usr/local/agent
# 這里可以傳遞skywalking-agent 配置
ENTRYPOINT [ "sh", "-c", "java -javaagent:/usr/local/agent/skywalking-agent.jar -Dskywalking.agent.service_name=yourappname -Dskywalking.collector.backend_service=xx.xx.xx.xx:11800 -Dspring.profiles.active=dev -jar /app.jar" ]
- 4. 修改pom.xml打包程序
我們使用的是spotify maven docker插件
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.3</version>
<!--加入下面兩項配置-->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<imageName>${project.artifactId}:${project.version}</imageName>
<!--鏡像構(gòu)建成果推送進行到指定存儲庫-->
<dockerHost>http://192.168.128.20:2375</dockerHost>
<imageTags>
<imageTag>latest</imageTag>
</imageTags>
<!--dockerDirectory 參數(shù)表示使用Dockerfile構(gòu)建鏡像枫笛,${basedir}表示Dockerfile與pom.xml同級目錄 -->
<dockerDirectory>${basedir}</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
通過上述步驟構(gòu)建鏡像并運行服務(wù)便可以集成skywalking-agent
三、 Spring Cloud 微服務(wù)整合skywalking及應(yīng)用實戰(zhàn)
通過上述步驟我們基本能夠?qū)嶋HJava應(yīng)用集成skywalking-agent刚照,下面我們將開始Spring Cloud 微服務(wù)整合skywalking-agent刑巧、微服務(wù)接入skywalking日志、動態(tài)配置无畔、基于skywalking-ui托盤圖進行微服務(wù)調(diào)用關(guān)系分析啊楚、調(diào)用鏈分析、skywalking-agent探針優(yōu)化浑彰、開啟skywalking實戰(zhàn)之旅恭理。
3.1 微服務(wù)整合skywalking-agent
3.1.1 SpringCoud Gateway 集成skywalking-agent
微服務(wù)整合skywalking-agent按照上述Docker集成skywalking-agent步驟便能完成大多數(shù)應(yīng)用的集成,只有SpringCoud Gateway需要進行額外的處理郭变,需要將/optional-plugins可選插件包下apm-spring-cloud-gateway-xx.jar拷貝到/plugins插件包目錄下颜价,具體版本根據(jù)自己微服務(wù)版本而定涯保,本項目使用2.2.4版本,選擇apm-spring-cloud-gateway-2.1.x-plugin-8.7.0.jar即可周伦,不要把所有版本插件全部移動到/plugins
如果SpringCoud Gateway不做上述操作夕春,那么Gateway服務(wù)就和普通服務(wù)一樣,起點就是User专挪,而看不到Gateway作為網(wǎng)關(guān)路由的效果及志。下圖為添加了apm-gateway插件后微服務(wù)全局拓撲圖,可以看到前端訪問微服務(wù)均是通過網(wǎng)關(guān)進行轉(zhuǎn)發(fā):
3.1.2 SpringCoud 日志接入skywalking
完成skywalking-agent探針集成后寨腔,我們便可以對微服務(wù)進行調(diào)用鏈和拓撲圖進行分析速侈,但是我們有時還需要通過elk或者其他日志工具對調(diào)用鏈日志進行分析,skywalking提供無侵入式的trace ID迫卢、trace context倚搬、gRPC reporter,支持log4j乾蛤、log4j2潭枣、logback。我們的項目使用logback幻捏,因此這里只介紹logback模式-Print trace ID in your logs盆犁。更多可以查看官方文檔
- step1 引入skywalking日志組件依賴
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.7.0</version>
</dependency>
- step2 修改應(yīng)用日志配置
配置layout,指定class為skywalking TraceIdPatternLogbackLayout篡九,并且在模板中增加tid的錨點谐岁。
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<springProperty scope="context" name="profilesActive" source="spring.profiles.active"/>
<appender name="consoleApp" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<!--SW layout 配置 -->
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern> %date{yyyy-MM-dd HH:mm:ss.SSS} [%tid] %-5level[%thread]%logger{56}.%method:%L -%msg%n</Pattern>
</layout>
</encoder>
</appender>
<appender name="fileInfoApp" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern> %date{yyyy-MM-dd HH:mm:ss.SSS} [%tid] %-5level[%thread]%logger{56}.%method:%L -%msg%n</Pattern>
</layout>
<!-- 滾動策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 路徑 -->
<fileNamePattern>logs/${springAppName}.info.%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<appender name="fileErrorApp" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern> %date{yyyy-MM-dd HH:mm:ss.SSS} [%tid] %-5level[%thread]%logger{56}.%method:%L -%msg%n</Pattern>
</layout>
<!-- 設(shè)置滾動策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 路徑 -->
<fileNamePattern>logs/${springAppName}.err.%d.log</fileNamePattern>
<!-- 控制保留的歸檔文件的最大數(shù)量,超出數(shù)量就刪除舊文件榛臼,假設(shè)設(shè)置每個月滾動伊佃,
且<maxHistory> 是1,則只保存最近1個月的文件沛善,刪除之前的舊文件 -->
<MaxHistory>1</MaxHistory>
</rollingPolicy>
</appender>
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="consoleApp"/>
<appender-ref ref="fileInfoApp"/>
<appender-ref ref="fileErrorApp"/>
</root>
</springProfile>
<springProfile name="test">
<root level="INFO">
<appender-ref ref="consoleApp"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="consoleApp"/>
</root>
</springProfile>
</configuration>
修改完配置航揉,啟動應(yīng)用,可以看到如下效果:當應(yīng)用激活了SW agent金刁,外部請求日志打印會攜帶tid帅涂,而內(nèi)部請求則打印N/A。
2022-02-07 00:00:00.031 [TID:N/A] INFO [xxl-rpc, EmbedServer bizThreadPool-71423529]com.xxl.job.core.executor.XxlJobExecutor.registJobThread:159 ->>>>>>>>>>> xxl-job regist JobThread success, jobId:144, handler:com.xxl.job.core.handler.impl.MethodJobHandler@c8567c9[class com.xxxx.saas.dsuserserver.job.VipActivePackagesExpiredStateJob$$EnhancerBySpringCGLIB$$72fe4b40#vipActivePackagesExpiredState]
2022-02-07 00:00:00.036 [TID:3344006a6a504161b199c17d5778a36d.3192.16441632000360001] INFO [Thread-1559]c.m.s.dsuserserver.job.VipActivePackagesExpiredStateJob.vipActivePackagesExpiredState:42 -================vipActivePackagesExpiredState start:1644163200036================
2022-02-07 00:00:00.112 [TID:3344006a6a504161b199c17d5778a36d.3192.16441632000360001] INFO [Thread-1559]c.m.s.dsuserserver.job.VipActivePackagesExpiredStateJob.vipActivePackagesExpiredState:46 -================vipActivePackagesExpiredState end:1644163200112================
2022-02-07 00:01:33.130 [TID:N/A] INFO [Thread-1559]com.xxl.job.core.thread.JobThread.run:212 ->>>>>>>>>>> xxl-job JobThread stoped, hashCode:Thread[Thread-1559,10,main]
2022-02-07 10:34:52.757 [TID:d9bb5cb491e34b5ca945c591a326ed8b.69.16442012921820337] INFO [http-nio-7004-exec-8]c.d.saas.common.feign.interceptor.MyOkhttpInterceptor.intercept:23 -OkHttp Feign 發(fā)送請求 [http://192.168.128.20:7001/oauth/token?password=a123456&grant_type=password&userType=1&username=sujingjun%40dhgate.com] on [null]
使用日志追蹤打印的tid尤蛮,在SW UI 追蹤模塊可以追蹤到對應(yīng)的請求鏈路媳友,如下圖:
源碼分析
- TraceIdPatternLogbackLayout:TraceIdPatternLogbackLayout繼承ch.qos.logback.classic.PatternLayout,添加了LogbackPatternConverter和LogbackSkyWalkingContextPatternConverter轉(zhuǎn)換器产捞,支持%tid占位符醇锚。
ublic class TraceIdPatternLogbackLayout extends PatternLayout {
public TraceIdPatternLogbackLayout() {
}
static {
defaultConverterMap.put("tid", LogbackPatternConverter.class.getName());
defaultConverterMap.put("sw_ctx", LogbackSkyWalkingContextPatternConverter.class.getName());
}
}
// 這里實際僅是一個入口程序,實際日志打印實現(xiàn)是agent-activation包下定義的切面和攔截器處理
public class LogbackPatternConverter extends ClassicConverter {
public LogbackPatternConverter() {
}
public String convert(ILoggingEvent iLoggingEvent) {
return "TID: N/A";
}
}
- LogbackPatternConverterActivation: LogbackPatternConverterActivation定義了%tid占位符轉(zhuǎn)換器方法切面 和 攔截器坯临。
public class LogbackPatternConverterActivation extends ClassInstanceMethodsEnhancePluginDefine {
public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.toolkit.activation.log.logback.v1.x.PrintTraceIdInterceptor";
public static final String ENHANCE_CLASS = "org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter";
public static final String ENHANCE_METHOD = "convert";
/**
* @return the target class, which needs active.
*/
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
/**
* @return null, no need to intercept constructor of enhance class.
*/
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
/**
* @return the collection of {@link StaticMethodsInterceptPoint}, represent the intercepted methods and their
* interceptors.
*/
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(ENHANCE_METHOD).and(takesArgumentWithType(0, "ch.qos.logback.classic.spi.ILoggingEvent"));
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
- PrintTraceIdInterceptor: PrintTraceIdInterceptor是%tid占位符轉(zhuǎn)換的實際處理攔截器焊唬,*.afterMethod() 方法調(diào)用 ContextManager#getGlobalTraceId() 方法恋昼,使用全局鏈路追蹤編號。
public class PrintTraceIdInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
if (!ContextManager.isActive()) {
if (allArguments[0] instanceof EnhancedInstance) {
SkyWalkingContext skyWalkingContext = (SkyWalkingContext) ((EnhancedInstance) allArguments[0]).getSkyWalkingDynamicField();
if (skyWalkingContext != null) {
return "TID:" + skyWalkingContext.getTraceId();
}
}
}
return "TID:" + ContextManager.getGlobalTraceId();
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
}
}
更多源碼詳情參考官方https://github.com/apache/skywalking
3.1.3 忽略追蹤某項節(jié)點url
SW支持忽略特點節(jié)點url赶促,要支持節(jié)點忽略功能需要將apm-trace-ignore-plugin-8.7.0.jar插件包拷貝到../plugins目錄下焰雕,同時需要在../config目錄下增加配置文件apm-trace-ignore-plugin.config,并加入trace.ignore_path=${SW_AGENT_TRACE_IGNORE_PATH:/api-docs/**} 為例芳杏,來忽略請求url的追蹤,示例如下:
trace.ignore_path=/api-docs/**,/actuator/**
3.2 客戶端動態(tài)配置
按照Skywalking官網(wǎng)的客戶端搭建方式辟宗,基本采取配置文件爵赵,或者通過java -D 帶參數(shù)方式(也可以直接使用環(huán)境變量進行配置),這些操作辦法都屬于靜態(tài)配置泊脐。如果在生產(chǎn)環(huán)境需要調(diào)整采樣率空幻、忽略url等,只能通過重新啟動agent方式更新配置信息容客。
Skywalking官方提供了動態(tài)更新功能秕铛,可以結(jié)合配置中心實現(xiàn)后臺動態(tài)更新agent采樣率、忽略url缩挑、調(diào)用鏈深度等配置但两。
3.2.1 動態(tài)配置說明
SW 支持以下動態(tài)配置:
配置key | 參數(shù)描述 | 參數(shù)示例 |
---|---|---|
agent-analyzer.default.slowDBAccessThreshold | 慢sql的閾值,覆蓋application.yml中receiver-trace/default/slowDBAccessThreshold | default:200,mongodb:50 |
agent-analyzer.default.uninstrumentedGateways | 網(wǎng)關(guān)配置 | 參數(shù)參考gateways.yml
|
alarm.default.alarm-settings | 告警配置 | 參考alarm-settings.yml
|
core.default.endpoint-name-grouping | 端點分組配置 | 參考service-apdex-threshold.yml
|
core.default.log4j-xml | log4j配置 | 參考log4j2.xml
|
configuration-discovery.default.agentConfigurations | ConfigurationDiscovery 配置 | 參考configuration-discovery.md
|
更多動態(tài)配置說明參考Dynamic Configuration
3.2.2 集成nacos實現(xiàn)SW動態(tài)配置
SW動態(tài)配置依賴上游配置服務(wù)供置,因此默認是關(guān)閉的谨湘,在2.2 核心配置已經(jīng)介紹過配置中心配置說明,這里不再贅述芥丧。我們直接從nacos集成步驟開始
- step1 nacos配置中心安裝部署
我們直接使用SpringCloud nacos配置中心作為SW配置中心不再額外部署nacos紧阔,nacos安裝部署可以參考官方https://nacos.io/zh-cn/docs/deployment.html
- 修改OAP Server
修改OAP Server application.yml 開啟動態(tài)配置并使用nacos作為配置中心
configuration:
selector: nacos #開啟開啟動態(tài)配置并使用nacos作為配置中心
nacos:
# Nacos Server Host
serverAddr: ${SW_CONFIG_NACOS_SERVER_ADDR:192.168.128.20}
# Nacos Server Port
port: ${SW_CONFIG_NACOS_SERVER_PORT:8848}
# Nacos Configuration Group
group: ${SW_CONFIG_NACOS_SERVER_GROUP:skywalking}
# Nacos Configuration namespace
namespace: ${SW_CONFIG_NACOS_SERVER_NAMESPACE:1c53b59e-9f3d-44a4-b2d7-5faaea25b3c6}
# Unit seconds, sync period. Default fetch every 60 seconds.
period: ${SW_CONFIG_NACOS_PERIOD:60}
# Nacos auth username
username: ${SW_CONFIG_NACOS_USERNAME:""}
password: ${SW_CONFIG_NACOS_PASSWORD:""}
# Nacos auth accessKey
accessKey: ${SW_CONFIG_NACOS_ACCESSKEY:""}
secretKey: ${SW_CONFIG_NACOS_SECRETKEY:""}
nacos動態(tài)配置結(jié)果如下:
3.2.3 ConfigurationDiscovery 配置舉例說明
ConfigurationDiscovery 配置了服務(wù)發(fā)現(xiàn)配置,包含采樣率续担、不記錄鏈路信息url后綴擅耽、不記錄鏈路信息url、鏈路最大跨度物遇。ConfigurationDiscovery 配置示例如下:
configurations:
ds-user-center-server:
agent.trace.ignore_path: Mysql/**,Lettuce/**,/941124188381/*,Lettuce/EXISTS/**,MongoDB/**
uaa-center-server:
agent.trace.ignore_path: /api-docs/**,/actuator/**,Mysql/**,Lettuce/**,Lettuce/EXISTS/**
gateway-server:
agent.trace.ignore_path: /api-docs/**,/actuator/**
ConfigurationDiscovery 配置模板
ConfigurationDiscovery 按服務(wù)維度進行配置
configurations:
//service name
serviceA:
// Configurations of service A
// Key and Value are determined by the agent side.
// Check the agent setup doc for all available configurations.
key1: value1
key2: value2
...
serviceB:
...
ConfigurationDiscovery 配置說明
key | 參數(shù)描述 | 參數(shù)示例 | 依賴插件 |
---|---|---|---|
agent.sample_n_per_3_secs | 每3秒采集鏈路數(shù)據(jù),-1表示全部收集 | -1 | - |
agent.ignore_suffix | 不記錄鏈路信息url后綴(第一個節(jié)點開始算起)乖仇,如果多個,采用逗號,隔開 | .txt,.log | - |
agent.trace.ignore_path | 記錄調(diào)用鏈的路徑询兴,多個可以采用逗號,隔開 | /your/path/1/,/your/path/2/ | apm-trace-ignore-plugin |
agent.span_limit_per_segment | 鏈路最大跨度 | 300 | - |