学习不走弯路,通过《mall视频教程(最新版)》,使用更系统、高效的方式来学习mall电商实战项目吧!
自从项目上了SkyWalking,睡觉真香!
自从项目上了SkyWalking,睡觉真香!
随着我们的项目越来越庞大,各个服务间的调用关系也变得越来越复杂,那么该如何理清服务间的调用关系从而定位性能问题呢?SkyWalking能帮助我们解决这个问题,今天就来聊聊它的使用。
SkyWalking简介
SkyWalking是一款性能监控工具,可用于微服务请求链路跟踪。当客户端发起一个请求时,这个请求经过多个服务后,最终返回了结果,经过的每一个服务都有可能发生延迟或错误,从而导致请求失败。这时候我们就需要请求链路跟踪工具来帮助我们,理清请求调用的服务链路,解决问题。
下载与安装
首先我们来讲解下SkyWalking的下载与安装。
- 我们需要下载
SkyWalking APM的发行包,里面包含了skywalking-oap(收集监控信息)和skywalking-ui(管理页面),下载地址:https://skywalking.apache.org/downloads/

- 由于我们需要监控Java应用,所以还需要下载Java Agent,下载地址同上;

- 由于这里使用的SkyWalking版本为
9.x,最低要求为JDK17,所以我们需要先安装好JDK17并在环境变量里配置好JAVA_HOME;

- 将SkyWalking的发行包解压到本地目录,双击skywalking-apm的bin目录下的
startup.bat命令启动,此时会同时启动skywalking-oap和skywalking-ui;

- 等待启动成功后就可以访问SkyWalking的管理页面了,访问地址:http://localhost:8080/

查看监控信息
接下来我们就可以使用SkyWalking来监控微服务应用了。
这里我们会使用到示例代码
sky-user-service和sky-feign-service,后者将通过OpenFeign来远程调用前者,代码地址在文末;接下来我们就要使用Java Agent的方式来监控这两个服务了,在运行服务时,我们需要添加如下的JVM参数;
-javaagent:D:\developer\env\skywalking-agent\skywalking-agent.jar
-Dskywalking.agent.service_name=sky-user-service
-Dskywalking.collector.backend_service=127.0.0.1:11800- 在启动这两个应用之前我们需要先启动Nacos注册中心,然后在IDEA的
VM options中设置即可,先使用上面的JVM参数启动sky-user-service;

- 这里的
javaagent的jar在我们解压的skywalking-agent包里面,直接配置这个Jar的路径即可;

这里的
backend_service地址配置为skywalking-oap的运行地址,端口默认为11800;再使用下面的JVM参数启动
sky-feign-service;
-javaagent:D:\developer\env\skywalking-agent\skywalking-agent.jar
-Dskywalking.agent.service_name=sky-feign-service
-Dskywalking.collector.backend_service=127.0.0.1:11800- 两个服务都正常启动后,我们可以在SkyWalking的管理页面看到它们的监控信息;

- 此时我们调用测试接口进行测试,可以在SkyWalking的
Trace标签中看到追踪信息,接口地址:http://localhost:8701/userFeign/1

- 在
Topology标签中我们可以看到项目的拓扑图。

性能剖析
如果我们的微服务调用之中有个服务特别慢,我们如何通过SkyWalking来找到这个服务呢?这里我们来实践下。
- 这里我们修改下
sky-user-service中UserController中的代码,在getByUsername方法中添加5s的休眠来模拟慢请求;
/**
* @auther macrozheng
* @description 用户管理Controller
* @date 2023/11/30
* @github https://github.com/macrozheng
*/
@RestController
@RequestMapping("/user")
public class UserController {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserService userService;
@GetMapping("/getByUsername")
public CommonResult<User> getByUsername(@RequestParam String username) {
User user = userService.getByUsername(username);
ThreadUtil.safeSleep(5000);
return new CommonResult<>(user);
}
}我们先来访问下这个慢请求收集下数据,接口地址:http://localhost:8701/userFeign/getByUsername?username=macro
此时我们需要用到
Trace Profiling功能也就是性能剖析,新建一个任务,选择好端点;

- 接下来我们多次访问上面的测试接口,来收集数据,等待收集到数据后点击
分析按钮;

- 在
Thread Stack中我们可以找到耗时操作,并且可以找到耗时操作的最终调用在UserFeignController的第30行代码中;

- 打开我们的
UserFeignController类代码,确实是第30行调用了慢查询接口。

