Spring Cloud进阶之路 | 十三:服务链路追踪(Spring Cloud Sleuth)

转载请注明作者及出处:

作者:银河架构师

原文链接:https://www.cnblogs.com/luas/p/12201668.html

​前言

微服务架构同时也是分布式架构,按业务划分服务单元,往往划分很多个小服务单元。由于服务单元数量众多,同时也可能会集群部署,一个请求可能需要调用多个服务,如果链路上任何一个服务出现问题或者网络超时,都会导致整个调用失败。

随着业务的不断扩张,服务之间的调用会越来越复杂,而服务调用的复杂度,也决定了问题定位的难度,以至于一旦出现错误,便极难定位。

随着业务不断扩张,服务也越来越多,调用链分析也会随之越来越复杂。它们之间的调用关系也许如下:

所以,在微服务架构中,必须实现分布式链路追踪,来记录一个请求到底有哪些服务参与,顺序又是怎样,达到每个请求的细节都清晰可见,出了问题,快速定位。

Google开源了Dapper链路追踪组件,并在2010年发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇文章是业内实现链路追踪的标杆和理论基础,具有非常大的参考价值。

目前,链路追踪组件有Google的Dapper,Twitter 的Zipkin,以及阿里的Eagleeye (鹰眼)等,都是非常优秀的链路追踪开源组件。

其中,Twitter的Zipkin是基于google的分布式监控系统Dapper(论文)的开源实现,zipkin用于追踪分布式服务之间的应用数据链路,分析处理延时,帮助我们改进系统的性能和定位故障。

Dapper术语

Span

基本工作单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span通过一个64位ID唯一标识,trace以另一个64位ID表示,span还有其他数据信息,比如摘要、时间戳事件、关键值注释(tags)、span的ID、以及进度ID(通常是IP地址) 。

span在不断的启动和停止,同时记录了时间信息,当你创建了一个span,你必须在未来的某个时刻停止它。

Trace

一系列spans组成的一个树状结构,例如,如果正在运行一个分布式大数据工程,一个PUT类型的请求就会形成一个trace。

Annotation

