在上一篇 Spring Cloud 接入 EDAS 之服务发现篇 中已经讲解了如何接入 EDAS 的服务注册中心。在这一篇中,我们将聊聊全链路跟踪。
全链路跟踪的必要性
微服务框架带来的好处已经无需多言,模块化,解耦,提高了开发的效率,服务具备更好的扩展性等等。但是微服务其实是一把双刃剑,微服务同时也带来了一些问题。
随着业务的拆分越来越细,模块越来越多,一个看似简单的业务动作,很可能跨越了几十个系统,调用链非常复杂。
基于微服务体系之下构建的业务系统存在的问题基本上分为四类。
- 故障定位难
即使是一个简单的下单的动作,用户在页面上点购买按钮,其实它背后是由十几个甚至数十个的微服务去共同完成的,这十几个甚至几十个微服务也由不同的团队去负责,这是微服务的过度协同带来的结果,一旦出现问题,最坏情况下我们也许就要拉上十几个团队一起来看问题。
- 容量预估难
当遇到大促活动时,在以前的单体应用系统当中做容量预估是非常容易的,因为我们大促时候按照预估的流量与当前系统的单机压测容量做一个对比,把所有的系统按比例去扩容就可以了。而在微服务的大促场景下,每一个系统在核心链路当中的参与度、重要性都是不一样的,我们并不能对每一个系统做等比例的扩容,所以微服务架构下的容量预估也是一件难事。
- 资源浪费多
资源浪费多首先是容量预估不准的一个后果,同时资源浪费多背后隐含的另一个问题就是性能优化难,为什么这么说呢?我们当打开一个页面发现它慢的时候,我根本不知道这个页面慢在哪里,瓶颈在哪里,怎么去优化,这些问题累积下来,资源的浪费也成为了一个巨大的问题。
- 链路梳理难
一个新人加入公司的时候,老板让他负责一个系统,他在这个复杂的微服务体系中,就像人第一次在没有地图没有导航的情况下来到一个大城市一样,根本不知道自己身在何处。应用负责人不知道自己的系统被谁依赖了,也不知道自己的系统下游会影响其他哪些人。
EagleEye
EagleEye 就是为了解决上述问题而生的。
EagleEye 简介
EagleEye 是阿里巴巴的分布式追踪系统,基于 Google 的分布式调用跟踪系统 Dapper 实现。
EagleEye 日均处理万亿级别的分布式调用链数据,通过收集和分析在不同的网络调用中进行日志埋点,可以得到同一次请求上的各个系统的调用链关系,有助于梳理应用的请求入口与服务的调用来源、依赖关系,同时,也对分析系统调用瓶颈、估算链路容量、快速定位异常有很大帮助。
EagleEye 如何接入
Spring Cloud 应用接入 EagleEye 很简单,如果你已经使用了 上文 中提到了 EDAS 注册中心,则只需要添加如下依赖即可自动接入 EagleEye。
目前 EDAS 的 EagleEye 已经支持自动对 RestTemplate、AsyncRestTemplate、FeignClient 调用的请求自动进行跟踪。后续我们将接入更多的组件的自动埋点。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eagleeye</artifactId>
<version>1.1</version>
</dependency>
如果你只是想单纯地使用 EagleEye 的功能,同样没问题,除了基本的 Spring Cloud 所需的依赖外,还需要在 pom.xml 文件中加入如下公共配置。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eagleeye</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-pandora</artifactId>
<version>1.2</version>
</dependency>
<build>
<plugins>
<plugin>
<groupId>com.taobao.pandora</groupId>
<artifactId>pandora-boot-maven-plugin</artifactId>
<version>2.1.7.8</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
还需要在 main 函数中加入两行代码,加入后的代码如下图所示
public static void main(String[] args) {
PandoraBootstrap.run(args);
SpringApplication.run(ServerApplication.class, args);
PandoraBootstrap.markStartupAndWait();
}
当然,建议还是全套使用 EDAS 的配套功能,这样才能形成合力,发挥最大的作用。
加入如上依赖后,无需搭建任何采集分析系统,开箱即可使用 EDAS 的全链路跟踪功能。
注意 由于目前 spring cloud for aliware 尚未进入中央仓库,需要配置 maven 的私服地址,配置详情参考 私服配置
Demo
源码
为了演示 EagleEye 的功能,我们在这里编写了两个 Demo 应用,通过模拟他们的互相调用,分别模拟了正常调用,延迟较大和异常出错的场景。
分别将这两个应用部署到 EDAS 后,我们通过调用 Service1 的几个方法来演示 EagleEye 的使用。
我们分别调用这些方法 /rest/ok 、 rest/delay 、 /rest/ok ,它们分别对应了正常调用,延迟较大调用,异常出错的场景。
使用 EagleEye 的查看调用链功能,可以看到如下的信息。
正常的调用链详情
正常调用的场景,从图中可以看出服务经过了这么几次调用,并且可以看到 step1、step2、step3 的耗时分别是 2ms、1ms、0ms。
延迟较大的调用链详情
延迟较大的场景,从图中可以看到 delay1、delay2、delay3 的耗时分别是 453ms、353ms、151ms,
将鼠标停留在 delay3 这个调用段,还可以看到更多详细的调用链的信息。其中服务端处理请求花费了 150ms,客户端在服务端处理完请求后的 1ms 收到了响应。
异常出错的调用链详情
从图中我们可以很清晰地看到,出错的请求为 /rest/error3 ,极大地方便了我们对问题进行定位。
关于 EagleEye 更详细的使用方式,参考文档 服务监控
其他客户端的演示
同时,我们也在 /echo-rest/{str} 、 /echo-async-rest/{str} 、 /echo-feign/{str} 这三个 URI 中,分别演示了 EagleEye 对 RestTemplate、 AsyncRestTemplate 、 FeignClient 的自动埋点支持,您可以在调用后,通过 服务监控 页面查看着这三者的调用链信息。
Sleuth
我们都知道 Spring Cloud 提供了原生的链路跟踪解决方案 Sleuth ,使用起来也不复杂。
日志埋点
在 Spring Cloud 工程中接入 Sleuth 埋点功能,首先需要在 pom.xml 中加入如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
这里只是完成了日志埋点的第一步,接下来就是日志分析了。
启动 Zipkin
日志分析使用的是 zipkin,所以需要部署一下 zipkin ,最方便的方式就是使用 docker 的方式启动,参照 官方文档
埋点日志采集
启动 zipkin 后,只剩下最后一步:将业务服务的机器上埋点日志,通过某种方式将数据传送到 zipkin 。目前支持基于 HTTP 请求传送及通过消息队列传送的方式。
http方式
基于 http 协议,加入如下依赖和配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
spring.zipkin.baseUrl=http://${zipkin-server-ip}:${zipkin-server-port}
zipkin 的组件将会在请求结束之后,异步地将埋点的日志信息以 http 的方式传送给 zipkin。
虽然是异步的,但是性能消耗还是比较大,更好的方式就是通过消息队列传送了。
消息队列方式
基于消息队列传送,这里以 kafka 为例子,业务服务端需要加入如下依赖和配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
spring.sleuth.sampler.percentage=1.0
spring.cloud.stream.kafka.binder.brokers=192.168.0.2:9092,192.168.0.3:9092
spring.cloud.stream.kafka.binder.zkNodes=192.168.0.2:2181,192.168.0.3:2181
基于消息队列传送,这里以 kafka 为例子,zipkin 服务端需要加入如下依赖和配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
spring.sleuth.enabled=false
spring.sleuth.sampler.percentage=1.0
spring.cloud.stream.kafka.binder.brokers=192.168.0.2:9092,192.168.0.3:9092
spring.cloud.stream.kafka.binder.zkNodes=192.168.0.2:2181,192.168.0.3:2181
这里的 brokers 和 zkNodes 地址和端口是随手写的,实际使用中,还需要更换成自身搭建的kafka和zk的地址。
其他依赖
当使用消息队列时,kafka 这类消息队列也需要自己搭建。
zipkin 默认将数据存储在内存中。实际使用中,为了达到数据持久化和提升查找效率的目的,还需要配置数据库存储和 ElasticSearch 等。
Sleuth VS EagleEye
EDAS EagleEye 的开箱即用的特点,简单可靠,省去了您自身搭建日志分析服务、消息队列、存储等维护的成本,提升了您的开发效率。
不建议同时使用 Sleuth 和 EagleEye ,虽然目前版本我们做了一定的兼容,但是不保证后续版本会兼容。而且多个链路跟踪的存在,容易引起性能上损耗,影响服务性能及稳定性。
两者其实都是基于 Google 的分布式调用跟踪系统 Dapper 实现,EagleEye 会提供 Sleuth 所涵盖的功能的支持。同时,结合阿里内部的 EagleEye 分析系统 以及 业务实时监控服务 ARMS 等系统,还可对服务进行全息排查,全方位实时监控您的业务。