背景
本文是《Java 后端从小白到大神》修仙系列之框架学习,Spring Cloud 微服务实战系列的 第七篇
。Spring Cloud 是构建微服务架构的基石,拥有完整的服务治理生态,在云原生架构中广泛应用。本系列将从架构认知到实际工程,逐步构建一套企业级 Spring Cloud 微服务项目。若想详细学习请点击首篇博文开始,现在开始学习。
文章概览
链路追踪体系构建:Micrometer Tracing + Zipkin + 日志关联:
- 链路追踪演进:从 Sleuth 到 Micrometer Tracing
- Micrometer Tracing 原理与 Zipkin 可视化接入
- Gateway + Feign 链路自动传递
- 日志注入 TraceId / SpanId
- 异步线程链路追踪传播
1. 链路追踪演进:从 Sleuth 到 Micrometer Tracing
旧的项目可能在使用 Spring Cloud Sleuth 来实现链路追踪功能,但自 2022 年起已不再维护,Spring 官方推荐使用 Micrometer Tracing 替代。
Micrometer Tracing 更加轻量、模块化,并支持多种 backend,如 Zipkin、Jaeger、OpenTelemetry,是现代云原生环境下更优的选择。
2. Micrometer Tracing 集成与 Zipkin 可视化
在所有需要链路追踪的服务中加入以下依赖:
1
2
3
4
5
6
7
8
|
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
|
application.yaml 配置
1
2
3
4
|
management:
tracing:
sampling:
probability: 1.0 # 100%采样,生产可调整为0.1或动态配置
|
启动 Zipkin 服务
使用 docker-compose:
1
2
3
4
|
zipkin:
image: openzipkin/zipkin
ports:
- "9411:9411"
|
访问:http://localhost:9411
查看完整的请求调用链!
3. Gateway + Feign 链路追踪自动传递
Micrometer Tracing 与 Spring Cloud Gateway、OpenFeign 自动集成:
- Gateway:生成 traceId,传递至下游服务
- Feign:自动携带上下文,无需手动注入
无需额外配置,只需在 gateway-service、user-service、task-service 中接入依赖和配置即可。
4. 日志注入 TraceId / SpanId
通过日志 MDC 机制,自动注入链路 ID 信息:
1
2
3
|
logging:
pattern:
level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
|
输出示例:
1
|
INFO [gateway-service,9fabc1234,3bcd4567] 请求进入网关
|
方便结合 ELK、SkyWalking 等日志分析系统进行统一追踪。
通过 TraceId 可以在日志聚合平台(如 ELK)中快速定位某一次请求的所有日志记录。
5. 异步线程上下文传播支持
Micrometer Tracing 支持异步传播:
1
2
3
4
5
|
@Async
public CompletableFuture<Void> runAsync() {
log.info("异步调用,依旧包含TraceId");
return CompletableFuture.completedFuture(null);
}
|
无需额外操作,自动传递上下文信息。
6. 搭建两个微服务
user-service
:提供用户信息接口(Feign 被调用方)
task-service
:通过 FeignClient 调用 user-service
获取用户信息
user-service
1
2
3
4
5
6
7
8
9
|
user-service
├── controller/UserController.java
├── service/UserService.java
├── repository/UserRepository.java
├── entity/User.java
├── dto/UserDTO.java
├── resources/application.yaml
├── resources/bootstrap.yaml
└── pom.xml
|
user-service 源代码
1
2
3
4
5
6
7
8
|
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public UserDTO getUser(@PathVariable Long id) {
return new UserDTO(id, "用户" + id);
}
}
|
1
2
3
4
5
6
7
|
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
private Long id;
private String name;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
@Entity
@Table(name = "users")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
}
|
1
2
|
public interface UserRepository extends JpaRepository<User, Long> {
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
/**
* 根据用户ID获取用户信息
*/
public UserDTO getUserById(Long id) {
User user = userRepository.findById(id).orElse(null);
if (user == null) return null;
return new UserDTO(user.getId(), user.getUsername());
}
}
|
项目配置文件
application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
server:
port: 9002
spring:
application:
name: user-service
profiles:
active: dev
datasource:
url: jdbc:mysql://localhost:3306/cloud_task?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
jpa:
hibernate:
ddl-auto: update # 或 none、create、validate(根据你需求)
show-sql: true
database-platform: org.hibernate.dialect.MySQL8Dialect
cloud:
nacos:
discovery:
namespace: 47bd187a-3446-43a7-8a56-573dc8abc147
|
bootstrap.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
server:
port: 9002
spring:
application:
name: user-service
profiles:
active: dev
datasource:
url: jdbc:mysql://localhost:3306/cloud_task?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
jpa:
hibernate:
ddl-auto: update # 或 none、create、validate(根据你需求)
show-sql: true
database-platform: org.hibernate.dialect.MySQL8Dialect
cloud:
nacos:
discovery:
namespace: 47bd187a-3446-43a7-8a56-573dc8abc147
|
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yutao</groupId>
<artifactId>cloudtask2</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.yutao</groupId>
<artifactId>user-service</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Spring Boot 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 可选:Nacos Discovery(如果需要注册自身) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 动态刷新配置所需 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 可选:暴露刷新端点 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 链路追踪 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
|
task-service
1
2
3
4
5
6
7
8
|
task-service
├── controller/TaskController.java
├── feign/UserClient.java
├── dto/TaskDTO.java
├── service/TaskService.java
├── resources/application.yaml
├── resources/bootstrap.yaml
└── pom.xml
|
task-service 源代码
1
2
3
4
5
6
7
8
9
10
11
12
|
@RestController
@RequestMapping("/tasks")
public class TaskController {
@Autowired
private UserClient userClient;
@GetMapping("/create/{userId}")
public String createTask(@PathVariable Long userId) {
UserDTO user = userClient.getUserById(userId);
return "为用户 " + user.getUsername() + " 创建任务成功";
}
}
|
1
2
3
4
5
|
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
UserDTO getUser(@PathVariable("id") Long id);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Service
public class TaskService {
// 假设调用 FeignClient 获取用户信息
@Autowired
private UserClient userClient;
public TaskDTO getTaskWithUser(Long taskId) {
// 模拟任务查询
TaskDTO task = new TaskDTO(taskId, "测试任务", 1001L);
// 通过 Feign 调用 user-service 获取用户信息
UserDTO user = userClient.getUserById(task.getUserId());
task.setUser(user);
return task;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TaskDTO {
private Long id;
private String name;
private Long userId;
private UserDTO user; // 用户信息
public TaskDTO(Long id, String name, long userId) {
this.id = id;
this.name = name;
this.userId = userId;
}
}
|
项目配置文件
application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
|
server:
port: 9001
spring:
application:
name: task-service
profiles:
active: dev
cloud:
nacos:
discovery:
namespace: 47bd187a-3446-43a7-8a56-573dc8abc147
|
bootstrap.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
spring:
application:
name: task-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: 47bd187a-3446-43a7-8a56-573dc8abc147
group: DEFAULT_GROUP
discovery:
namespace: 47bd187a-3446-43a7-8a56-573dc8abc147
profiles:
active: dev
|
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yutao</groupId>
<artifactId>cloudtask2</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.yutao</groupId>
<artifactId>task-service</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Spring Boot 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 可选:Nacos Discovery(如果需要注册自身) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 动态刷新配置所需 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 可选:暴露刷新端点 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 链路追踪 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.yutao</groupId>
<artifactId>user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
|
总结
从 Sleuth 到 Zipkin 的链路收集与可视化。服务间的 TraceId 自动传递,为我们后续日志追踪、接口耗时分析、异步问题定位提供了扎实基础。