用于及时记录事件的存在。依托于于Brave的设计,我们不再需要为Zipkin设置特殊事件来了解客户端和服务器是谁,请求在哪里开始以及在哪里结束。但是,出于学习目的,我们标记这些事件以突出显示发生了哪种操作。

    • cs:Client Sent -客户端发起一个请求,这个annotion描述了这个span的开始

    • sr:Server Received -服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟

    • ss:Server Sent -注解表明请求处理的完成(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要的处理请求时间

    • cr:Client Received -表明span的结束,客户端成功接收到服务端的回复,如果cr减去cs时间戳便可得到客户端从服务端获取回复的所有所需时间 

下图显示了SpanTrace以及Zipkin Annotation在系统中的样子:

每种颜色的记录表示一个Span(有七个spans-从AG)。请看以下记录:

Trace Id = X
Span Id = D
Client Sent

该记录表明,当前span Trace Id设定为XSpan Id设置为D,同时,Client Sent事件发生了。

下图显示了Span的父子关系:

Brave

Brave is a distributed tracing instrumentation library. Brave typically intercepts production requests to gather timing data, correlate and propagate trace contexts. While typically trace data is sent to Zipkin server, third-party plugins are available to send to alternate services such as Amazon X-Ray.

Brave 是用来装备Java程序的类库,提供了面向标准Servlet、Spring MVC、Http Client、JAX RS、Jersey、Resteasy 和 MySQL 等接口的装备能力,通过编写简单的配置和代码,让基于这些框架构建的应用可以向 Zipkin 报告数据。同时 Brave 也提供了非常简单且标准化的接口,在以上封装无法满足要求的时候可以方便扩展与定制。

从2.0.0版本开始,Spring Cloud Sleuth使用Brave作为追踪库。由此,Sleuth不再负责存储上下文,而是将工作委托给Brave。

由于Sleuth与Brave具有不同的命名和标记约定,因此我们决定从现在开始遵循Brave的约定。但是,如果要使用传统的Sleuth方法,可以将spring.sleuth.http.legacy.enabled属性设置为true。

Zipkin

何为Zipkin

官方介绍

Zipkin is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures. Features include both the collection and lookup of this data.

If you have a trace ID in a log file, you can jump directly to it. Otherwise, you can query based on attributes such as service, operation name, tags and duration. Some interesting data will be summarized for you, such as the percentage of time spent in a service, and whether or not operations failed.

Zipkin是一种分布式追踪系统。它有助于收集解决服务体系结构中的延迟问题所需的计时数据。其功能包括收集和查找此数据。

如果日志文件中有追踪ID,则可以直接跳转到该文件。否则,你可以根据服务,操作名称,标签和持续时间等属性进行查询。将为您总结一些有趣的数据,例如在服务中花费的时间占比,以及操作是否失败等。

为何Zipkin

正如前文所述,随着业务越来越复杂,系统也随之进行各种拆分。

特别是随着微服务架构和容器技术的兴起,看似简单的一个应用,后台可能有几十个甚至几百个服务在支撑。一个请求可能需要多次服务调用才能完成。

当请求变慢、出错、或不可用时,我们无法得知是具体原因。而问题的关键就取决于如何快速定位服务故障点,Zipkin分布式追踪系统便能很好的解决这样的问题。

原理

针对服务化应用链路追踪的问题,Google发表了Dapper论文,介绍了如何进行服务追踪分析。其核心思想便是在服务调用的请求和响应中加入标识ID,以此标明上下游请求关系。利用这些信息,便可以可视化地分析并展示服务调用链路和服务间的依赖关系。

Zipkin便是基于Dpper的开源实现,且支持多种语言,包括JavaScript,Python,Java, Scala, Ruby, C#, Go等。其中Java由多种不同的库来支持。

Spring Cloud Sleuth便是对Zipkin的再次封装,对于Span、Trace等信息的生成、HTTP Request接入,向Zipkin Server发送采集信息等全部自动完成。

Spring Cloud Sleuth

Spring Cloud Sleuth是用于Spring Cloud的分布式追踪工具,它借鉴了Dapper,Zipkin和HTrace,为Spring Cloud实现了分布式追踪解决方案。

术语

参考Dapper术语,Spring Cloud Sleuth借鉴了Dapper的术语。

Spring Cloud Zipkin

Spring Cloud Sleuth基于Zipkin的适配,自动采集数据,并通过HTTP,自动将追踪数据发送到Zipkin。

引用Spring Cloud Zipkin后,将自动引入Spring Cloud Sleuth。

由于Spring Cloud Sleuth原生实现略显复杂,化繁为简,本文也将基于Spring Cloud Zipkin,来介绍如何将应用与Zipkin快速连接起来。

准备工作

复用前一篇文章Spring Cloud进阶之路 | 十二:断路器聚合监控(Turbine)中的工程xmall-product。

改造商品工程

依赖改造

添加spring-cloud-starter-zipkin依赖,修改后的pom文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion><parent>
    <groupId>com.luas.cloud</groupId>
    <artifactId>java-boot-parent-2.1</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <relativePath>../../java-boot-parent-2.1</relativePath>
  </parent><groupId>com.luas.cloud</groupId>
  <artifactId>xmall-product</artifactId>
  <version>1.0.0-SNAPSHOT</version><name>xmall-product</name>
  <description>Spring Cloud Learning,nacos-client</description><dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency><!-- nacos cloud -->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency><dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency><dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency><dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies><build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build></project>

配置改造

修改application.yml,添加zipkin server地址及sleuth.samplerprobability

server:
  port: 8080
​
​
spring:
  zipkin:
    base-url: http://localhost:9411/
  sleuth:
    sampler:
      probability: 1.0

注意,如果sleuth.samplerprobability概率过低,将会导致数据不会上报至zipkin,进而zipkin server看不到任何信息

创建订单工程

创建订单工程,其中订单信息接口调用商品信息接口,形成服务内部调用逻辑。

pom

完整的pom文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion><parent>
        <groupId>com.luas.cloud</groupId>
        <artifactId>java-boot-parent-2.1</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../../java-boot-parent-2.1</relativePath>
    </parent><groupId>com.luas.xmall</groupId>
    <artifactId>xmall-order</artifactId>
    <version>0.0.1-SNAPSHOT</version><name>xmall-order</name>
    <description>xmall order</description><properties>
        <java.version>1.8</java.version>
    </properties><dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency><dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency><dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency><!-- nacos cloud -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency><dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency><dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency><dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies><build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build></project>

创建SkuService

创建feign client SkuService,远程调用xmall-product商品接口。

package com.luas.xmall.order.clients.product;
​
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
​
@FeignClient(name = "xmall-product", fallback = SkuFallbackService.class)
public interface SkuService {
​
    @RequestMapping(value = "/sku/{skuId}", method = RequestMethod.GET)
    Object info(@PathVariable("skuId") String skuId);
​
}

配置

application.yml配置如下。注意,feign开启hystrix

server:
  port: 8084
​
feign:
  hystrix:
    enabled: true
​
spring:
  zipkin:
    base-url: http://localhost:9411/
  sleuth:
    sampler:
      probability: 1.0

启动类

启动类添加@EnableFeignClients注解,激活feign客户端。

package com.luas.xmall.order;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.openfeign.EnableFeignClients;
​
@EnableCircuitBreaker
@EnableFeignClients
@SpringBootApplication
public class XmallOrderApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(XmallOrderApplication.class, args);
    }
