19. SpringCloudAlibaba 实践笔记:Sleuth项目集成
最简整合
引入依赖
在每个微服务(用户微服务 shop-user、商品微服务 shop-product、订单微服务 shop-order、网关服务 shop-gateway)下的 pom.xml 文件中添加如下 Sleuth 的依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
修改网关应用配置
server:
port: 10002
spring:
application:
name: server-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
port: 7777
dashboard: 127.0.0.1:8888
web-context-unify: false
eager: true
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowCredentials: true
allowedHeaders: "*"
discovery:
locator:
enabled: true
route-id-prefix: gateway-
检验配置效果
启动服务后,在浏览器输入: http://localhost:10001/server-order/order/submit_order?userId=1&productId=1&count=1,查看控制台输出
- 用户微服务
2024-09-23 18:10:40.979 INFO [server-user,bf0f01cbd91b8ffb,515697f8a589d5fb] 23932 --- [nio-8060-exec-4] c.s.u.controller.UserController : 获取到的用户信息为:{"address":"China","id":1,"password":"123456","phone":"12345678901","username":"chan"}
- 商品微服务
2024-09-23 18:10:40.993 INFO [server-product,bf0f01cbd91b8ffb,9c4ab721b57f34e9] 24220 --- [nio-8087-exec-5] c.s.p.controller.ProductController : 更新商品库存传递的参数为: 商品id:1, 购买数量:1
- 订单微服务
2024-09-23 18:10:40.995 INFO [server-order,bf0f01cbd91b8ffb,6ad81ebaf2d13f66] 8532 --- [nio-8080-exec-7] c.s.o.service.impl.OrderServiceImpl : 库存扣减成功
- 网关服务
2024-09-23 18:10:40.777 DEBUG [server-gateway,,] 22548 --- [ctor-http-nio-3] o.s.c.s.instrument.web.TraceWebFilter : Received a request to uri [/server-order/order/submit_order]
2024-09-23 18:10:40.782 DEBUG [server-gateway,,] 22548 --- [ctor-http-nio-3] o.s.c.s.instrument.web.TraceWebFilter : Handled receive of span NoopSpan(bf0f01cbd91b8ffb/bf0f01cbd91b8ffb)
2024-09-23 18:10:40.964 DEBUG [server-gateway,,] 22548 --- [ctor-http-nio-5] ientBeanPostProcessor$TracingDoOnRequest : Handled send of the netty client span [NoopSpan(bf0f01cbd91b8ffb/6ad81ebaf2d13f66)] with parent [bf0f01cbd91b8ffb/bf0f01cbd91b8ffb]
2024-09-23 18:10:41.006 DEBUG [server-gateway,,] 22548 --- [ctor-http-nio-5] PostProcessor$AbstractTracingDoOnHandler : Handle receive of the netty client span [NoopSpan(bf0f01cbd91b8ffb/6ad81ebaf2d13f66)]
2024-09-23 18:10:41.009 DEBUG [server-gateway,,] 22548 --- [ctor-http-nio-3] o.s.c.s.instrument.web.TraceWebFilter : Handled send of NoopSpan(bf0f01cbd91b8ffb/bf0f01cbd91b8ffb)
抽样采集数据
Sleuth 支持抽样采集数据。尤其是在高并发场景下,如果采集所有的数据,那么采集的数据量就太大了,非常耗费系统的性能。通常的做法是可以减少一部分数据量,特别是对于采用 Http 方式去发送采集数据,能够提升很大的性能。
Sleuth 可以采用如下方式配置抽样采集数据。
spring:
sleuth:
sampler:
probability: 1.0
probability:设置采样的概率。这里设置为1.0,表示对所有的请求进行追踪采样,即全采样。如果将采样率设置为0.5,那么大约有一半的请求会被采样进行追踪。
追踪自定义线程池
Sleuth支持对异步任务的链路追踪,在项目中使用@Async注解开启一个异步任务后,Sleuth会为异步任务重新生成一个Span。但是如果使用了自定义的异步任务线程池,则会导致Sleuth无法新创建一个Span,而是会重新生成Trace和Span。此时,需要使用Sleuth提供的LazyTraceExecutor类来包装下异步任务线程池,才能在异步任务调用链路中重新创建Span。
在服务中开启异步线程池任务,需要在用户微服务shop-user的 UserStarter 启动类上添加 @EnableAsync 注解。
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(value = { "io.binghe.shop.user.mapper" })
@EnableDiscoveryClient
@EnableAsync
public class UserStarter {
public static void main(String[] args){
SpringApplication.run(UserStarter.class, args);
}
}
在用户微服务 shop-user 的 UserService 接口中定义一个 asyncMethod()方法
void asyncMethod();
在用户微服务 shop-user 的 UserServiceImpl 类中实现 asyncMethod()方法,并在 asyncMethod()方法上添加@Async 注解
@Async
@Override
public void asyncMethod() {
log.info("执行了异步任务...");
}
在用户微服务 shop-user 的 UserController 类中新增 asyncApi()方法
@GetMapping(value = "/async/api")
public String asyncApi() {
log.info("执行异步任务开始...");
userService.asyncMethod();
log.info("异步任务执行结束...");
return "asyncApi";
}
分别启动用户微服务和网关服务,在浏览器中输入链接 http://localhost:10001/server-user/user/async/api
查看用户微服务与网关服务的控制台日志,分别存在如下日志。
- 用户微服务
2024-09-23 18:26:51.993 INFO [server-user,37660d0bbaffd46b,2334d815f06a4f79] 27344 --- [nio-8061-exec-3] c.shop.user.controller.UserController : 执行异步任务开始...
2024-09-23 18:26:52.005 INFO [server-user,37660d0bbaffd46b,2334d815f06a4f79] 27344 --- [nio-8061-exec-3] c.s.user.service.impl.UserServiceImpl : 执行了异步任务...
2024-09-23 18:26:52.006 INFO [server-user,37660d0bbaffd46b,2334d815f06a4f79] 27344 --- [nio-8061-exec-3] c.shop.user.controller.UserController : 异步任务执行结束...
- 网关服务
2024-09-23 18:26:51.963 DEBUG [server-gateway,,] 23000 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Received a request to uri [/server-user/user/async/api]
2024-09-23 18:26:51.963 DEBUG [server-gateway,,] 23000 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Handled receive of span NoopSpan(37660d0bbaffd46b/37660d0bbaffd46b)
2024-09-23 18:26:51.968 DEBUG [server-gateway,,] 23000 --- [ctor-http-nio-7] ientBeanPostProcessor$TracingDoOnRequest : Handled send of the netty client span [NoopSpan(37660d0bbaffd46b/2334d815f06a4f79)] with parent [37660d0bbaffd46b/37660d0bbaffd46b]
2024-09-23 18:26:52.017 DEBUG [server-gateway,,] 23000 --- [ctor-http-nio-7] PostProcessor$AbstractTracingDoOnHandler : Handle receive of the netty client span [NoopSpan(37660d0bbaffd46b/2334d815f06a4f79)]
2024-09-23 18:26:52.017 DEBUG [server-gateway,,] 23000 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Handled send of NoopSpan(37660d0bbaffd46b/37660d0bbaffd46b)
自定义链路过滤器
在 Sleuth 中存在链路过滤器,并且还支持自定义链路过滤器。TracingFilter 是 Sleuth 中负责处理请求和响应的组件,可以通过注册自定义的 TracingFilter 实例来实现一些扩展性的需求。
在用户微服务shop-user 创建 MyGenericFilter 类,继承 org.springframework.web.filter.GenericFilterBean 类。
@Component
@Order( Ordered.HIGHEST_PRECEDENCE + 6)
public class MyGenericFilter extends GenericFilterBean {
private Pattern skipPattern = Pattern.compile(SleuthWebProperties.DEFAULT_SKIP_PATTERN);
private final Tracer tracer;
public MyGenericFilter(Tracer tracer){
this.tracer = tracer;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)){
throw new ServletException("只支持HTTP访问");
}
Span currentSpan = this.tracer.currentSpan();
if (currentSpan == null) {
chain.doFilter(request, response);
return;
}
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = ((HttpServletResponse) response);
boolean skipFlag = skipPattern.matcher(httpServletRequest.getRequestURI()).matches();
if (!skipFlag){
String traceId = currentSpan.context().traceId();
httpServletRequest.setAttribute("traceId", traceId);
httpServletResponse.addHeader("SLEUTH-HEADER", traceId);
}
chain.doFilter(httpServletRequest, httpServletResponse);
}
}
- 在过滤器中,会将生成的 traceId 添加到 request 的 attribute ,并将 response 的 Header 添加
SLEUTH-HEADER=<traceId>
在用户微服务 shop-user 的 UserController 类中新建 sleuthFilter()方法,在 sleuthFilter()方法中获取并打印 traceId,如下所示。
@GetMapping(value = "/sleuth/filter/api")
public String sleuthFilter(HttpServletRequest request) {
Object traceIdObj = request.getAttribute("traceId");
String traceId = traceIdObj == null ? "" : traceIdObj.toString();
log.info("获取到的traceId为: " + traceId);
return "sleuthFilter";
}
在浏览器中输入 http://localhost:10001/server-user/user/sleuth/filter/api,查看用户微服务的输出信息
2024-09-23 19:17:20.720 INFO [server-user,4729363c365580bc,ebcf4a7cc2083793] 26388 --- [nio-8061-exec-1] c.shop.user.controller.UserController : 获取到的traceId为: 4729363c365580bc
查看浏览器的控制台,看到在响应的结果信息中新增了一个名称为 SLEUTH-HEADER,值为 4729363c365580bc 的 Header

浙公网安备 33010602011771号