Spring Cloud Sleuth
介绍:
在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前段请求都会形成一条复杂的分布式服务调用链,链路中的任何一环出现高延时或错误都会引起整个请求的失败。所以我们需要一个具有追踪功能的组件,来帮助我们快速准确的找出是哪个服务哪个请求的错误。
随着服务越来越多,他们的关系也许如下图一般:
Spring Cloud Sleuth就是这样,它提供了一套完整的服务跟踪的解决方案。包括链路追踪(可以看到每个请求的依赖服务)、性能分析(可以看到在每个调用消耗的时间)以及通过链路分析程序错误等。
在分布式系统中提供追踪解决方案并且兼容支持了zipkin。其实就是sleuth负责监控,zipkin负责展现。
如果你想具体了解Spring Cloud Sleuth ,请访问官网:https://github.com/spring-cloud/spring-cloud-sleuth
下载zipkin
在开始 Sleuth之前,我们首先要下载zipkin,主要用来进行链路的图形化展示。
注意:springcloud在H版本就不再不需要自己构建ZipkinServer,只需要下载jar包运行即可。
zipkin Server jar包下载:http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/
点击需要的版本下载即可
1.下载jar如下图
2.启动zipkin-server-2.12.9
cmd 进入你存放的zipkin-server-2.12.9的文件下输入如下命令:
如我的D:\tools 目录下
java -jar zipkin-server-2.12.9-exec.jar
出现如下界面,说明启动成功。
3.访问,zipkin默认端口是9411
http://localhost:9411/zipkin/
这就是zipkin图形界面。
实现原理简单介绍:
下图表示请求链路,一条链路通过Trace Id唯一标识,Span标识发起的请求信息,各个Span通过parent id 关联起来。
上图简化:
如 服务1的Span id=A parent id=null,
服务2的Span id=B parent id=A,
服务3的Span id=C parent id=B
如此形成一条或多条链路,由于Trace Id是唯一标识,所以可以清楚的知道每个服务请求的链路。
sleuth+zipkin 链路追踪的实现
环境准备
为了保证我们能看效果了,前提是需要有两个以上的服务,比如 A 服务、B 服务,然后 A 服务中调用 B 服务提供的接口。
springcloud-eureka-7001
:注册中心
springcloud-provider-user-8001
: 服务提供者
springcloud-consumer-user-80
:服务消费者
如果你有兴趣可以了解上述环境搭建请访问:
springcloud(一)-- 环境搭建及多模块使用RestTemplate实现api调用
springcloud(二) --服务注册与发现 Eureka
1.服务提供者 springcloud-provider-user-8001 支持链路追踪
只有两步,在你的服务提供者加入如下代码配置
1.1 添加pom依赖
<!--包含了sleuth+zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
1.2 application.yml
server:
port: 8001
spring:
application:
name: springcloud-provider-user
#下载地址 http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/
# 配置 zipKin Server 的地址
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
#采样率值介于0-1之间,1代表全部采集
probability: 1
#Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
添加这段配置,支持链路追踪
zipkin:
base-url: http://localhost:9411 sleuth:
sampler:
#采样率值介于0-1之间,1代表全部采集
probability: 1
1.3为了测试,我们在Controller 添加一个方法
//提供restful服务
@RestController
public class UserController {
@GetMapping("/user/zipkin")
public String getZipkin(){
return "hi,this is getZipkin server fall back.";
}
}
2.服务消费者 springcloud-consumer-user-80 支持链路追踪
这里基本和服务端类似
2.1添加pom依赖
<!--包含了sleuth+zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
2.2 application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false #不向eureka注册自己
service-url:
defaultZone: http://localhost:7001/eureka/
spring:
application:
name: cloud-user-client
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
#采样率值介于0-1之间,1代表全部采集
probability: 1
1.3 Controller 添加一个方法
@RestController
public class UserConsumerController {
@Autowired
private RestTemplate restTemplate;//提供多种便捷访问远程http服务的方法,简单的restful服务模板
private static final String REST_URL_PREFIX="http://springcloud-provider-user";
/*zipkin客户端调用服务端,测试链路追踪*/
@RequestMapping("/consumer/user/zipkin")
public String getZipkin(){
return restTemplate.getForObject(REST_URL_PREFIX+"/user/zipkin",String.class);
}
}
3.启动后测试
依次启动eureka->服务提供者->服务消费者,然后访问如下:
http://localhost/consumer/user/zipkin
访问多次
出现了正确的信息。
这时候我们查看zipkin的web页面,可以清楚的看到我们访问了那些服务服务。
选择你要查看的服务名,点击查找
对应的追踪信息可查看请求链路详细。
通过依赖可以查看链路中服务的依赖关系。
补充
Zipkin 可以将日志聚合,并进行可视化展示和全文检索。
日志输出信息如下:
2021-01-28 11:46:31.697 INFO [cloud-user-client,19b146dca26d3e40,5fb35923c170b2ee,true] 17560 --- [p-nio-80-exec-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client springcloud-provider-user initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=springcloud-provider-user,current list of Servers=[192.168.1.102:8001],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:192.168.1.102:8001; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}
在方法中记录日志,我们会发现在日志的最前面加了一部分内容,这部分内容就是 Sleuth 为服务直接提供的链路信息。
可以看到内容是由 [appname,traceId,spanId,exportable] 组成的,具体含义如下:
- appname:服务的名称,也就是 spring.application.name 的值。
- traceId:整个请求的唯一 ID,它标识整个请求的链路。
- spanId:基本的工作单元,发起一次远程调用就是一个 span。
- exportable:决定是否导入数据到 Zipkin 中。