一、前言
在现代软件系统中,随着业务的发展,整个系统会变得越来越复杂,且随着数据量的增加,单体项目必然要朝着微服务架构演变,将整个大的系统根据领域模型拆分成不同的微服务,但是随着系统服务化,原先的调用链路从应用内调用变成了服务间调用,调用链路变得复杂,一条调用链路变多条,且每一条链路都可能发生延迟或错误,这种场景下,一旦出现问题,排查起来将会是一个噩梦。为了解决这个问题,分布式系统调用跟踪应运而生。
目前业界分布式服务跟踪的理论基础主要来自于 Google 的一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,使用最为广泛的开源实现是 Twitter 的 Zipkin。为了实现平台无关、厂商无关的分布式服务跟踪,CNCF 发布了布式服务跟踪标准 Open Tracing,各大厂商基于该标准做了不同的实现。
Spring Cloud作为一套完整的微服务框架,作为组件之一的Spring Cloud Sleuth 为我们提供了一套完整的解决方案。本文中,我将详细介绍如何使用 Spring Cloud Sleuth + Zipkin 来为我们的微服务架构增加分布式服务跟踪的能力。
二、Spring Cloud Sleuth
作为微服务间的链路追踪解决方案,需要做到3点:
- 数据收集
- 数据存储
- 数据展示
大型分布式系统的追踪数据分为实时数据和全量数据,其中实时数据主要用于问题排查,全量数据主要用于性能优化。
生成数据的服务追踪单元,由客户端发起请求,在请求到达服务边界上,到被调用服务返回客户端响应为止,这个过程被称为一个Trace
,服务间的调用通过一个TraceId
串联起来,调用链路中经过的服务被称为Span
,最终,一个服务追踪单元的基本组成就是由一个Trace
和多个Span
顺序组成的结构。把这些带有Span
的Trace
记录下来,就可以描绘出一幅系统的服务拓扑图。附带上Span
中的响应时间,以及请求成功与否等信息,就可以在发生问题的时候,找到异常的服务。
Spring Cloud Sleuth 为服务间调用提供了链路追踪,通过查看整个调用链路,可以方便的知道一个服务请求经过了哪些服务,每个服务处理花费了多长以及定位调用异常点,除此以外,通过Sleuth,还可以确定
- 耗时分析: 通过 Sleuth 可以很方便的了解到每个采样请求的耗时,从而分析出哪些服务调用比较耗时;
- 可视化错误: 对于程序未捕捉的异常,可以通过集成 Zipkin 服务界面上看到;
- 链路优化: 对于调用比较频繁的服务,可以针对这些服务实施一些优化措施。
下图很全面的展示了整个调用链路。
Sleuth需要与Zipkin做集成,将信息发送到 Zipkin,利用 Zipkin 的存储来存储信息,利用 Zipkin UI 来展示数据。
三、Zipkin
Zipkin 是 Twitter 的一个开源项目,它基于 Google Dapper 实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。
我们通过在各个服务上做链路追踪后,将数据传输到Zipkin做存储,Zipkin提供了友好的UI通过使用TraceId或者服务名称等作为查询条件查询调用链路和服务间的依赖关系。
如上图为zipkin与服务集群集成的基础架构图,图中主要由4个组件构成:
- Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为 Zipkin 内部处理的 Span 格式,以支持后续的存储、分析、展示等功能。
- Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中,如 Mysql 和 Elasticsearch 等。
- RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。
- Web UI:UI 组件,基于 API 组件实现的上层应用。通过 UI 组件用户可以方便而有直观地查询和分析跟踪信息
四、集成使用
4.1 安装部署zkpin
zkpin支持多种方式部署,如下载源码编译,直接下载jar包和docker部署等,本文出于便利,仅展示通过docker容器安装方式,其他方式读者自行查询了解。
docker run -d -p 9411:9411 openzipkin/zipkin
使用以上docker脚本命令即可安装部署,较其他方式更加方便,执行完毕后,等待zipkin镜像下载到本地仓库并启动,通过docker ps
查看运行状态。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9CujuRz1-1646119561016)(/media/202111/D84EAA7D-3705-4ff8-B8A6-3855C3036B15_1636680662.png)]
如上图所示,则表明zipkin正常启动,接下来通过http://ip:9411/
访问web页面,如下图所示,即可正常访问。接下来需要继承到微服务集群中进行数据采集。
4.2 zkpin集成Spring cloud sleuth
由于各个微服务都需要引入zkpin,才能进行链路数据采集,因此,将依赖引入放在父pom文件,这样就无需在每个子pom重复引入。
<!-- 链路跟踪 sleuth和zipkin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
引入pom依赖后,在各个微服务配置文件中进行以下配置:
spring:
sleuth:
web:
client:
# 开启采集链路
enabled: true
sampler:
# 默认采集是 0.1(百分之十),生产环境采用默认,测试环境可以修改为1.0
probability: 1.0
# zipkin服务所在地址
zipkin:
base-url: http://ip:9411/
在做好以上配置后,启动各个微服务,zipkin就可以追踪整个服务间调用链路了。
本文中各微服务启动后,使用Postman进行测试。
本文中演示的接口为调用全局唯一ID生成服务,请求首先到达网关服务,经过路由解析后,转发到全局唯一ID生成服务,该服务再调用Dubbo接口生成主键ID返回。
如图所示,整个调用链路经过了2个服务,实际上应该是3,但是全局唯一ID生成服务调用Dubbo接口,未被算到链路中,,为什么会这样呢?此处算是本文留下的疑惑,供读者自行探索。
到此为止,zkpin集成Spring cloud sleuth做链路追踪结束,可以看出,zkpin对服务集成无侵入,且集成方便。提供的Web也可以很方便的查看调用链路,但是也有不足之处,就是zkpin提供的服务较为简单,只有查询和服务依赖查看,对于一些复杂的服务需求无法满足,需要根据实际二次开发。
五、问题解决
在集成过程中,由于pom依赖问题,导致服务启动会报以下错误
java.lang.IllegalStateException: Failed to introspect Class [org.springframework