微服务教程 | 袁庭新老师带你玩儿爆Spring Cloud Sleuth+Zipkin分布式微服务链路追踪
分布式应⽤架构虽然满⾜了应⽤横向扩展的需求,但是运维和诊断的过程变得越来越复杂,例如会遇到接⼝诊断困难、应⽤性能诊断复杂、架构分析复杂等难题,传统的监控⼯具并⽆法满⾜,分布式链路系统由此诞⽣。

01 链路追踪介绍
1.1 微服务链路追踪介绍
一个完整的微服务系统一般由成百上千,甚至几万、几十万个服务实例构成。抛两个常⻅的问题:
微服务调⽤链路出现了问题怎么快速排查?
微服务调⽤链路耗时⻓怎么定位是哪个服务?
分布式链路追踪(Distributed Link Tracking),就是将一次分布式请求还原成调用链路,进行日志记录,性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。

所以,需要用链路跟踪工具来监控微服务状态,当出现问题时能及时定位问题点,快速解决问题。
1.2 微服务链路追踪产品
在分布式系统中,链路追踪的解决方案有很多产品。具体介绍见下:
log4j是Spring Cloud提供的分布式系统中链路追踪解决方案。
Cat由大众点评开源,基于Java开发的实时应用监控平台,包括实时应用监控,业务监控。集成方案是通过代码埋点的方式来实现监控。
Pinpoint专注于链路和性能监控,韩国研发团队开源,埋点无侵入,UI功能较强。但毕竟是小团队,不知道会不会一直维护着,目前版本仍在更新中。
SkyWalking是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能较强,接入端无代码侵入。目前已加入Apache孵化器。SkyWalking专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。
Zipkin由Twitter公司开源,开放源代码分布式的跟踪系统,用于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现图形化。该产品结合Spring Cloud Sleuth使用较为简单,集成很方便,但是功能较简单。
注意:Spring Cloud Alibaba技术栈中并没有提供自己的链路追踪技术的,我们可以采用Sleuth + Zipkin来做链路追踪解决方案。
02 Spring Cloud Sleuth概述
2.1 Spring Cloud Sleuth介绍
Spring Cloud Sleuth为Spring Cloud的分布式跟踪解决方案提供API。它与OpenZipkin Brave集成。
Spring Cloud Sleuth能够跟踪您的请求和消息,以便您可以将该通信与相应的日志条目相关联。您还可以将跟踪信息导出到外部系统以可视化延迟。Spring Cloud Sleuth直接支持OpenZipkin兼容系统。
2.2 Spring Cloud Sleuth术语
Spring Cloud Sleuth借用了Dapper的术语。
Span
代表了一组基本工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(Span Id)来标记它的开始、具体过程和结束。通过Span Id的开始和结束时间戳,就能统计该span的调用时间,除此之外,我们还可以获取如事件的名称,请求信息等元数据。
Trace
由一组Trace Id相同的Span串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即Trace Id),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。
Annotation/Event
用它记录一个完成请求的4个事件,内部使用的重要注释。
cs:Client Sent。客户端已经发出了一个请求。描述的是一个Span的开始。
sr:Server Received。服务器端收到请求并开始处理。从这个时间戳中减去
cs
时间戳可以显示网络延迟(sr-cs = 网络延迟,即服务调用的时间)。ss:Server Sent。服务端处理完毕,当响应被发送回客户端时。从这个时间戳中减去
sr
时间戳可以揭示服务器端处理请求所需的时间(ss - sr = 服务器上的请求处理时间)。cr:Client Reveived。客户端已成功收到服务器端的响应,标志着请求结束。从该时间戳中减去
cs
时间戳,即可显示客户端从服务器接收响应所需的全部时间(cr - cs = 请求的总时间)。
下图显示了Span和Trace在系统中的样子:

上图中的每一种颜色都表示一个Span(从A到G有七个Span)。考虑以下注意事项:
此注释表明,当前跨度将Trace Id设置为X,Span Id设置为D。此外,从RPC的角度来看,发生了Client Sent
事件。
让我们考虑更多的注意事项:
您可以继续使用已创建的Span(例如,no custom span
指示),也可以手动创建子Span(例如,custom span
指示)。下图显示了Span的亲子关系:

2.3 Spring Cloud Sleuth特点
Spring Cloud Sleuth有以下几个特点。

03 Zipkin概述
3.1 Zipkin介绍
Spring Cloud Sleuth对于分布式链路的跟踪仅仅是生成一些数据,这些数据不便于人类阅读,因此我们一般把这种跟踪数据上传到Zipkin Server,由Zipkin通过UI页面统一进行数据的展示。那什么是Zipkin呢?Zipkin是Twitter的一个开源项目,它基于Google Dapper实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储展现、查找和我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源,除了面向开发的API接口之外,它也提供了方便的UI组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。
Zipkin提供了可插拔数据存储方式:In-Memory、MySQL、Cassandra以及Elasticsearch。

上图展示了Zipkin的基础架构,它主要由4个核心组件构成:
Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin内部处理的Span格式,以支持后续的存储、分析、展示等功能。
Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。
RestFul API:API组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。
Web UI:UI组件,基于API组件实现的上层应用。通过UI组件用户可以方便而又直观地查询和分析跟踪信息。
Zipkin分为两端,一个是Zipkin服务端,一个是Zipkin客户端,介绍见下:
Zipkin客户端:指微服务应用,客户端会配置服务端的URL地址,一旦发生服务间的调用的时候,会被配置在微服务里面的Sleuth的监听器监听,并生成相应的Trace和Span信息发送给服务端,发送的方式主要有两种,一种是HTTP报文的方式,还有一种是消息总线的方式如RabbitMQ。
Zipkin服务端:服务端负责将接收到的消息根据Trace Id和Span Id整理成一个完整的Request时序链路,并通过Web页面直观的展示出来。
3.2 Zipkin服务端安装
Zipkin的服务端(Zipkin Server),在使用Spring Boot 2.x版本后,官方就不推荐自行定制编译了,反而是直接提供了编译好的jar包来给我们使用。
1.下载Zipkin的jar包。访问ZipKin官网https://zipkin.io/pages/quickstart.html,点击【latest release】链接进行下载。

