摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud/Spring-Cloud-Sleuth/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 labx-13 目录。
原创不易,给点个 Star 嘿,一起冲鸭!
1. 概述
Spring Cloud Sleuth 是由 Spring Cloud 官方推出,为 Spring Cloud 实现分布式链路追踪 的功能,它在设计上借鉴了 Dapper 、 Zipkin 、HTrace 。
Spring Cloud Sleuth is a distributed tracing tool for Spring Cloud. It borrows from Dapper , Zipkin , and HTrace .
实际上,我们可以直接把 Spring Cloud Sleuth 理解成对 Zipkin 的封装 ,方便在 Spring Cloud 使用。艿艿记得之前在 Spring Boot 中直接使用 Zipkin 的时候,真的是贼麻烦,可以后续翻翻《芋道 Spring Boot 链路追踪 Zipkin 入门》 文章。
也因此,在开始 Spring Cloud Sleuth 的学习之前,胖友需要先 看看《芋道 Zipkin 极简入门》 文章,完成原生 Zipkin 的学习与使用。
完成对 Zipkin 的学习之后,我们就真正开始本文 Spring Cloud Sleuth 之旅。我们的重心,会放在如何使用 Spring Cloud Sleuth 在 Spring Cloud 项目中对各种组件的链路追踪 。例如说:
针对 MySQL、Redis、MongoDB、Elasticsearch 等数据库操作的链路追踪
针对 SpringMVC、WebFlux、Gateway 等 Web 请求 的链路追踪
针对 Dubbo、Feign、Web Client 等远程调用 的链路追踪
针对 RocketMQ、RabbitMQ、Kafka、ActiveMQ 等消息队列 的链路追踪
2. 说明一波
目前主流使用的 Spring Cloud Sleuth 是 2.X 版本,而网上很多文章或者资料是基于 1.X 版本,所以会存在很多跑不通的地方。
① 例如说,使用 @EnableZipkinServer
注解 来自定义一个 Zipkin Server,目前已经废弃 ,在 Spring Cloud Sleuth 的 ISSUE#912 已经有相关说明。如下图所示:
因此,无论是在本小节的示例,还是在生产环境下,直接使用 Zipkin 已经提供好的发布包 即可。
② 又例如说,Spring Cloud Sleuth 使用 Spring Cloud Stream 发送链路数据到 Zipkin 中,目前已经废弃 ,在《Spring Cloud Sleuth 2.0 Migration Guide》 文档提到如下:
也就是说,如果我们相使用消息队列 来发送链路数据到 Zipkin 中的话,Zipkin 已经内置 了 zipkin-collector-kafka
和 zipkin-collector-rabbitmq
。
3. SpringMVC 示例
示例代码对应仓库:labx-13-sc-sleuth-springmvc
。
本小节,我们来搭建一个 Spring Cloud Sleuth 对 SpringMVC 的 API 接口的链路追踪。该链路通过如下插件 实现收集:
友情提示:一般来说,在 Java 应用程序中,我们使用 Brave 库,作为 Zipkin Server 的 Java Tracer 客户端。同时它的 instrumentation 子项目,已经提供了 SpringMVC、MySQL、Dubbo 等等的链路追踪的功能。
本文对 instrumentation 统称为“插件”。
我们来新建一个 labx-13-sc-sleuth-springmvc
项目,最终如下图所示:
3.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-springmvc</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > </dependencies > </project >
通过引入 spring-cloud-starter-zipkin
依赖,从而引入 Spring Cloud Sleuth + Zipkin 相关依赖,实现对它们的自动配置,从而实现链路追踪 的功能。
spring-cloud-starter-zipkin
包括了 spring-cloud-starter-sleuth
和 spring-cloud-sleuth-zipkin
。如下图所示:
3.2 配置文件
创建 application.yml
配置文件,添加相应配置项如下:
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true
① spring.application.name
配置项,为应用(服务)名,稍后在 Zipkin 中也会使用该名字。
② spring.zipkin
配置项,为 Zipkin 的配置项,对应 ZipkinProperties 类。
base-url
配置项,Zipkin 服务的地址。
③ spring.sleuth
配置项,为 Spring Cloud Sleuth 配置项。
其中,spring.sleuth
配置项,为 Spring Cloud Sleuth 针对 Web 组件(例如说 SpringMVC)的配置项,对应 SleuthWebProperties 类。
enabled
:是否开启,默认为 true
。如果胖友想关闭对 SpringMVC 的链路追踪,可以设置为 false
来关闭。
还有其它配置项,胖友可以在 SleuthWebProperties 类里挖掘下,例如说 additional-skip-pattern
配置项可以设置不追踪的 URL。
3.3 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { return "user:" + id; } }
3.4 UserServiceApplication
创建 UserServiceApplication 类,配置 @SpringBootApplication
注解即可。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
3.5 简单测试
执行 SpringMVCApplication,启动该 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,请求下 Spring Cloud 应用提供的 API。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④ 再之后,点击第一个 Span,可以看到一个 Span 明细。如下图所示:
4. Feign 示例
示例代码对应仓库:
本小节,我们来搭建一个 Spring Cloud Sleuth 对 Feign 的远程 HTTP 调用的链路追踪。该链路通过如下插件 实现收集:
我们来新建一个 labx-13-sc-sleuth-feign
项目作为消费者,使用 Feign 调用 「3. SpringMVC 示例」 的 labx-13-sc-sleuth-springmvc
的 /user/get
接口。最终如下图所示:
4.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-feign</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-openfeign</artifactId > </dependency > </dependencies > </project >
4.2 配置文件
创建 application.yml
配置文件,添加相应配置项如下:
server: port: 8081 spring: application: name: feign-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true feign: enabled: true
spring.sleuth.feign
配置项,为 Spring Cloud Sleuth 针对 Feign 组件的配置项,对应 SleuthFeignProperties 类。
另外,这里修改了 spring.application.name
配置项为 feign-service
,保证链路追踪使用不同的名字。
4.3 UserServiceFeignClient
创建 UserServiceFeignClient 接口,调用 user-service
服务的 Feign 客户端,即「3. SpringMVC 示例」 的 labx-13-sc-sleuth-springmvc
。代码如下:
@FeignClient (name = "user-service" , url = "http://127.0.0.1:8080" )public interface UserServiceFeignClient { @GetMapping ("/user/get" ) String get (@RequestParam("id" ) Integer id) ; }
考虑到方便,我们不引入注册中心,而是通过 @FeignClient
的 url
属性,设置调用的 user-service
服务的地址。
4.4 FeignController
创建 FeignController 类,提供 /feign/get
接口,使用 UserServiceFeignClient 调用 user-service
服务。代码如下:
@RestController @RequestMapping ("/feign" )public class FeignController { @Autowired private UserServiceFeignClient userServiceFeignClient; @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { return userServiceFeignClient.get(id); } }
4.5 FeignApplication
创建 FeignApplication 类,feign-service
服务启动类。代码如下:
@SpringBootApplication @EnableFeignClients public class FeignApplication { public static void main (String[] args) { SpringApplication.run(FeignApplication.class, args); } }
4.6 简单测试
使用 FeignApplication 和 UserServiceApplication 启动两个 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8081/feign/get?id=1
命令,使用 Feign 调用 user-service
服务。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
一条链路经过 feign-service
和 user-service
两个服务,一共有三个 Span 。
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
比较奇怪的是,此时我们两个 Span ,少了一个 Span !不晓得是不是 Zipkin UI 的 Bug?此时如果我们点击右上角的「JSON」按钮,查看该链路的原始数据,返回 JSON 如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
5. Spring Cloud Gateway 示例
示例代码对应仓库:
本小节,我们来搭建一个 Spring Cloud Sleuth 对 Spring Cloud Gateway 的代理请求的链路追踪。该链路通过如下插件 实现收集:
友情提示:因为 Spring Cloud Gateway 是基于 WebFlux 实现,而 Spring Cloud Sleuth 的 instrument/web
模块提供的插件,实际是针对 WebFlux 框架,所以也适用于 Spring Cloud Gateway。
感兴趣的胖友,后续可以看看 TraceWebFilter 的源码。
我们来新建一个 labx-13-sc-sleuth-springcloudgateway
项目作为 API 网关,转发请求到后端服务。最终如下图所示:
考虑到方便,我们直接使用「4. Feign 示例」 的 feign-service
和 user-service
两个服务,作为被转发的后端服务。
5.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-08</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-springcloudgateway</artifactId > <properties > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > <spring.cloud.alibaba.version > 2.2.0.RELEASE</spring.cloud.alibaba.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-alibaba-dependencies</artifactId > <version > ${spring.cloud.alibaba.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-gateway</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > </dependencies > </project >
5.2 配置文件
创建 application.yml
配置文件,添加相应配置项如下:
server: port: 8888 spring: application: name: gateway-application zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true cloud: gateway: routes: - id: feign-service-route uri: http://127.0.0.1:8081 predicates: - Path=/**
① 因为使用的是 instrument/web
模块提供的插件,所以和 SpringMVC 一样,WebFlux 也是使用 spring.sleuth.web
配置项。
② 在 spring.cloud.gateway
配置项中,我们创建了一个编号为 feign-service-route
的路由,转发到「4. Feign 示例」 小节的 feign-service
服务。这样整个请求的链路,就是 gateway-application => feign-service => user-service
。
5.3 GatewayApplication
创建 GatewayApplication 类,网关启动类。代码如下:
@SpringBootApplication public class GatewayApplication { public static void main (String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
5.4 简单测试
使用 FeignApplication、UserServiceApplication、GatewayApplication 启动三个 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8888/feign/get?id=1
命令,请求 API 网关,从而转发请求到 feign-service
服务。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
一条链路经过 gateway-application
feign-service
、user-service
三个服务,一共有五个 Span 。
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
比较奇怪的是,此时我们五个 Span ,少了两个 Span !不晓得是不是 Zipkin UI 的 Bug?此时如果我们点击右上角的「JSON」按钮,查看该链路的原始数据,返回 JSON 如下图所示:
④ 再之后,分别点击个 Span,可以看到三个 Span 明细。如下图所示:
6. Zuul 示例
TODO 后续补充
7. Dubbo 示例
示例代码对应仓库:
本小节,我们来搭建一个 Spring Cloud Sleuth 对 Dubbo 的远程 RPC 调用的链路追踪。该链路通过如下插件 实现收集:
友情提示:Brave 一共提供了两个插件,其中本文使用的 brave-instrumentation-dubbo
适用于 Dubbo 2.7.X 版本,而另外的 brave-instrumentation-dubbo-rpc
适用于 Dubbo 2.6.X 版本。
我们来新建一个 labx-13-sc-sleuth-dubbo
模块,一共包含三个子项目。最终如下图所示:
另外,考虑到 Spring Cloud Alibaba 主推 Nacos 作为诸注册中心,所以本小节也是使用 Nacos。不了解的胖友,后续可以看看《Nacos 极简入门》 文章。
7.1 搭建 API 项目
创建 labx-13-sc-sleuth-dubbo-api
项目,服务接口 ,定义 Dubbo Service API 接口,提供给消费者使用。
7.1.1 UserService
创建 UserService 接口,定义用户服务 RPC Service 接口。代码如下:
public interface UserService { String get (Integer id) ; }
7.2 搭建服务提供者
创建 labx-13-sc-sleuth-dubbo-provider
项目,服务提供者 ,实现 labx-13-sc-sleuth-dubbo-api
项目定义的 Dubbo Service API 接口,提供相应的服务。
7.2.1 引入依赖
创建 pom.xml
文件中,引入依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13-sc-sleuth-dubbo</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-dubbo-consumer</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > <spring.cloud.alibaba.version > 2.2.0.RELEASE</spring.cloud.alibaba.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-alibaba-dependencies</artifactId > <version > ${spring.cloud.alibaba.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > cn.iocoder.springboot.labs</groupId > <artifactId > labx-13-sc-sleuth-dubbo-api</artifactId > <version > 1.0-SNAPSHOT</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-discovery</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-dubbo</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > io.zipkin.brave</groupId > <artifactId > brave-instrumentation-dubbo</artifactId > <version > 5.10.1</version > </dependency > </dependencies > </project >
重点是引入 brave-instrumentation-dubbo
依赖,实现对 Dubbo 的链路追踪。
7.2.2 配置文件
创建 application.yml
配置文件,添加相应配置项如下:
spring: application: name: demo-provider cloud: nacos: discovery: server-addr: 127.0 .0 .1 :8848 zipkin: base-url: http://127.0.0.1:9411 dubbo: scan: base-packages: cn.iocoder.springcloud.labx13.providerdemo.service protocols: dubbo: name: dubbo port: -1 registry: address: spring-cloud://127.0.0.1:8848 provider: filter: tracing cloud: subscribed-services: ''
重点是设置 dubbo.provider.filter
配置项为 tracing
,使用 brave-instrumentation-dubbo
提供的 TracingFilter 过滤器,实现对 Dubbo 的链路追踪。不过实际上,TracingFilter 已经通过 @Activate
注解进行默认激活 ,所以也是可以不进行配置的。
关于 dubbo
配置项,胖友可以后续阅读《芋道 Spring Cloud Alibaba 服务调用 Dubbo 入门》 文章。
7.2.3 UserServiceImpl
创建 UserServiceImpl 类,实现 UserService 接口,用户服务具体实现类。代码如下:
@org .apache.dubbo.config.annotation.Service(protocol = "dubbo" , version = "1.0.0" )public class UserServiceImpl implements UserService { @Override public String get (Integer id) { return "user:" + id; } }
7.2.4 ProviderApplication
创建 ProviderApplication 类,服务提供者的启动类。代码如下:
@SpringBootApplication public class ProviderApplication { public static void main (String[] args) { SpringApplication.run(ProviderApplication.class); } }
7.3 搭建服务消费者
创建 labx-13-sc-sleuth-dubbo-consumer
项目,服务消费者 ,会调用 labx-13-sc-sleuth-dubbo-provider
项目提供的 User Service 服务。
7.3.1 引入依赖
创建 pom.xml
文件中,引入依赖。和「7.2.1 引入依赖」 基本是一致的,胖友可以点击 pom.xml
文件查看。
7.3.2 配置文件
创建 application.yml
配置文件,添加相应配置项如下:
spring: application: name: demo-consumer cloud: nacos: discovery: server-addr: 127.0 .0 .1 :8848 zipkin: base-url: http://127.0.0.1:9411 dubbo: registry: address: spring-cloud://127.0.0.1:8848 consumer: filter: tracing cloud: subscribed-services: demo-provider
重点是设置 dubbo.consumer.filter
配置项为 tracing
,使用 brave-instrumentation-dubbo
提供的 TracingFilter 过滤器,实现对 Dubbo 的链路追踪。不过实际上,TracingFilter 已经通过 @Activate
注解进行默认激活 ,所以也是可以不进行配置的。
关于 dubbo
配置项,胖友可以后续阅读《芋道 Spring Cloud Alibaba 服务调用 Dubbo 入门》 文章。
7.3.3 UserController
创建 UserController 类,提供调用 UserService 服务的 HTTP 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { @Reference (protocol = "dubbo" , version = "1.0.0" ) private UserService userService; @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { return userService.get(id); } }
7.3.4 ConsumerApplication
创建 ConsumerApplication 类,服务消费者的启动类。代码如下:
@SpringBootApplication public class ConsumerApplication { public static void main (String[] args) { SpringApplication.run(ConsumerApplication.class); } }
7.4 简单测试
使用 ProviderApplication 启动服务提供者,使用 ConsumerApplication 启动服务消费者。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,使用 Dubbo 调用 user-service
服务。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
一条链路经过 demo-consumer
和 demo-provider
两个服务,一共有三个 Span 。
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
比较奇怪的是,此时我们两个 Span ,少了一个 Span !不晓得是不是 Zipkin UI 的 Bug?此时如果我们点击右上角的「JSON」按钮,查看该链路的原始数据,返回 JSON 如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
8. MySQL 示例
示例代码对应仓库:labx-13-sc-sleuth-db-mysql
。
本小节,我们来搭建一个 Spring Cloud Sleuth 对 MySQL 操作的链路追踪。该链路通过如下插件实现收集:
我们来新建一个 我们来新建一个 labx-13-sc-sleuth-db-mysql
项目,实现简单的 MySQL 数据库操作。最终如下图所示:
另外,我们将使用 Spring JdbcTemplate 进行 MySQL 的操作。对 Spring JdbcTemplate 感兴趣的胖友,可以后续去看看《芋道 Spring Boot JdbcTemplate 入门》 文章。
8.1 引入依赖
创建 pom.xml
文件中,引入依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-db-mysql</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-jdbc</artifactId > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.46</version > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > io.zipkin.brave</groupId > <artifactId > brave-instrumentation-mysql</artifactId > </dependency > </dependencies > </project >
重点是引入 brave-instrumentation-mysql
依赖,实现对 MySQL 的链路追踪。
8.2 配置文件
在 application.yml
中,添加数据库相关配置,如下:
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true datasource: url: jdbc:mysql://127.0.0.1:3306/lab-39-mysql?useSSL=false&useUnicode=true&characterEncoding=UTF-8&statementInterceptors=brave.mysql.TracingStatementInterceptor&zipkinServiceName=demo-db-mysql driver-class-name: com.mysql.jdbc.Driver username: root password:
① 通过自定义 StatementInterceptorV2 的实现类 TracingStatementInterceptor ,达到拦截 SQL 请求,进行 MySQL 的链路追踪。
在 spring.datasource.url
配置项上的 statementInterceptors
和 zipkinServiceName
属性,分别设置拦截器和该 MySQL 在 Zipkin 中展示的服务名 。
② 这里,胖友记得在测试的数据库中,创建 t_user
表,并插入一条 id = 1
的记录。SQL 脚本如下:
CREATE TABLE `t_user` ( `id` int (8 ) NOT NULL AUTO_INCREMENT COMMENT '主键自增' , `username` varchar (50 ) NOT NULL COMMENT '用户名' , `password` varchar (50 ) NOT NULL COMMENT '密码' , PRIMARY KEY (`id` ) ) ENGINE =InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET =utf8 COMMENT ='用户表' ; INSERT INTO `t_user` (`id` , `username` , `password` ) VALUES (1 , 'yudaoyuanma' , 'nicai' );
8.3 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { @Autowired private JdbcTemplate template; @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { this .selectById(1 ); return "success" ; } public Object selectById (Integer id) { return template.queryForObject("SELECT id, username, password FROM t_user WHERE id = ?" , new BeanPropertyRowMapper<>(Object.class), id); } }
在 /user/get
接口中,会执行一次 MySQL 的查询。
8.4 UserServiceApplication
创建 UserServiceApplication 类,应用启动类。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
8.5 简单测试
使用 UserServiceApplication 启动 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,从而执行一次 MySQL 查询操作。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
9. Redis 示例
示例代码对应仓库:labx-13-sc-sleuth-db-redis
。
本小节,我们来搭建一个 Zipkin 对 Redis 操作的链路追踪。Brave 并未提供对 Jedis、Lettuce、Redisson 等等 Redis 客户端的支持,所以我们只能另寻途径。
在 opentracing-contrib 项目中,有一个 java-redis-client 子项目,提供了 OpenTracing 针对 Jedis、Lettuce、Redisson 等等客户端的链路追踪。这样,我们搭配上 brave-opentracing 项目,就可以将使用 OpenTracing API 收集的链路数据,发送给 Zipkin Server 中。
brave-opentracing:OpenTracing Java Bridge for Zipkin。
This library is a Java bridge between the Brave/Zipkin Api and OpenTracing. It allows its users to write portable (in the OpenTracing sense) instrumentation that's translated into Brave instrumentation transparently.
我们来新建一个 labx-13-sc-sleuth-db-redis
项目,实现简单的 Redis 数据库操作。最终如下图所示:
另外,我们将使用 Spring Data Redis + Jedis 进行 Redis 的操作。对 Spring Data Redis 感兴趣的胖友,可以后续去看看《芋道 Spring Boot Redis 入门》 文章。
友情提示:Lettuce 基于 Brave 实现了 BraveTracing ,从而实现对 Redis 操作的链路追踪。并且,Spring Cloud Sleuth 的 instrument/redis
模块对它实现了自动配置。
因此,如果胖友项目中是使用 Lettuce 作为 Redis 客户端的话,也可以考虑采用这种方式。
9.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-db-redis</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > <exclusions > <exclusion > <groupId > io.lettuce</groupId > <artifactId > lettuce-core</artifactId > </exclusion > </exclusions > </dependency > <dependency > <groupId > redis.clients</groupId > <artifactId > jedis</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > io.opentracing.brave</groupId > <artifactId > brave-opentracing</artifactId > <version > 0.35.0</version > </dependency > <dependency > <groupId > io.opentracing.contrib</groupId > <artifactId > opentracing-redis-jedis3</artifactId > <version > 0.1.14</version > </dependency > <dependency > <groupId > io.opentracing.contrib</groupId > <artifactId > opentracing-redis-spring-data</artifactId > <version > 0.1.14</version > </dependency > </dependencies > </project >
① 额外引入 brave-opentracing
依赖,Brave 对 Opentracing 的实现。注意,Opentracing 和 JDBC 一样是一个标准,因此需要有 Brave 对 Opentracing 进行实现,从而将链路数据写入到 Zipkin 中,就好比 JDBC 有 MySQL Driver 实现,将数据写入到 MySQL 中。
② 额外引入 opentracing-redis-spring-data
和 opentracing-redis-jedis3
依赖,实现对 Jedis 来操作 Redis 的链路追踪。
9.2 配置文件
在 application.yml
中,添加数据库相关配置,如下:
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true redis: host: 127.0 .0 .1 port: 6379 password: database: 0 timeout: 0 jedis: pool: max-active: 8 max-idle: 8 min-idle: 0 max-wait: -1
没什么特别~
9.3 SleuthConfiguration
创建 SleuthConfiguration 配置类,创建一个 TracingRedisConnectionFactory Bean 对象。这样,我们就能拦截到 Redis 操作,进行相应的链路追踪。代码如下:
@Configuration public class SleuthConfiguration { @Bean public RedisConnectionFactory redisConnectionFactory (Tracer tracer, RedisProperties redisProperties) { RedisConnectionFactory connectionFactory = new JedisConnectionFactory(); TracingConfiguration tracingConfiguration = new TracingConfiguration.Builder(tracer) .extensionTag("Server Address" , redisProperties.getHost() + ":" + redisProperties.getPort()) .build(); return new TracingRedisConnectionFactory(connectionFactory, tracingConfiguration); } }
9.4 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { @Autowired private StringRedisTemplate redisTemplate; @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { this .get("demo" ); return "success" ; } public void get (String key) { redisTemplate.opsForValue().get(key); } }
在 /user/get
接口中,会执行一次 Redis 的查询。
9.5 UserServiceApplication
创建 UserServiceApplication 类,应用启动类。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
9.6 简单测试
使用 UserServiceApplication 启动 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,从而执行一次 Redis 查询操作。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
10. MongoDB 示例
示例代码对应仓库:labx-13-sc-sleuth-db-mongodb
。
和「9. Redis 示例」 一样,Brave 并未提供对 对 MongoDB 操作的链路追踪。因此,我们还是使用 opentracing-contrib 的子项目 java-mongo-driver ,搭配上 brave-opentracing 项目,实现将使用 OpenTracing API 收集的链路数据,发送给 Zipkin Server 中。
我们来新建一个 labx-13-sc-sleuth-db-mongodb
项目,实现简单的 MongoDB 数据库操作。最终如下图所示:
另外,我们将使用 Spring Data MongoDB 进行 MongoDB 的操作。对 Spring Data MongoDB 感兴趣的胖友,可以后续去看看《芋道 Spring Boot MongoDB 入门》 文章。
10.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-db-mongodb</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-mongodb</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > io.opentracing.brave</groupId > <artifactId > brave-opentracing</artifactId > <version > 0.35.0</version > </dependency > <dependency > <groupId > io.opentracing.contrib</groupId > <artifactId > opentracing-mongo-driver</artifactId > <version > 0.1.5</version > </dependency > </dependencies > </project >
重点是引入 opentracing-mongo-driver
依赖,实现对 MongoDB 操作的链路追踪。
10.2 配置文件
在 application.yml
中,添加数据库相关配置,如下:
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true data: mongodb: host: 127.0 .0 .1 port: 27017 database: yourdatabase username: test01 password: password01
没什么特别~
10.3 SleuthConfiguration
创建 SleuthConfiguration 配置类,创建一个带有 TracingCommandListener 监听器的 MongoClientOptions Bean 对象。这样,我们就能拦截到 MongoDB 操作,进行 MongoDB 的链路追踪。代码如下:
@Configuration public class SleuthConfiguration { @Bean public MongoClientOptions mongoClientOptions (Tracer tracer) { TracingCommandListener listener = new TracingCommandListener.Builder(tracer).build(); return MongoClientOptions.builder().addCommandListener(listener).build(); } }
10.4 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { @Autowired private MongoTemplate mongoTemplate; @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { this .findById(1 ); return "success" ; } public UserDO findById (Integer id) { return mongoTemplate.findOne(new Query(Criteria.where("_id" ).is(id)), UserDO.class); } }
在 /user/get
接口中,会执行一次 MongoDB 的查询。
另外,UserDO 实体类,直接点击查看。
10.5 UserServiceApplication
创建 UserServiceApplication 类,应用启动类。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
10.6 简单测试
使用 UserServiceApplication 启动 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,从而执行一次 MongoDB 查询操作。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
11. Elasticsearch 示例
示例代码对应仓库:labx-13-sc-sleuth-db-elasticsearch
。
和「4. Redis 示例」 一样,Brave 并未提供对 对 Elasticsearch 操作的链路追踪。因此,我们还是使用 opentracing-contrib 的子项目 java-elasticsearch-client ,搭配上 brave-opentracing 项目,实现将使用 OpenTracing API 收集的链路数据,发送给 Zipkin Server 中。
我们来新建一个 labx-13-sc-sleuth-db-elasticsearch
项目,实现简单的 MongoDB 数据库操作。最终如下图所示:
另外,我们将使用 Spring Data Elasticsearch 进行 Elasticsearch 的操作。对 Elasticsearch 感兴趣的胖友,可以后续去看看《芋道 Spring Boot Elasticsearch 入门》 文章。
11.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-db-elasticsearch</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-elasticsearch</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > io.opentracing.brave</groupId > <artifactId > brave-opentracing</artifactId > <version > 0.35.0</version > </dependency > <dependency > <groupId > io.opentracing.contrib</groupId > <artifactId > opentracing-elasticsearch6-client</artifactId > <version > 0.1.6</version > </dependency > </dependencies > </project >
重点是引入 opentracing-elasticsearch6-client
依赖,实现对 MongoDB 操作的链路追踪。
11.2 配置文件
在 application.yml
中,添加数据库相关配置,如下:
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true data: elasticsearch: cluster-name: elasticsearch cluster-nodes: 127.0 .0 .1 :9300
没什么特别~
11.3 SleuthConfiguration
创建 SleuthConfiguration 配置类,创建一个 TracingPreBuiltTransportClient Bean 对象。这样,我们就能拦截到 Elasticsearch 操作,进行相应的链路追踪。代码如下:
@Configuration public class SleuthConfiguration { @Bean public TransportClient elasticsearchClient (Tracer tracer, ElasticsearchProperties elasticsearchProperties) throws Exception { TracingTransportClientFactoryBean factory = new TracingTransportClientFactoryBean(tracer); factory.setClusterNodes(elasticsearchProperties.getClusterNodes()); factory.setProperties(this .createElasticsearch(elasticsearchProperties)); factory.afterPropertiesSet(); return factory.getObject(); } private Properties createElasticsearch (ElasticsearchProperties elasticsearchProperties) { Properties properties = new Properties(); properties.put("cluster.name" , elasticsearchProperties.getClusterName()); properties.putAll(elasticsearchProperties.getProperties()); return properties; } }
#elasticsearchClient(...)
方法,先创建一个 TracingTransportClientFactoryBean 对象,之后通过它创建可追踪链路的 TracingPreBuiltTransportClient Bean 对象。这样,我们就能拦截到 Elasticsearch 操作,进行 Elasticsearch 的链路追踪。
不过因为 opentracing-elasticsearch6-client
提供的 TracingPreBuiltTransportClient 类,是直接继承 PreBuiltTransportClient 类,并且并未提供传入 PreBuiltTransportClient 参数的构造方法,导致我们不能通过直接修饰 TransportClient Bean 的方式,而是只能自己定义了一个 TracingTransportClientFactoryBean 类,创建可追踪链路的 TracingPreBuiltTransportClient 对象。
TracingTransportClientFactoryBean 基本复制 TransportClientFactoryBean 的代码,主要重写了 #buildClient()
方法,创建 TracingPreBuiltTransportClient 对象。代码如下:
private Tracer tracer; protected void buildClient () throws Exception { client = new TracingPreBuiltTransportClient(tracer, settings()); }
可能这么说略微有点晦涩,胖友先继续往下看,等后面自己动手实践一次,就会很好理解了。
11.4 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { @Autowired private ESUserRepository userRepository; @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { this .findById(id); return "success" ; } public ESUserDO findById (Integer id) { return userRepository.findById(id).orElse(null ); } }
在 /user/get
接口中,会执行一次 Elasticsearch 的查询。
11.5 UserServiceApplication
创建 UserServiceApplication 类,应用启动类。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
11.6 简单测试
使用 UserServiceApplication 启动 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,从而执行一次 Redis 查询操作。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
12. RabbitMQ 示例
示例代码对应仓库:
本小节,我们来搭建一个 Spring Cloud Sleuth 对 RabbitMQ 消息的发送和消费的链路追踪。该链路通过如下插件实现收集:
我们来新建一个 labx-13-sc-sleuth-mq-rabbitmq
模块,会包括生产者和消费者两个子项目。最终如下图所示:
另外,我们将使用 Spring Cloud Stream RabbitMQ 进行 RabbitMQ 的操作。对 RabbitMQ 感兴趣的胖友,可以后续去看看《芋道 Spring Cloud 消息队列 RabbitMQ 入门》 文章。
12.1 搭建生产者
创建 labx-13-sc-sleuth-mq-rabbitmq-produce
项目,作为生产者。
12.1.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13-sc-sleuth-mq-rabbitmq</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-mq-rabbitmq-producer</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-stream-rabbit</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > </dependencies > </project >
因为 spring-cloud-starter-zipkin
依赖中,已经包含 brave-instrumentation-messaging
和 brave-instrumentation-spring-rabbit
依赖,所以无需手动引入。
12.1.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: demo-producer-application cloud: stream: binders: rabbit001: type: rabbit environment: spring: rabbitmq: host: 127.0 .0 .1 port: 5672 username: guest password: guest bindings: demo01-output: destination: DEMO-TOPIC-01 content-type: application/json binder: rabbit001 zipkin: base-url: http://127.0.0.1:9411 sleuth: messaging: rabbit: enabled: true remote-service-name: rabbitmq server: port: 18080
spring.sleuth.messaging.rabbit
配置项,为 Spring Cloud Sleuth 针对 RabbitMQ 组件的配置项,对应 SleuthMessagingProperties.Rabbit 类。
enabled
配置项,是否开启,默认为 true
。
remote-service-name
配置项,远程服务名,默认为 rabbitmq
。
12.1.3 MySource
创建 MySource 接口,声明名字为 Output Binding。代码如下:
public interface MySource { @Output ("demo01-output" ) MessageChannel demo01Output () ; }
12.1.4 Demo01Message
创建 Demo01Message 类,示例 Message 消息。代码如下:
public class Demo01Message { private Integer id; }
12.1.5 Demo01Controller
创建 Demo01Controller 类,提供发送消息的 HTTP 接口。代码如下:
@RestController @RequestMapping ("/demo01" )public class Demo01Controller { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private MySource mySource; @GetMapping ("/send" ) public boolean send () { Demo01Message message = new Demo01Message() .setId(new Random().nextInt()); Message<Demo01Message> springMessage = MessageBuilder.withPayload(message) .build(); return mySource.demo01Output().send(springMessage); } }
12.1.6 ProducerApplication
创建 ProducerApplication 类,启动生产者的应用。代码如下:
@SpringBootApplication @EnableBinding (MySource.class)public class ProducerApplication { public static void main (String[] args) { SpringApplication.run(ProducerApplication.class, args); } }
12.2 搭建消费者
创建 labx-13-sc-stream-mq-rabbitmq-consumer
项目,作为消费者。
12.2.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
友情提示:和「12.1 搭建生产者」 基本一样,点击 链接 查看。
12.2.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: demo-consumer-application cloud: stream: binders: rabbit001: type: rabbit environment: spring: rabbitmq: host: 127.0 .0 .1 port: 5672 username: guest password: guest bindings: demo01-input: destination: DEMO-TOPIC-01 content-type: application/json group: demo01-consumer-group-DEMO-TOPIC-01 binder: rabbit001 zipkin: base-url: http://127.0.0.1:9411 sleuth: messaging: rabbit: enabled: true remote-service-name: rabbitmq server: port: ${random.int[10000,19999]}
12.2.3 MySink
创建 MySink 接口,声明名字为 Input Binding。代码如下:
public interface MySink { String DEMO01_INPUT = "demo01-input" ; @Input (DEMO01_INPUT) SubscribableChannel demo01Input () ; }
12.2.4 Demo01Message
创建 Demo01Message 类,示例 Message 消息。
友情提示:和「12.1.4 Demo01Message」 基本一样,点击 链接 查看。
12.2.5 Demo01Consumer
创建 Demo01Consumer 类,消费消息。代码如下:
@Component public class Demo01Consumer { private Logger logger = LoggerFactory.getLogger(getClass()); @StreamListener (MySink.DEMO01_INPUT) public void onMessage (@Payload Demo01Message message) { logger.info("[onMessage][线程编号:{} 消息内容:{}]" , Thread.currentThread().getId(), message); } }
12.2.6 ConsumerApplication
创建 ConsumerApplication 类,启动应用。代码如下:
@SpringBootApplication @EnableBinding (MySink.class)public class ConsumerApplication { public static void main (String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
12.3 简单测试
使用 ProducerApplication 启动生产者,使用 ConsumerApplication 启动消费者。
① 首先,使用 curl http://127.0.0.1:18080/demo01/send
命令,使用 RabbitMQ Producer 发送一条消息,从而触发 RabbitMQ Consumer 消费一条消息。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④、再之后,点击红圈 的个 Span,可以看到一个 Producer 的 Span 明细。如下图所示:
⑤、再之后,点击蓝圈 的个 Span,可以看到一个 Consumer 的 Span 明细。如下图所示:
13. Kafka 示例
示例代码对应仓库:
本小节,我们来搭建一个 Spring Cloud Sleuth 对 Kafka 消息的发送和消费的链路追踪。该链路通过如下插件实现收集:
我们来新建一个 labx-13-sc-sleuth-mq-kafka
模块,会包括生产者和消费者两个子项目。最终如下图所示:
另外,我们将使用 Spring Cloud Stream Kafka 进行 Kafka 的操作。对 Kafka 感兴趣的胖友,可以后续去看看《芋道 Spring Cloud 消息队列 Kafka 入门》 文章。
13.1 搭建生产者
创建 labx-13-sc-sleuth-mq-kafka-produce
项目,作为生产者。
13.1.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13-sc-sleuth-mq-kafka</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-mq-kafka-producer</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-stream-kafka</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > </dependencies > </project >
因为 spring-cloud-starter-zipkin
依赖中,已经包含 brave-instrumentation-messaging
和 brave-instrumentation-spring-rabbit
依赖,所以无需手动引入。
13.1.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: demo-producer-application cloud: stream: bindings: demo01-output: destination: DEMO-TOPIC-01 content-type: application/json kafka: binder: brokers: 127.0 .0 .1 :9092 bindings: demo01-output: producer: sync: true zipkin: base-url: http://127.0.0.1:9411 sleuth: messaging: kafka: enabled: true remote-service-name: kafka server: port: 18080
spring.sleuth.messaging.kafka
配置项,为 Spring Cloud Sleuth 针对 Kafka 组件的配置项,对应 SleuthMessagingProperties.Kafka 类。
enabled
配置项,是否开启,默认为 true
。
remote-service-name
配置项,远程服务名,默认为 kafka
。
13.1.3 MySource
创建 MySource 接口,声明名字为 Output Binding。代码如下:
public interface MySource { @Output ("demo01-output" ) MessageChannel demo01Output () ; }
13.1.4 Demo01Message
创建 Demo01Message 类,示例 Message 消息。代码如下:
public class Demo01Message { private Integer id; }
13.1.5 Demo01Controller
创建 Demo01Controller 类,提供发送消息的 HTTP 接口。代码如下:
@RestController @RequestMapping ("/demo01" )public class Demo01Controller { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private MySource mySource; @GetMapping ("/send" ) public boolean send () { Demo01Message message = new Demo01Message() .setId(new Random().nextInt()); Message<Demo01Message> springMessage = MessageBuilder.withPayload(message) .build(); return mySource.demo01Output().send(springMessage); } }
13.1.6 ProducerApplication
创建 ProducerApplication 类,启动生产者的应用。代码如下:
@SpringBootApplication @EnableBinding (MySource.class)public class ProducerApplication { public static void main (String[] args) { SpringApplication.run(ProducerApplication.class, args); } }
13.2 搭建消费者
创建 labx-13-sc-stream-mq-kafka-consumer
项目,作为消费者。
12.2.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
友情提示:和「13.1 搭建生产者」 基本一样,点击 链接 查看。
12.2.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: demo-consumer-application cloud: stream: bindings: demo01-input: destination: DEMO-TOPIC-01 content-type: application/json group: demo01-consumer-group kafka: binder: brokers: 127.0 .0 .1 :9092 zipkin: base-url: http://127.0.0.1:9411 sleuth: messaging: kafka: enabled: true remote-service-name: kafka server: port: ${random.int[10000,19999]}
12.2.3 MySink
创建 MySink 接口,声明名字为 Input Binding。代码如下:
public interface MySink { String DEMO01_INPUT = "demo01-input" ; @Input (DEMO01_INPUT) SubscribableChannel demo01Input () ; }
12.2.4 Demo01Message
创建 Demo01Message 类,示例 Message 消息。
友情提示:和「12.1.4 Demo01Message」 基本一样,点击 链接 查看。
12.2.5 Demo01Consumer
创建 Demo01Consumer 类,消费消息。代码如下:
@Component public class Demo01Consumer { private Logger logger = LoggerFactory.getLogger(getClass()); @StreamListener (MySink.DEMO01_INPUT) public void onMessage (@Payload Demo01Message message) { logger.info("[onMessage][线程编号:{} 消息内容:{}]" , Thread.currentThread().getId(), message); } }
12.2.6 ConsumerApplication
创建 ConsumerApplication 类,启动应用。代码如下:
@SpringBootApplication @EnableBinding (MySink.class)public class ConsumerApplication { public static void main (String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
13.3 简单测试
使用 ProducerApplication 启动生产者,使用 ConsumerApplication 启动消费者。
① 首先,使用 curl http://127.0.0.1:18080/demo01/send
命令,使用 Kafka Producer 发送一条消息,从而触发 Kafka Consumer 消费一条消息。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④、再之后,点击红圈 的个 Span,可以看到一个 Producer 的 Span 明细。如下图所示:
⑤、再之后,点击蓝圈 的个 Span,可以看到一个 Consumer 的 Span 明细。如下图所示:
14. ActiveMQ 示例
示例代码对应仓库:labx-13-sc-sleuth-mq-activemq
考虑到让示例更简单,我们的示例项目包含 ActiveMQ 的生产者 Producer 和消费者 Consumer。
本小节,我们来搭建一个 Spring Cloud Sleuth 对 Kafka 消息的发送和消费的链路追踪。该链路通过如下插件实现收集:
我们来新建一个 labx-13-sc-sleuth-mq-activemq
模块,会包括生产者和消费者两个子项目。最终如下图所示:
另外,我们将使用 Spring-JMS 进行 ActiveMQ 的操作。对 ActiveMQ 感兴趣的胖友,可以后续去看看《芋道 Spring Boot 消息队列 ActiveMQ 入门》 文章。
友情提示:Spring Cloud Stream ActiveMQ 处于不维护的状态,详情可见《芋道 Spring Cloud 消息队列 ActiveMQ 入门》 文章。
14.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-mq-activemq</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-activemq</artifactId > </dependency > </dependencies > </project >
因为 spring-cloud-starter-zipkin
依赖中,已经包含 brave-instrumentation-messaging
和 brave-instrumentation-jms
依赖,所以无需手动引入。
14.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: demo-application-activemq activemq: broker-url: tcp://127.0.0.1:61616 user: admin password: admin packages: trust-all: true zipkin: base-url: http://127.0.0.1:9411 sleuth: messaging: jms: enabled: true remote-service-name: jms
spring.sleuth.messaging.jms
配置项,为 Spring Cloud Sleuth 针对 JMS 组件的配置项,对应 SleuthMessagingProperties.Jms 类。
enabled
配置项,是否开启,默认为 true
。
remote-service-name
配置项,远程服务名,默认为 jms
。
14.3 DemoController
创建 DemoController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/demo" )public class DemoController { @Autowired private DemoProducer producer; @GetMapping ("/activemq" ) public String echo () { this .sendMessage(1 ); return "activemq" ; } public void sendMessage (Integer id) { producer.syncSend(id); } }
14.4 ActiveMQApplication
创建 ActiveMQApplication.java
类,应用启动类。代码如下:
@SpringBootApplication public class ActiveMQApplication { public static void main (String[] args) { SpringApplication.run(ActiveMQApplication.class, args); } }
14.5 简单测试
使用 ActiveMQApplication 启动生产者和消费者。
① 首先,使用 curl http://127.0.0.1:8080/demo/activemq
命令,使用 ActiveMQ Producer 发送一条消息,从而触发 ActiveMQ Consumer 消费一条消息。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④、再之后,点击红圈 的个 Span,可以看到一个 Producer 的 Span 明细。如下图所示:
⑤、再之后,点击蓝圈 的个 Span,可以看到一个 Consumer 的 Span 明细。如下图所示:
15. RocketMQ 示例
比较遗憾,我们暂时无法在 Zipkin 中,实现对 RocketMQ 的链路追踪。原因如下:
如果胖友想要实现对 RocketMQ 的链路追踪,可以考虑下 SkyWalking。详细可见
16. 日志框架示例
示例代码对应仓库:labx-13-sc-sleuth-logback
在使用 Zipkin 排查问题的时候,我们可能希望能够跟链路的日志 进行关联,那么我们可以将链路编号( Zipkin TraceId )记录到日志中,从而进行关联。
友情提示:艿艿自己的项目里,在一些业务数据希望跟 Zipkin 链路进行关联时,会考虑新增一个 traceId
字段,存储 Zipkin TraceId。例如说:
发送聊天消息时,消息记录上会存储链路编号。
创建交易订单时,订单记录上会存储链路编号。
这样,在排查该数据记录时,我们就可以拿着 traceId
字段,去查响应的链路信息和日志信息。
在 Spring Cloud Sleuth 的 log
模块,提供了基于 SLF4J 门面 日志框架的集成,默认 将链路的 traceId 和 spanId 附加到日志内容当中。
我们来新建一个 labx-13-sc-sleuth-logback
项目,打印带有链路信息的日志。最终如下图所示:
友情提示:对 Logging 感兴趣的胖友,可以后续去看看《芋道 Spring Boot 日志框架 Logging 入门》 文章。
16.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-logback</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > </dependencies > </project >
16.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true log: slf4j: enabled: true
spring.sleuth.log.slf4j
配置项,为 Spring Cloud Sleuth 针对 SLF4J 组件的配置项,对应 SleuthSlf4jProperties 类。
enabled
配置项,是否开启,默认为 true
。
16.3 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { private Logger logger = LoggerFactory.getLogger(getClass()); @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { logger.info("测试日志" ); return "user:" + id; } }
在 /user/get
接口中,会执行一次日志的记录。
16.4 UserServiceApplication
创建 UserServiceApplication 类,应用启动类。代码如下:
@SpringBootApplication public class ActiveMQApplication { public static void main (String[] args) { SpringApplication.run(ActiveMQApplication.class, args); } }
16.5 简单测试
Spring Cloud Sleuth 提供的默认日志格式 为 [{applicationName},{traceId},{spanId},{export}]
,通过 TraceEnvironmentPostProcessor 类的代码可以看到,如下图:
{applicationName}
:应用名称,即 spring.application.name
配置项。
{traceId}
:类似于树结构的 Span 集合,表示一条完整的调用链路,存在唯一标识,即 TraceId 链路编号。
{spanId}
:基本工作单元,一次链路调用(可以是 RPC,DB 等等,没有特定的限制)创建一个 Span,通过一个 64 位 ID 标识它,即 SpanId 跨度编号。
{export}
:表示是否要将该信息输出到类似 Zipkin 这样的聚合器进行收集和展示。
简单来说,就是抽样收集。如果 export
为 false
时,则不进行收集
① 使用 UserServiceApplication 启动 Spring Cloud 应用。启动日志如下:
2020 -03 -20 22 :40 :53.182 INFO [user-service,,,] 41891 --- [ main] c.i.s.l.s.UserServiceApplication : Started UserServiceApplication in 2.731 seconds (JVM running for 3.276 )
因为此时没有链路的 TraceId 和 SpanId,所以 [{applicationName},{traceId},{spanId},{export}]
最终被格式化成 [user-service,,,]
。
② 使用 curl http://127.0.0.1:8080/user/get?id=1
命令,请求示例 API 接口,打印日志,可以看到带有链路信息如下:
2020 -03 -20 22 :42 :21.487 INFO [user-service,3e7 a452ddeee89a4,3e7 a452ddeee89a4,true ] 41891 --- [nio-8080 -exec-1 ] c.i.s.l.s.controller.UserController : 测试日志
[{applicationName},{traceId},{spanId},{export}]
最终被格式化成 [user-service,3e7a452ddeee89a4,3e7a452ddeee89a4,true]
。因为这里只有一个 Span,所以 TraceId 和 SpanId 相同。
至此,我们已经完成 Spring Cloud Sleuth 的日志框架示例。后续,如果胖友想要:
17. OpenTracing 示例
示例代码对应仓库:labx-13-sc-sleuth-opentracing
。
在开始本节之前,推荐胖友先阅读下《OpenTracing 官方标准 —— 中文版》 规范,对 OpenTracing 有个简单的了解。
在 opentracing-java 项目中,定义了 OpenTracing Java API。而 brave-opentracing 项目,提供了对该 OpenTracing Java API 的实现。这样,我们就可以将使用 OpenTracing API 收集的链路数据,发送给 Zipkin Server 中。
下面,我们来搭建一个 OpenTracing Java API 的使用示例。最终项目如下图所示:
17.1 引入依赖
创建 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-opentracing</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > <dependency > <groupId > io.opentracing.brave</groupId > <artifactId > brave-opentracing</artifactId > <version > 0.35.0</version > </dependency > </dependencies > </project >
通过 brave-opentracing
依赖,引入 Brave 对 Opentracing 的实现。同时 Spring Cloud Sleuth 的 OpentracingAutoConfiguration 会自动创建 BraveTracer Bean。如下图所示:
17.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true opentracing: enabled: true
spring.sleuth.opentracing
配置项,为 Spring Cloud Sleuth 针对 JMS 组件的配置项,对应 SleuthOpentracingProperties 类。
enabled
配置项,是否开启,默认为 true
。
17.3 UserController
创建 DemoController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/demo" )public class DemoController { @Autowired private Tracer tracer; @GetMapping ("/opentracing" ) public String echo () { tracer.buildSpan("custom_operation" ).withTag("mp" , "芋道源码" ).start().finish(); return "opentracing" ; } }
在 /demo/opentracing
接口中的<X>
处,我们使用 Opentracing Java API 创建了一个 Span。
更多的 Opentracing Java API 的使用,可以看看 opentracing-java 项目提供的示例哈。
17.4 UserServiceApplication
创建 UserServiceApplication 类,项目启动类。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
17.5 简单测试
使用 UserServiceApplication 启动 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令,从而执行一次 Redis 查询操作。因为,我们要追踪下该链路。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
③ 之后,我们点击该链路数据,可以看到一个 Trace 明细。如下图所示:
④ 再之后,分别点击个 Span,可以看到两个 Span 明细。如下图所示:
18. 抽样收集示例
示例代码对应仓库:labx-13-sc-sleuth-sampler
。
在访问量较少 时,链路全量 收集不会对系统带来多少负担,同时能够完整 的观测到系统的运行状况。但是在访问量较大 时,全量 的链路收集,对链路收集的客户端(应用)、服务端(例如说 Zipkin Server)、存储器(例如说 Elastcsearch)都会带来较大 的性能开销,甚至会影响应用的正常运行。
因此,在访问量级较大的情况下,我们往往会选择抽样采样 ,只选择收集部分链路信息 。Spring Cloud Sleuth 的 sampler
模块提供了两种 采样策略,如下图所示:
默认配置下,Spring Cloud Sleuth 采用 RateLimitingSampler 作为取样器,限制数量为 10 。
下面,我们来新建一个 labx-13-sc-sleuth-sampler
项目,配置使用 ProbabilityBasedSampler 作为采样器,采样百分比为 10%
。最终如下图所示:
18.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<? xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > labx-13</artifactId > <groupId > cn.iocoder.springboot.labs</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > labx-13-sc-sleuth-sampler</artifactId > <properties > <maven.compiler.target > 1.8</maven.compiler.target > <maven.compiler.source > 1.8</maven.compiler.source > <spring.boot.version > 2.2.4.RELEASE</spring.boot.version > <spring.cloud.version > Hoxton.SR1</spring.cloud.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > ${spring.boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring.cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-zipkin</artifactId > </dependency > </dependencies > </project >
18.2 配置文件
创建 application.yaml
配置文件,添加相关配置。
spring: application: name: user-service zipkin: base-url: http://127.0.0.1:9411 sleuth: web: enabled: true sampler: probability: 0.1
spring.sleuth.sampler
配置项,为 Spring Cloud Sleuth 针对 SLF4J 组件的配置项,对应 SamplerProperties 类。
probability
配置项,采样百分比,默认为空,针对 ProbabilityBasedSampler 采样器。
rate
配置项,限流采样,即每秒可收集链路的数量,默认为 10,针对 RateLimitingSampler 采样器。
如果 probability
和 rate
两个配置项都设置的情况下,采用 ProbabilityBasedSampler 采样器。原因可见 SamplerAutoConfiguration 配置类,如下图所示:
18.3 UserController
创建 UserController 类,提供示例 API 接口。代码如下:
@RestController @RequestMapping ("/user" )public class UserController { private Logger logger = LoggerFactory.getLogger(getClass()); @GetMapping ("/get" ) public String get (@RequestParam("id" ) Integer id) { logger.info("测试日志" ); return "user:" + id; } }
18.4 UserServiceApplication
创建 UserServiceApplication 类,应用启动类。代码如下:
@SpringBootApplication public class UserServiceApplication { public static void main (String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
18.5 简单测试
执行 UserServiceApplication,启动该 Spring Cloud 应用。
① 首先,使用 curl http://127.0.0.1:8080/user/get?id=1
命令 10 次 ,来发起 10 次 请求,从而测试 10%
采样率。
② 然后,继续使用浏览器,打开 http://127.0.0.1:9411/ 地址,查看链路数据。点击「查找」按钮,便可看到刚才我们调用接口的链路数据。如下图所示:
只有一条链路数据,符合 10%
采样率的预期。
666. 彩蛋
至此,我们已经完成 Spring Cloud Sleuth 的学习。如下是 Sleuth 相关的官方文档:
另外,想要在 Spring Boot 项目中使用 Zipkin 作为链路追踪的胖友,可以阅读《芋道 Spring Boot 链路追踪 Zipkin 入门》 文章。