为什么需要Spring Cloud Sleuth
Spring Cloud Seleuth是SpringCloud的一个组件,它的主要功能是在分布式系统中提供服务链路追踪解决方案。
微服务架构是一个分布式架构,微服务系统按业务划分服务单元,一个微服务系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性较高,如果出现了错误和异常,很难去定位。主要体现在一个请求可能需要调用很多个服务,而内部服务的调用复杂性决定了问题难以定位。所以在微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见,出了问题能够快速定位的目的。
Google开源了Dapper 链路追踪组件,并在2010 年发表了论文《Dapper, a Large-ScaleDistributed Systems Tracing Infrastructure)》,这篇论文是业内实现链路追踪的标杆和理论基础,具有很高的参考价值。
目前,常见的链路追踪组件有Google 的Dapper、Twitter 的Zipkin,以及阿里的Eagleeye(鹰眼)等,它们都是非常优秀的链路追踪开源组件。
基本术语
Spring Cloud Sleuth采用了Google的开源项目Dapper的专业术语。
-
Span
:基本工作单元,发送一个远程调度任务就会产生一个Span,Span是用一个64位ID唯一标识的,Trace是用另一个64位ID唯一标识的。Span还包含了其他的信息,例如摘要、时间戳事件、Span的ID以及进行ID。 -
Trace
:由一系列Span组成的,呈树状结构。请求一个微服务系统的API接口,这个API接口需要调用多个微服务单元,调用每个微服务单元都会产生一个新的Span,所有由这个请求产生的Span组成了这个Trace。 Annotation
:用于记录一个事件,一些核心注解用于定义一个请求的开始和结束:
-
cs-Client Sent
:客户端发送一个请求,这个注解描述了Span的开始; -
sr-Server Received
:服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳,便可得到网络传输的时间; -
ss-Server Sent
:服务端发送响应,该注解表明请求处理的完成(当请求返回客户端),用ss的时间戳减去sr时间戳,便可以得到服务器请求的时间。 -
cr-Client Received
:客户端接收响应,此时Span结束,如果cr的时间戳减去cs时间戳,便可以得到请求所消耗的时间;
简单实例
构建Eureka Server
依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
配置:
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://localhost:${server.port}/eureka/
启动类:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
构建Zipkin Server:
新建一个Module工程,取名为zipkin-server, 工程的pom文件继承了主Maven工程的pom文件,并引入Eureka 的起步依赖spring-cloud-starter-eureka、Zipkin Server 的依赖zipkin-server,以及Zipkin Server 的UI界面依赖zipkin-autoconfigure-ui。后两个依赖提供了Zipkin的功能和Zipkin界面展示的功能,代码如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
</dependencies>
在程序的启动类ZipkinServiceApplication加上@EnableZipkinServer注解,开启ZipkinServer 的功能,加上@EnableEurekaClient注解,启动Eureka Client,代码如下:
@SpringBootApplication
@EnableEurekaClient
@EnableZipkinServer
public class ZipkinServerApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinServerApplication.class, args);
}
}
配置:
server:
port: 9411
spring:
application:
name: zipkin-server
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
构建User Service:
在主Maven工程下建一个Module工程,取名为user-service,作为服务提供者,对外暴露API接口。
user-service 工程的pom文件继承了主Maven工程的pom文件,并引入了Eureka的起步依赖spring-cloud-starter-eureka、Web起步依赖spring-boot- starter-web,以及Zipkin的起步起来spring-cloud-starter-zipkin。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<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>
<version>RELEASE</version>
</dependency>
</dependencies>
在程序的配置文件applicatiom.yml中,指定程序名为user-service, 端口号为8762,服务注册地址http://localhost:8761/eurea/
,Zipkin Server地址为http://localhost:9411
。spring.sleuth.sampler.percentage为1.0
, 即以100%的概率将链路的数据上传给Zipkin Server, 在默认情况下,该值为0.1。配置文件代码如下:
server:
port: 8762
spring:
application:
name: user-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
percentage: 1.0
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
在UserController类建一个"/user/hi"的API接口,对外提供服务:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/hi")
public String hi() {
return "I'm forezp";
}
}
最后作为Eureka Client,需要在程序的启动类UserServiceApplication 加上@EnableEurekaClient注解,开启Eureka Client的功能。
构建Gateway Service:
新建一个名为gateway-service的工程,这个工程作为服务网关,将请求转发到user-service。作为Zipkin客户端,需要将链路数据上传给Zipkin Server,同时它也作为Eureka Client。在工程的pom文件中除了需要继承主Maven工程的pom文件,还需引入如下的依赖,代码清单如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<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>
<version>RELEASE</version>
</dependency>
</dependencies>
在工程的配置文件application.yml中,配置程序名为gateway-service, 端口号为5000,服务注册地址为http://locahost:8761/eureka/
, Zipkin Server 地址为http://localhost:9411, 以“/user-api/**" 开头的Uri请求转发到服务名为user-service 的服务
,配置代码如下:
server:
port: 5000
spring:
application:
name: gateway-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
percentage: 1.0
zuul:
routes:
api-a:
path: /user-api/**
serviceId: user-service
在程序的启动类GatewayServiceApplication 上加@EnableEurekaClient 注解,开启EurekaClient的功能,加上@EnableZuulProxy注解,开启Zuul代理功能,代码如下:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
}
测试:
完整的项目搭建完毕,依次启动eureka-server.zipkin-serveruser service和gateway-service。在浏览器上访问http:/localhost:5000/user-api/user/hi
,浏览器显示如下:
访问http://localhost:9411
,即访问Zipkin的展示界面:
这个界面用于展示Zipkin Server收集的链路数据,可以根据服务名、开始时间、结束时间、请求消耗的时间等条件来查找。单击"Find Tracks"按钮,从图中可知请求的调用情况,例如请求的调用时间、消耗时间,以及请求调用的链路情况:
单击“Dependences"按钮,可以查看服务的依赖关系。在本案例中,gateway-service将请求转发到了user-service, 这两个服务的依赖关系如图: