使用 SpringCloud(Gateway) + Skywal
本文涉及源码都在 这里。
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
中启动服务为例:
add jvm params
仪表盘(Dashboard)
启动4个服务后,再次访问 http://localhost:8080/ ,可以看到类似如下:
拓扑图(Topology)
再看下拓扑图:
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个实例。
所以我们可以在启动时配置一下环境变量即可。如下:
add env variables
把4个服务都配置了 SW_AGENT_NAME
环境变量后,重新启动。
再看下拓扑图,会变成下面这样:
topology
这样就比较符合我们的预期了。因为 skywalking
有一定缓存机制,当服务不可用后,不会立即删除(Your_ApplicationName
),等过一段时间后会自动清清除。
请求追踪
多次访问 http://localhost:3100/licence/1,然后切到 追踪 标签页,可以看到类似如下:
正常的请求长这样:
trace
可以看到,一个请求的所有调用链都被记录下来,包括 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页,如下:
image.png
可以看到所有都是跟 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