简介
套用官网的介绍,Sleuth是一套Spring Cloud的分布式服务追踪(跟踪)解决方案。Sleuth借用了Google Dapper和Twitter Zipkin,所以学习之前,先要了解Zipkin以及一些像Span、Trace等概念。目前Zipkin是服务追踪最广泛使用的开源解决方案,同时与Spring Cloud Sleuth集成也很方便。为了实现平台无关、厂商无关的分布式服务跟踪,CNCF(云原生计算基金会)发布了布式服务跟踪标准 Open Tracing。
为什么需要服务追踪
先考虑问题:在微服务架构下,一次请求调用服务接口发生异常,如何快速定位问题出现在哪里?
在微服务架构下,服务都进行了拆分,用户的每次请求往往需要涉及到多个业务,不同的开发团队、编程语言,不同的部署场景,发布在不同的数据中心甚至不同的城市,每次客户的请求调用,经过哪些服务处理,通过查看完整的服务追踪链路,形成拓补图可以更加直观的了解业务流转情况,也可以针对当前的系统进行分析是否需要扩容、优化接口、失败缓解,还有通过日志快速定位哪些是调用失败的环节等等。
基本概念
- Span
代表了一组基本的工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(Span ID)来标记它的开始、具体过程和结束。通过Span ID的开始和结束时间戳,就能统计该Span的调用时间,除此之外,我们还可以获取如事件的名称,请求信息等元数据。
- Trace
由一组Trace ID相同的Span串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即Trace ID),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。
- Annotation
用它记录一段时间内的事件,内部使用的重要注释:
CS(Client Send)客户端发出请求,开始一个请求的生命
SR(Server Received)服务端接受到请求开始进行处理, timestampSR - timestampCS = 网络延迟(服务调用的时间)
SS(Server Send)服务端处理完毕准备发送到客户端, timestampSS - timestampSR = 服务器上的请求处理时间
CR(Client Reveived)客户端接受到服务端的响应,请求结束。 timestampCR - timestampCS = 请求的总时间
服务跟踪原理
分布式系统的服务跟踪主要包括下面两个关键点:
1,为了实现请求跟踪,当请求发送到分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的跟踪标识Trace ID,同时在分布式系统内部流转的时候,框架保持该唯一标识,直到返回给请求方位置。
服务追踪的追踪单元是从客户发起请求(request)抵达被追踪系统的边界开始,到被追踪系统向客户返回响应(response)为止的过程,称为一个“trace”。
2,为了统计各处理单元的时间延迟,当请求到达各个服务组件时,是通过一个唯一标识Span ID来标记它的开始,具体过程以及结束。对每一个Span来说,它必须有开始和结束两个节点,通过记录开始Span和结束Span的时间戳,就能统计出该Span的时间延迟,除了时间戳记录之外,它还可以包含一些其他元数据,比如时间名称、请求信息等。这样,若干个有序的 Span 就组成了一个 Trace。在系统向外界提供服务的过程中,会不断地有请求和响应发生,也就会不断生成 Trace,把这些带有Span 的 Trace记录下来,就可以描绘出一幅系统的服务拓扑图。附带上 Span 中的响应时间,以及请求成功与否等信息,就可以在发生问题的时候,找到异常的服务;根据历史数据,还可以从系统整体层面分析出哪里性能差,定位性能优化的目标。
集成Zipkin
首先构建Zipkin Server,单独下载Zipkin Server即可,下载地址https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/,我们这里下载2.12.1版本,默认端口9411
启动命令:
java -jar zipkin-server-2.12.1-exec.jar
然后我们新建项目工程,只要准备两个Spring Boot的工程即可,我基于上一节课的工程进行了改造,只保留了Service-Provider和他的一个copy,首先引入sleuth和zipkin的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
然后在配置文件中加入一个指向zipkin server和sleuth的采样比例设置
server:
port: 9001
spring:
application:
name: service-provider-a
zipkin:
base-url: http://localhost:9411 #zipkin server
sleuth:
sampler:
percentage: 1.0 #sleuth 采样比例
编写两个服务的代码,由一个服务调用另外一个服务,调用方代码
package org.dothwinds.serviceprovider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RestController
public class SpringCloudStudyServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudStudyServiceProviderApplication.class, args);
}
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@GetMapping("/sayHi")
public String sayHi() {
return restTemplate.getForObject("http://localhost:9002/sayHi", String.class);
}
}
被调用方代码:
package org.dothwinds.serviceprovider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class SpringCloudStudyServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudStudyServiceProviderApplication.class, args);
}
@GetMapping("/sayHi")
public String sayHi() {
return "hi, im from service provider copy service for sleuth";
}
}
启动服务,首先打zipkin的图形化界面,访问地址:http://localhost:9411
紧接着,访问服务调用接口http://localhost:9001/sayHi,点击zipkin的依赖,可以看到服务依赖的效果,点击查找,可以查看一些详细信息
本文用了sleuth和zipkin来做演示,其实单独用sleuth就能收集到追踪信息,但是信息都是在命令行下查看,不方便,引入zipkin它自带ui,查看起来也比较方便,有兴趣的可以单独用sleuth最终信息,先不装zipkin,查看命令行的追踪信息;另外zipkin server显示的信息默认是保存在内存中的,实际应用中,需持久化到DB之类的,本文不做更详细的学习记录了,如果需要可以自行搜索一下。
参考资料:
https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/single/spring-cloud.html
https://blog.51cto.com/zero01/2173394?source=dra
代码:
https://gitee.com/dothwinds/Spring-Cloud-Study/tree/master/spring-cloud-study-sleuth