1. 背景

如果是单体应用,请求到响应可以通过设置一个请求序列号来记录相应的消息流转过程;但是扩展到级联调用的服务或者是微服务,跟踪一个请求从一个服务到下一个服务的流转过程,还不能影响已有的业务,这就比较困难。

2. SpringCloudSleuth

在日志中增加四个值:

1. 服务名:spring.application.name的值
2. trace ID:包含一系列span ID,形成一个树状结构
3. span ID:工作基本单元,比如发送一个HTTP 请求
4. span是否应该导出到Zipkin

3. 单服务

3.1. POM

在 eureka-service-demo 的 POM 文件中增加依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

3.2. 增加日志

修改 eureka-service-demo 的 io.github.hiant.UUIDController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class UUIDController {
/**
* name="{@link UUIDController}"
*/
private static final Logger LOGGER = LoggerFactory.getLogger(UUIDController.class);
@GetMapping("/uuid")
public String uuid() {
LOGGER.info("{}", LOGGER);
return UUID.randomUUID().toString();
}
}

3.3. 验证

  1. 启动 io.github.hiant.EurekaServiceDemoApplication

    http://localhost:8765/

  2. 启动 io.github.hiant.EurekaServiceDemoApplication

    http://localhost:8765/ 会显示注册的 UUID 服务
    第 3 步执行后,会在控制台输出:

    2017-03-02 13:48:18.152 INFO [UUID,58c1d40563eb68a4,58c1d40563eb68a4,false] 11128 — [nio-8081-exec-7] io.github.hiant.UUIDController : Logger[io.github.hiant.UUIDController]

  3. 启动 io.github.hiant.EurekaClientDemoApplication

    会在控制台输出获取到的 uuid

4. 链式服务

4.1. 新增模块 eureka-service-complex-demo

4.1.1. POM

POM 中的依赖和 eureka-service-demo 保持一致

4.1.2. 源码

class 描述
EurekaClientDemoApplication 客户端启动入口
TimeController 时间服务

4.1.2.1. EurekaServiceComplexDemoApplication

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaClient
public class EurekaServiceComplexDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceComplexDemoApplication.class, args);
}
}

4.1.2.2. TimeController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class TimeController {
/**
* name="{@link TimeController io.github.hiant.UUIDController}"
*/
private static final Logger LOGGER = LoggerFactory.getLogger(TimeController.class);
@GetMapping("/now")
public Long now() {
LOGGER.info("{}", LOGGER);
return System.currentTimeMillis();
}
}

4.1.3. 配置

文件名 描述
application.properties spring boot 配置文件
1
2
3
4
5
6
# 服务名字
spring.application.name=TIME
# 服务端口,spring cloud 使用 restful 方式调用服务
server.port=8082
# 注册服务器地址
eureka.client.service-url.defaultZone=http://localhost:8765/eureka/

4.2. 修改模块 eureka-service-demo

4.2.1. POM

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

使用 FeignClient 调用嵌套的服务

4.2.2. 源码

4.2.2.1. EurekaServiceDemoApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class EurekaServiceDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceDemoApplication.class, args);
}
@FeignClient("TIME")
interface Service {
@GetMapping("/now")
long now();
}
}

加入 FeignClient 包装的 TIME 服务相关代码及注解

4.2.2.2. UUIDController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
public class UUIDController {
@Autowired
EurekaServiceDemoApplication.Service service;
/**
* name="{@link UUIDController io.github.hiant.UUIDController}"
*/
private static final Logger LOGGER = LoggerFactory.getLogger(UUIDController.class);
@GetMapping("/uuid")
public String uuid() {
LOGGER.info("{}", LOGGER);
return UUID.randomUUID().toString() + "-" + service.now();
}
}

注入 TIME 服务,并在 uuid 方法中调用

4.3. 验证

  1. 启动 io.github.hiant.EurekaServiceDemoApplication

    http://localhost:8765/

  2. 启动 io.github.hiant.EurekaServiceDemoApplication

    http://localhost:8765/ 会显示注册的 UUID 服务
    第 4 步执行后,会在控制台输出:

    2017-03-02 14:47:02.216 INFO [UUID,a945b5d3b97a31b4,a945b5d3b97a31b4,false] 9716 — [nio-8081-exec-1] io.github.hiant.UUIDController : Logger[io.github.hiant.UUIDController]

  3. 启动 io.github.hiant.EurekaServiceComplexDemoApplication

    第 4 步执行后,会在控制台输出:

    2017-03-02 14:47:04.060 INFO [TIME,a945b5d3b97a31b4,eec94acf057e7556,false] 424 — [nio-8082-exec-1] io.github.hiant.TimeController : Logger[io.github.hiant.TimeController]

  4. 启动 io.github.hiant.EurekaClientDemoApplication

    会在控制台输出获取到的 uuid

可以看到在调用链中,uuid 服务是入口服务,所以 trace ID 和 span ID 都是:a945b5d3b97a31b4;而 time 服务是 uuid 的下游服务,所以 trace ID 是 uuid 服务的 span ID:a945b5d3b97a31b4

4.4. 扩展

HTTP 应答头中,会增加2个属性:

1. X-B3-SpanId:当前服务的 id
2. X-B3-TraceId: 上游服务的 id