​
}

Zipkin Server

Spring Cloud从F版本开始,已经无需开发者自行构建Zipkin Server了,只需下载jar运行即可。下载地址为:

https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/。

下载完成之后,运行:

java -jar zipkin-server-2.11.12-exec.jar

访问zipkin server http://localhost:9411,此时尚无任何信息。

链路追踪

依次启动xmall-product,xmall-order,端口分别为8080,8084。

访问订单接口http://localhost:8084/order/888888,展示远程调用xmall-product商品接口后的商品信息及订单信息。

再次查看Zipkin Server,已有追踪数据。

点击spans行,可查看其详细信息。

点击接口行,可查看该接口调用详细信息。

order接口调用信息:

sku接口调用信息:

另外,查看接口调用信息中的traceId、spanId,再分别查看工程控制台,可发现这些ID同样也输出到了控制台,甚至日志中。

服务依赖

点击Zipkin Server监控界面上方“依赖/Dependency”按钮,可查看服务依赖关系。

依赖关系如下:

点击可查看详情。

点击服务名,还可查看详细调用信息,如调用次数、错误次数。


调用异常

去掉feign 客户端SkuService中的fallback声明,关闭feign hystrix,并停止xmall-product服务,再次调用订单接口http://localhost:8084/order/888888,查看Zipkin Server。

查看其详细信息。

查看接口调用详细信息。


错误信息一目了然,注册中心找不到xmall-product服务导致调用失败。

熔断降级

取消feign客户端SkuService中的fallback声明,开启feign hystrix。注意,此时xmall-product服务依然是停止状态。再次访问订单接口http://localhost:8084/order/888888。

查看Zipkin Server。

查看其详细信息。

能明显看到,调用中存在hystrix字样,表明触发了降级策略。

查看接口调用详细信息。

同样的,也能看到注册中心找不到xmall-product服务导致调用失败。只不过,比之前面一种情况,多了降级策略,能快速执行失败策略,这一点,在图中也能明确看到,响应时间以μs记

源码

github

https://github.com/liuminglei/SpringCloudLearning/tree/master/13/

gitee

https://gitee.com/xbd521/SpringCloudLearning/tree/master/13/

微信搜索【银河架构师】,发现更多精彩内容。

猜你喜欢

转载自www.cnblogs.com/luas/p/12201668.html