Spring Cloud分布式服务跟踪Sleuth组件

在一个大型的微服务项目中、各微服务间调用关系错综复杂,几乎每一个前端请求都会形成一条复杂的分布式服务调用链路, 在每条链路中任何一个依赖服务出现延迟过高错误的时候都有可能引起请求最后的失败,所以我们需要一个全链路追踪器,这就sleuth的作用。

1.快速入门

首先我们引入两个基础的Spring Cloud工程,两个工程都注册到同样一个eureka注册中心,同时trace-1工程调用trace-2服务获取结果。

1. 引入sleuth包

<dependency> 
	<groupid>org.springframework.cloud</groupid> 
	<artifactid>spring-cloud-starter-sleuth</artifactid> 
</dependency> 

2.在服务中加入日志

@RequestMapping(value = "/trace-2", method = RequestMethod.GET) 
public String trace() { 
	logger.info("===<call trace-2>==="); 
	return "Trace"; 
}

3.请求调用

// 加入sleuth前的日志
-- trace-2 
INFO 7136 --- [nio-9102-exec-1] ication$$EnhancerBySpringCGLIB$$52a02f0b: ===<call 
trace-2>===

// 加入后的日志
-- trace-2 
INFO [trace-2, f410ab57afd5cl45, e9a377dc2268bc29, false] 23112 --- [nio-9102-exec-1] 
ication$$EnhancerBySpringCGLIB$$e6cb4078 : ===<call trace-2>=== 

我们可以在INFO中看出多了很多调用过程中的服务数据。

  • 第一个trace-2:application.properties中 spring.application.name参数配置的属性。
  • 第二个f410ab57afd5cl45:traceId用来标识一条请求链路,一次请求就只会生成同一个traceId,来代表属于该请求过程中。
  • 第三个a9f2118fa2019684:SpanId,它表示一个基本的工作单元, 比如发送一个HTTP请求。
  • 第四个false: 表示是否要将该信息输出到Zipkin(内存日志存储)等服务中来收集和展示 。

2.跟踪原理

  • TraceId:在分布式系统内部流转的时候,框架始终保持传递该唯一标识, 直到返回给请求方为止, 这个唯一标识就是前文中提到的Trace ID。 通过TraceID的记录, 我们就能将所有请求过程的日志关联起来。
  • SpanId:为了统计各处理单元的时间延迟, 当请求到达各个服务组件时, 或是处理逻辑到达某个状态时, 也通过一个唯一标识来标记它的开始、 具体过程以及结束, 该标识就是前文中提到的SpanID。 对于每个Span来说, 它必须有开始和结束两个节点, 通过记录开始 Span和结束Span的时间戳。

3.收集原理

先来看看Zipkin的服务跟踪,zipkin是一个基于内存的日志收集系统 ,我们生成的大量服务日志可以存储到zipkin中,然后我们就可以进行查询、分析等。 里面有四个最重要的概念:

  1. Span 基础工作单元,一个http请求产生多个不同的事件状态(下面的4种Annotation)在同一条请求链路中的不同工作单元都会有不同的Span ID, 但是它们的Trace ID是相同的。
  2. Trace 由上面所说的具有相同TraceId的Span构成的树状结构
  3. Annotation 可以把 Annotation 理解为一个包含有时间戳的事件标签,对于一个Http请求来说定义了四种Annotation。
  • cs (Client Send): 该 Annotation 用来记录客户端发起了一个请求, 同时它也标识了这个 HTTP 请求的开始。

  • sr (Server Received): 该 Annotation 用来记录服务端接收到了请求, 并准备开始处理它。通过计算 sr 与 cs两个Annotation的时间戳之差,我们可以得到当前HTTP请求的网络延迟。

  • ss (Server Send): 该 Annotation 用来记录服务端处理完请求后准备发送请求响应信息。 通过计算 ss 与 sr 两个 Annotation 的时间戳之差, 我们可以得到当前服务端处理请求的时间消耗。

  • er (Client Received): 该 Annotation 用来记录客户端接收到服务端的回复, 同时它也标识了这个 HTTP 请求的结束。 通过计算 er 与 cs 两个 Annotation 的时间戳之差, 我们可以得到该 HTTP 请求从客户端发起到接收服务端响应的总时间消耗。

在这里插入图片描述

  • SpanT: 记录了客户端请求到达trace-1和trace-1发送请求响应的两个事件, 它可以计算出客户端请求响应过程的总延迟时间。
  • Span A: 记录了trace-1应用在接收到客户端请求之后调用处理方法的开始和结 束两个事件, 它可以计算出trace应用用于处理客户端请求时, 内部逻辑花费 的时间延迟。
  • Span B: 记录了trace-1应用发送请求给 trace-2应用、trace-2应用接收请 求, trace-2 应用发送响应、trace-1应用接收响应4个事件, 它可以计算出 trace-1调用trace-2 的总体依赖时间(cr - cs), 也可以计算出trace-1到trace-2的网络延迟(sr -cs), 还可以计算出trace-2应用用于处理客户端请求的花费的时间延迟(ss -sr)
  • Span C: 记录了trace-2应用在接收到trace-1的请求之后调用处理方法的开始 和结束两个事件,它可以计算出trace-2应用处理来自trace-1的请求时,内部 方法调用花费的时间延迟。

总结

Sleuth 通过 traceId 实现了对分布式系统调用链路的跟踪。在一次服务请求链路中,会保持并传递一个 traceId,从而将不同服务的请求跟踪信息串联起来,不同服务的 traceId相同 表示处在同一请求链中。基于 HTTP 请求的数据传递有两种方式:一种是做为参数传递,另一种是做为头信息传递。而 Sleuth 的 traceId 属于附加信息,不参与实际的业务,所以做为参数传递并不合适,实际也是作为头信息来传递的。

end
  • 作者:Endwas(联系作者)
  • 发表时间:2021-08-10 11:43
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转博主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者名字和博客地址
  • 评论