Spring Cloud Alibaba系列之nacos:(1)安装
Spring Cloud Alibaba系列之nacos:(2)单机模式支持mysql
Spring Cloud Alibaba系列之nacos:(3)服务注册发现
Spring Cloud 系列之OpenFeign:(4)集成OpenFeign
Spring Cloud 系列之OpenFeign:(5)OpenFeign的高级用法
Spring Cloud 系列之OpenFeign:(6)OpenFeign的链路追踪
在前面一节Spring Cloud 系列之OpenFeign:(6)OpenFeign的链路追踪中,通过MDC实现了一个简易的链路追踪服务:
里面对于链接追踪没有过多的讨论,所以这里还是要先对它是什么,有什么作用,常用实现方式再做一次探讨!
链路追踪这个名词也是17年初的时候才接触,当时入职一家做互联网金融的公司(以前都是在传统软件公司做企业级金融系统开发)。公司据说不久前融资了一笔钱,招兵买马准备大干一场。那时候公司在推行微服务,框架就是Spring Cloud套件,也就接触了zipkin这个概念,当时很经过一番名词轰炸,还是带来了不小的震撼:微服务,Springboot,注册中心Eureka,配置中心Config,网关Zuul,断路器,负载Ribbon,以及链路追踪的Sleuth(Springboot3已经被Micrometer Tracing项目取代)甚至是JAVA8的Lambda,还入手了一本翟永超的《Spring Cloud微服务实战》。
被名词轰炸的一个背后原因是在开发toB系统的那些年,系统基本都是单体的,所有的功能都在一个项目代码里面,包括前端/后端(那时候也不流行前后端分离):
在单体系统时代出了问题或者要排查问题,基本在本系统排查就够了,一般不超出关联上下游2-3个系统:
但是在分布式系统架构下,这个方式就有点困难了:
所以分布式系统架构对于统一的服务调用请求追踪就显示很有必要了:一个链路追踪需要达到至少2方面的要求:
上面说了一个链路追踪需要达到至少2方面的要求,既要追踪每次调用完整的链路,又要记录链路的每个服务细节,而这个在专业术语上分别叫作"追踪-Trace"与"跨度-Span":
Trace 和 Spans(图片来源于Dapper 论文)
现在就先通过集成SpringCloud组件的Sleuth体验一下吧
这里还是以工程tsm为例来演示SpringCloud如何集成Sleuth!
因为是SpringCloud项目,所以在auth及cipher工程都引入:
org.springframework.cloud
spring-cloud-starter-sleuth
修改application.properties文件,将系统日志请求调成DEBUG级别:
logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG
先启动nacos,再新增一个测试接口并启动cipher服务:
@RestController
@Slf4j
public class SleuthTestController
{
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
public void echo(@PathVariable String str)
{
log.info("echo init begin..........tId:{}", MdcContext.getTraceId());
}
}
然后发送一个请求进行测试:http://localhost:8082/echo/aa,观察打印的日志类似如下:
35:06.575 DEBUG [cipher-service,1091573eecf0928c,1091573eecf0928c,true] 5204 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : GET "/echo/aa", parameters={}
2023-08-19 21:35:06.596 INFO [cipher-service,1091573eecf0928c,1091573eecf0928c,true] 5204 --- [nio-8081-exec-1] c.t.t.c.controller.SleuthTestController : echo init begin..........tId:26dee1ed-823a-4738-9040-4b400dce816c
2023-08-19 21:35:06.609 DEBUG [cipher-service,1091573eecf0928c,1091573eecf0928c,true] 5204 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
这里要说明一下格式:应用名称,TraceId,SpanId,是否输出信息用于zipkin等服务收集
先启动nacos,再新增一个测试接口并启动cipher服务:log服务远程调用cipher服务
@Autowired
private CipherFeignClient authFeignClient;
@RequestMapping(value = "/cipher/echo/{str}", method = RequestMethod.GET)
public String logEcho(@PathVariable String str)
{
return authFeignClient.echo(str);
}
然后发送一个请求进行测试:http://localhost:8082/cipher/echo/aa,观察打印的日志类似如下:
前面一篇通过MDC实现了简单的链路追踪,如果应用使用了logback就可以自动从MDC里面获取sleuth的信息:
@Slf4j
public class MdcInterceptor implements HandlerInterceptor
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
// 获取tId
String tId = MdcContext.getTraceId();
// 将tId放入MDC中,方便日志输出
MDC.put("TraceId", tId);
// 从MDC中获取sleuth的traceId,spanId
String traceId = MDC.get("traceId");
String spanId = MDC.get("spanId");
log.info("sleuth traceId:{}, spanId:{}", traceId, spanId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
{
// 清除线程上下文
MdcContext.clear();
// 清楚MDC内容
MDC.clear();
}
}
在日志配置文件中logback.xml,可以直接获取:
%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}
The SLF4J MDC is always set and logback users immediately see the trace and span IDs in logs per the example shown earlier. Other logging systems have to configure their own formatter to get the same result. The default is as follows:
logging.pattern.level
set to%5p [${spring.zipkin.service.name:${spring.application.name:-}},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]
(this is a Spring Boot feature for logback users). If you do not use SLF4J, this pattern is NOT automatically applied.
上面通过sleuth实现了链路的追踪,但是sleuth有一个缺点就是没有可视化界面,它只是把追踪信息输出到日志中,这样就不方便直观的全链路查询排查问题。所以通常情况下会搭配zipkin来做数据展示,并可以将日志输出到redis等做持久化。
首先安装zipkin服务端,对于java来说,官方提供了docker安装或者直接运行jar包的方式。
这里就通过直接启动jar的方式来测试(如果是windows的话可以直接通过maven下载依赖包)
下载完成之后,启动一下
java -jar zipkin-server-2.24.3-exec.jar
正常会输出下面的启动信息:
访问一下zipkin显示下面表示运行成功,http://127.0.0.1:9411/zipkin/:
如果想要同时使用sleuth与zipkin,将上面的pom依赖修改如下:
org.springframework.cloud
spring-cloud-starter-zipkin
还是以上面的多个服务调用为例,发送测试请求之后,再zipkin上面查看调用链路:
里面清晰的记录的请求接口,响应时间,及结果,可以点击SHOW查看详情,飘红的就是调用失败的,比如把远程服务cipher关闭导致失败的:
而对于的成功的记录:
如果对于zipkin有定制化需要,可以通过进行配置或开发!
比如zipkin跟服务不在同一个服务,可以配置zipkin的地址:
If you want to find Zipkin through service discovery, you can pass the Zipkin’s service ID inside the URL, as shown in the following example for
zipkinserver
service ID:spring.zipkin.baseUrl: https://zipkinserver/
By default, api path will be set to
api/v2/spans
orapi/v1/spans
depending on the encoder version. If you want to use a custom api path, you can configure it using the following property (empty case, set ""):spring.zipkin.apiPath: v2/path2
To disable this feature just set
spring.zipkin.discoveryClientEnabled
to `false.