自定义链路跟踪
上面SkyWalking提供的默认链路跟踪的控制粒度只能到请求级别,如果我们想要细化到方法级别或者代码片段怎么实现,这就要用到它的自定义链路跟踪功能了。
@Trace注解
如果想监控方法,我们可以使用@Trace注解。
- 我们需要在
sky-feign-service中添加相关依赖;
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>9.1.0</version>
</dependency>- 然后创建CustomTraceController类用于测试接口;
/**
* @auther macrozheng
* @description 自定义链路跟踪测试Controller
* @date 2024/1/4
* @github https://github.com/macrozheng
*/
@RestController
@RequestMapping("/trace")
public class CustomTraceController {
@Autowired
private CustomTraceService customTraceService;
@GetMapping("/annotation")
public CommonResult<User> annotation(@RequestParam Long userId) {
return customTraceService.annotation(userId);
}
}- 调用的业务方法
annotation实现如下;
/**
* @auther macrozheng
* @description 自定义链接跟踪Service实现类
* @date 2024/1/4
* @github https://github.com/macrozheng
*/
@Service
public class CustomTraceServiceImpl implements CustomTraceService {
@Autowired
private UserService userService;
@Trace
@Tag(key = "userId", value = "arg[0]")//arg[0]为固定写法
@Tag(key = "result.id", value = "returnedObj.data.id")//returnedObj为固定写法
@Tag(key = "result.username", value = "returnedObj.data.username")
@Override
public CommonResult<User> annotation(Long userId) {
return userService.getUser(userId);
}
}- 接下来我们就调用该接口进行测试,此时我们可以发现多了更细粒度的方法级别监控,接口地址:http://localhost:8701/trace/annotation?userId=1

- 点击还可以看到我们标记的返回结果信息。

ActiveSpan打印日志
如果想将日志打印到SkyWalking中,可以使用ActiveSpan类提供的方法。
- 这里在业务方法
activeSpan中添加了日志打印;
/**
* @auther macrozheng
* @description 自定义链接跟踪Service实现类
* @date 2024/1/4
* @github https://github.com/macrozheng
*/
@Service
public class CustomTraceServiceImpl implements CustomTraceService {
@Override
public CommonResult<User> activeSpan(Long userId) {
ActiveSpan.debug("activeSpan debug message...");
ActiveSpan.info("activeSpan info message...");
ActiveSpan.error("activeSpan error message...");
return userService.getUser(userId);
}
}- 接下来调用测试接口,由于我们打印了
error日志,监控信息变成了红色,接口地址:http://localhost:8701/trace/activeSpan?userId=1

- 点开详情还可以看到我们打印的详细日志。

OpenTracing使用
如果想监控代码片段,可以使用OpenTracing。
- 启用OpenTracing我们需要在
sky-feign-service中添加如下依赖;
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-opentracing</artifactId>
<version>9.1.0</version>
</dependency>- 我们可以在业务方法
openTracing中通过Span的API来实现,这里我们休眠了1s后去请求了sky-user-service,我只监控了请求部分的代码片段;
/**
* @auther macrozheng
* @description 自定义链接跟踪Service实现类
* @date 2024/1/4
* @github https://github.com/macrozheng
*/
@Service
public class CustomTraceServiceImpl implements CustomTraceService {
@Override
public CommonResult<User> openTracing(Long userId) {
//模拟一个耗时操作
ThreadUtil.safeSleep(1000);
//只监控startManual和finish之间的代码片段
Tracer tracer = new SkywalkingTracer();
Tracer.SpanBuilder spanBuilder = tracer.buildSpan("/trace-span/openTracing");
Span span = spanBuilder.withTag("tag", "openTracing").startManual();
CommonResult<User> result = userService.getUser(userId);
span.finish();
return result;
}
}- 接下我们调用接口进行测试,我们可以发现接口执行了1000多ms,而代码片段执行了6ms,接口地址:http://localhost:8701/trace/openTracing?userId=1

总结
今天带大家使用SkyWalking实现了微服务应用的请求链路跟踪,涵盖了请求级别、方法级别和代码片段级别的跟踪,如果只要求到请求级别的话,SkyWalking对代码的侵入性还是很小的。
参考资料
官方文档:https://skywalking.apache.org/docs/
使用到的模块
springcloud-learning
├── sky-feign-service -- 添加了SkyWalking支持的feign-service
└── sky-user-service -- 提供远程调用接口的user-service项目源码地址
https://github.com/macrozheng/springcloud-learning
公众号