2.进入命令行终端,输入下面的命令启动Zipkin Server服务。
3.启动Zipkin Server服务成功后,命令行终端输出如下的日志信息。

4.通过浏览器访问http://127.0.0.1:9411地址,打开Zipkin Dashboard控制面板。

04 Sleuth链路追踪搭建
1.在micro-service-cloud-seata-storage-8006、micro-service-cloud-seata-account-8007和micro-service-cloud-seata-order-8008三个项目的pom.xml文件中分别都添加sleuth和sleuth-zipkin依赖。
说明:spring-cloud-starter-zipkin的最新版本是2.2.8.RELEASE,之后就没有更新了。较新版本的Spring Cloud已经不再支持spring-cloud-starter-zipkin依赖,取而代之的是spring-cloud-sleuth-zipkin依赖。
2.在micro-service-cloud-seata-storage-8006、micro-service-cloud-seata-account-8007和micro-service-cloud-seata-order-8008三个项目的application.yml文件中分别都添加sleuth和zipkin的配置,具体的配置在spring节点下添加如下子节点信息。
属性spring.zipkin.sender.type=web的含义是通过HTTP的方式发送数据到Zipkin Server,如果请求量比较大,这种方式其实性能是比较低的,一般情况下我们都是通过消息中间件来发送,比如RabbitMQ;这种方式就是让服务将Sleuth收集的日志推给MQ,让Zipkin去监控MQ的信息,通过MQ的队列获取到服务的信息,这样就提高了性能。如果日志数据量比较大,一般推荐拥有更高吞吐量的Kafka来进行日志推送。而日志的存储则可以采用Elasticsearch对数据进行持久化,这样可以保证Zipkin重启后,链路信息不会丢失。这种解决方案在本章节中仅作了解,具体实现不在这里展开介绍。
说明:关于Sleuth的其他相关配置属性,可查看官网:https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/appendix.html#appendix。
3.启动micro-service-cloud-seata-storage-8006、micro-service-cloud-seata-account-8007和micro-service-cloud-seata-order-8008三个微服务项目,使用ApiPost工具访问http://127.0.0.1:8008/order/create/1/1/10/200地址,产生链路信息。
4.如果在启动以上三个微服务项目时,提示如下错误,原因是把base-url的值声明成了http://127.0.0.1:9411,改写成http://localhost:9411即可解决该问题。如果没有以下的异常信息,则忽略此步骤。
5.使用浏览器访问http://127.0.0.1:9411网页,在【找到一个痕迹】选项下点击【RUN QUERY】按钮,查找请求信息,结果见下。

6.点击【micro-service-cloud-seata-order-8008: get /order/create/{userid}/{productid}/{count}/{money}】这条记录后的【SHOW】按钮,可以查阅一次访问的详细线路。结果见下。

7.也可以点击上图又上角的【SPAN TABLE】选项,以表格的形式展示Span的详情信息,结果见下。

8.在Zipkin主页选择【依赖】选项,然后可以根据时间段查询运行的服务信息,选择“开始时间”和“终止时间”段,然后点击【RUN QUERY】选项查询运行的服务。结果见下。

9.使用鼠标点击下图中的任意一个服务,在控制台的右侧将展示该服务的使用情况。

10.使用ApiPost工具访问http://127.0.0.1:8008/order/create/1/1/10/2000接口,提交的2000超出账户的可用总金额,因此后端业务代码会报错。再次进入到Zipkin。

05 Zipkin数据持久化
Zipkin Server默认会将追踪数据信息保存到内存,但这种方式不适合生产环境,一旦Zipkin Server关闭重启或者服务崩溃,就会导致历史数据消失。Zipkin支持修改存储策略使用其他存储组件,支持MySQL数据库、Cassandra(Cassandra是一套开源分布式NoSQL数据库系统)和Elasticsearch(Elasticsearch是一个分布式、高扩展、高实时的搜索与数据分析引擎)等。
1.在MySQL数据库中,新建一个名为zipkin
的数据库实例,并选中该数据库。
2.并通过以下SQL语句在zipkin
子库中创建3张表:zipkin_spans表、zipkin_annotations表和zipkin_dependencies表。
说明:Zipkin数据持久化的建表语句由Zipkin官方提供,通过访问Github的https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql地址来获取数据库脚本。
3.先关闭Zipkin服务,重新进入命令行终端,输入以下命令来启动Zipkin Server服务,同时在启动ZipKin Server服务的时候,指定数据保存的MySQL的信息。
通过命令启动Zipkin Server服务的参数说明:

4.启动Zipkin Server服务成功后,命令行终端输出如下的日志信息。

5.先使用ApiPost工具访问http://127.0.0.1:8008/order/create/1/1/10/200接口产生一个请求,然后查看zipkin中的zipkin_annotations表,发现已经将链路追踪信息存放到MySQL数据库中。

6.再次打开访问Zipkin的UI界面,链路信息将不会消失。至此,我们便完成了Zipkin数据持久化到MySQL数据库中的操作。

今天的内容,你学会了吗?关注「袁庭新」,干货天天都不断!
