微服务调用链追踪中心搭建

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

封面图片


概述

一个完整的微服务系统包含多个微服务单元,各个微服务子系统存在互相调用的情况,形成一个 调用链。一个客户端请求从发出到被响应 经历了哪些组件哪些微服务请求总时长每个组件所花时长 等信息我们有必要了解和收集,以帮助我们定位性能瓶颈、进行性能调优,因此监控整个微服务架构的调用链十分有必要,本文将阐述如何使用 Zipkin 搭建微服务调用链追踪中心。


Zipkin初摸

正如 Ziplin官网 所描述,Zipkin是一款分布式的追踪系统,其可以帮助我们收集微服务架构中用于解决延时问题的时序数据,更直白地讲就是可以帮我们追踪调用的轨迹。

Zipkin的设计架构如下图所示:

Zipkin设计架构

要理解这张图,需要了解一下Zipkin的几个核心概念:

  • Reporter

在某个应用中安插的用于发送数据给Zipkin的组件称为Report,目的就是用于追踪数据收集

  • Span

微服务中调用一个组件时,从发出请求开始到被响应的过程会持续一段时间,将这段跨度称为Span

  • Trace

从Client发出请求到完成请求处理,中间会经历一个调用链,将这一个整个过程称为一个追踪(Trace)。一个Trace可能包含多个Span,反之每个Span都有一个上级的Trace。

  • Transport

一种数据传输的方式,比如最简单的HTTP方式,当然在高并发时可以换成Kafka等消息队列


看了一下基本概念后,再结合上面的架构图,可以试着理解一下,只有装配有Report组件的Client才能通过Transport来向Zipkin发送追踪数据。追踪数据由Collector收集器进行手机然后持久化到Storage之中。最后需要数据的一方,可以通过UI界面调用API接口,从而最终取到Storage中的数据。可见整体流程不复杂。

Zipkin官网给出了各种常见语言支持的OpenZipkin libraries:

OpenZipkin libraries

本文接下来将 构造微服务追踪的实验场景 并使用 Brave 来辅助完成微服务调用链追踪中心搭建!


部署Zipkin服务

利用Docker来部署Zipkin服务再简单不过了:

docker run -d -p 9411:9411 \
--name zipkin \
docker.io/openzipkin/zipkin

完成之后浏览器打开:localhost:9411可以看到Zipkin的可视化界面:

Zipkin可视化界面


模拟微服务调用链

我们来构造一个如下图所示的调用链:

微服务调用链

图中包含 一个客户端 + 三个微服务

  • Client:使用/servicea接口消费ServiceA提供的服务
  • ServiceA:使用/serviceb接口消费ServiceB提供的服务,端口8881
  • ServiceB:使用/servicec接口消费ServiceC提供的服务,端口8882
  • ServiceC:提供终极服务,端口8883

为了模拟明显的延时效果,准备在每个接口的响应中用代码加入3s的延时。

简单起见,我们用SpringBt来实现三个微服务。

ServiceA的控制器代码如下:

@RestController
public class ServiceAContorller {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/servicea”)
    public String servicea() {
        try {
            Thread.sleep( 3000 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return restTemplate.getForObject("http://localhost:8882/serviceb", String.class);
    }
}

ServiceB的代码如下:

@RestController
public class ServiceBContorller {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/serviceb”)
    public String serviceb() {
        try {
            Thread.sleep( 3000 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return restTemplate.getForObject("http://localhost:8883/servicec", String.class);
    }
}

ServiceC的代码如下:

@RestController
public class ServiceCContorller {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/servicec”)
    public String servicec() {
        try {
            Thread.sleep( 3000 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Now, we reach the terminal call: servicec !”;
    }
}

我们将三个微服务都启动起来,然后浏览器中输入localhost:8881/servicea来发出请求,过了9s之后,将取到ServiceC中提供的微服务接口所返回的内容,如下图所示:

微服务链式调用结果

很明显,调用链可以正常work了!

那么接下来我们就要引入Zipkin来追踪这个调用链的信息!

编写与Zipkin通信的工具组件

从Zipkin官网我们可以知道,借助OpenZipkin库Brave,我们可以开发一个封装Brave的公共组件,让其能十分方便地嵌入到ServiceA,ServiceB,ServiceC服务之中,完成与Zipkin的通信。

为此我们需要建立一个新的基于Maven的Java项目:ZipkinTool

  • pom.xml中加入如下依赖:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hansonwang99</groupId>
    <artifactId>ZipkinTool</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <version>2.0.1.RELEASE</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.7.RELEASE</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-spring-web-servlet-interceptor</artifactId>
            <version>4.0.6</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-spring-resttemplate-interceptors</artifactId>
            <version>4.0.6</version>
        </dependency>
        <dependency>
            <groupId>io.zipkin.reporter</groupId>
            <artifactId>zipkin-sender-okhttp3</artifactId>
            <version>0.6.12</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>
  • 编写ZipkinProperties类

其包含endpoint和service两个属性,我们最后是需要将该两个参数提供给ServiceA、ServiceB、ServiceC微服务作为其application.properties中的Zipkin配置

@Data
@Component
@ConfigurationProperties("zipkin")
public class ZipkinProperties {
    private String endpoint;
    private String service;
}

用了lombok之后,这个类异常简单!

【注意:关于lombok的用法,可以看这里

  • 编写ZipkinConfiguration类

这个类很重要,在里面我们将Brave的BraveClientHttpRequestInterceptor拦截器注册到RestTemplate的拦截器调用链中来收集请求数据到Zipkin中;同时还将Brave的ServletHandlerInterceptor拦截器注册到调用链中来收集响应数据到Zipkin中

上代码吧:

@Configuration
@Import({RestTemplate.class, BraveClientHttpRequestInterceptor.class, ServletHandlerInterceptor.class})
public class ZipkinConfiguration extends WebMvcConfigurerAdapter {

    @Autowired
    private ZipkinProperties zipkinProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private BraveClientHttpRequestInterceptor clientInterceptor;

    @Autowired
    private ServletHandlerInterceptor serverInterceptor;

    @Bean
    public Sender sender() {
        return OkHttpSender.create( zipkinProperties.getEndpoint() );
    }

    @Bean
    public Reporter<Span> reporter() {
        return AsyncReporter.builder(sender()).build();
    }

    @Bean
    public Brave brave() {
        return new Brave.Builder(zipkinProperties.getService()).reporter(reporter()).build();
    }

    @Bean
    public SpanNameProvider spanNameProvider() {
        return new SpanNameProvider() {
            @Override
            public String spanName(HttpRequest httpRequest) {
                return String.format(
                        "%s %s",
                        httpRequest.getHttpMethod(),
                        httpRequest.getUri().getPath()
                );
            }
        };
    }

    @PostConstruct
    public void init() {
        List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
        interceptors.add(clientInterceptor);
        restTemplate.setInterceptors(interceptors);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(serverInterceptor);
    }
}

ZipkinTool完成以后,我们需要在ServiceA、ServiceB、ServiceC三个SpringBt项目的application.properties中加入Zipkin的配置:

以ServiceA为例:

server.port=8881
zipkin.endpoint=http://你Zipkin服务所在机器的IP:9411/api/v1/spans
zipkin.service=servicea

我们最后依次启动ServiceA、ServiceB、和ServiceC三个微服务,并开始实验来收集链路追踪数据 !


 实际实验

1. 依赖分析

浏览器打开Zipkin的UI界面,可以查看 依赖分析

点击依赖分析

图中十分清晰地展示了ServiceA、ServiceB和ServiceC三个服务之间的调用关系!
注意,该图可缩放,并且每一个元素均可以点击,例如点击 ServiceB这个微服务,可以看到其调用链的上下游!

点击ServiceB微服务


2. 查找调用链

接下来我们看一下调用链相关,点击 服务名,可以看到Zipkin监控到个所有服务:

查找调用链

同时可以查看Span,如以ServiceA为例,其所有REST接口都再下拉列表中:

查看Span

以ServiceA为例,点击 Find Traces,可以看到其所有追踪信息:

Find Traces

点击某个具体Trace,还能看到详细的每个Span的信息,如下图中,可以看到 A → B → C 调用过程中每个REST接口的详细时间戳:

某一个具体Trace

点击某一个REST接口进去还能看到更详细的信息,如查看/servicec这个REST接口,可以看到从发送请求到收到响应信息的所有详细步骤:

某一个具体Span详细信息

后记

作者更多的原创文章:在云栖社区

作者一些其他容器化应用方面的文章:

目录
相关文章
|
存储 监控 关系型数据库
《吃透微服务》- 服务追踪之Sleuth
本文主要介绍 SpringCloud中动态链路追踪
175 0
|
存储 消息中间件 数据可视化
微服务架构 | 10.3 使用 Zipkin 可视化日志追踪
Zipkin 允许开发人员以图形方式查看事务占用的时间量,并分解在调用中涉及的每个微服务所用的时间。在微服务架构中,Zipkin 是识别性能问题的宝贵工具;
962 0
微服务架构 | 10.3 使用 Zipkin 可视化日志追踪
|
数据可视化 Java 微服务
微服务架构 | 10.1 使用 Sleuth 追踪服务调用链
Spring Cloud Sleuth 是一个 Spring Cloud 项目,它将关联 ID 装备到 HTTP 调用上,并将生成的跟踪数据提供给 OpenZipkin 的钩子。Spring Cloud Sleuth 通过添加过滤器并与其他 Spring 组件进行交互,将生成的关联 ID 传递到所有系统调用;
191 0
微服务架构 | 10.1 使用 Sleuth 追踪服务调用链
|
数据可视化 搜索推荐 Java
微服务架构 | 10. 分布式追踪
微服务的调试问题会比较复杂,可以使用分布式追踪解决;
214 1
微服务架构 | 10. 分布式追踪
|
开发框架 监控 Java
ASP.NET Core微服务之基于Steeltoe使用Zipkin实现分布式追踪
本文简单地介绍了一下Spring Cloud Seluth与Zipkin,然后通过Java快速地构建了一个Zipkin Server,通过在ASP.NET Core中集成Zipkin并做了一个基本的微服务调用追踪Demo。
1970 0
ASP.NET Core微服务之基于Ocelot+Butterfly实现分布式追踪
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一、什么是Tracing?   微服务的特点决定了功能模块的部署是分布式的,以往在单应用环境下,所有的业务都在同一个服务器上,如果服务器出现错误和异常,我们只要盯住一个点,就可以快速定位和处理问题,但是在微服务的架构下,大部分功能模块都...
2315 0
|
7天前
|
敏捷开发 监控 数据管理
构建高效微服务架构的五大关键策略
【4月更文挑战第20天】在当今软件开发领域,微服务架构已经成为一种流行的设计模式,它允许开发团队以灵活、可扩展的方式构建应用程序。本文将探讨构建高效微服务架构的五大关键策略,包括服务划分、通信机制、数据管理、安全性考虑以及监控与日志。这些策略对于确保系统的可靠性、可维护性和性能至关重要。
|
7天前
|
消息中间件 监控 持续交付
构建高效微服务架构:后端开发的进阶之路
【4月更文挑战第20天】 随着现代软件开发的复杂性日益增加,传统的单体应用已难以满足快速迭代和灵活部署的需求。微服务架构作为一种新兴的分布式系统设计方式,以其独立部署、易于扩展和维护的特点,成为解决这一问题的关键。本文将深入探讨微服务的核心概念、设计原则以及在后端开发实践中如何构建一个高效的微服务架构。我们将从服务划分、通信机制、数据一致性、服务发现与注册等方面入手,提供一系列实用的策略和建议,帮助开发者优化后端系统的性能和可维护性。
|
18天前
|
Kubernetes 安全 Java
构建高效微服务架构:从理论到实践
【4月更文挑战第9天】 在当今快速迭代与竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性及容错性,成为众多企业转型的首选。本文将深入探讨如何从零开始构建一个高效的微服务系统,覆盖从概念理解、设计原则、技术选型到部署维护的各个阶段。通过实际案例分析与最佳实践分享,旨在为后端工程师提供一套全面的微服务构建指南,帮助读者在面对复杂系统设计时能够做出明智的决策,并提升系统的可靠性与维护效率。
|
2天前
|
监控 测试技术 持续交付
探索现代微服务架构的最佳实践
【4月更文挑战第25天】 随着软件开发领域不断演进,微服务架构已成为设计灵活、可扩展且高度可维护系统的首选方案。本文将深入探讨构建和部署微服务时的关键最佳实践,涵盖从服务划分原则到持续集成/持续部署(CI/CD)的流程,再到监控与日志记录的策略。我们的目标是为开发者提供一套实用的指南,帮助他们在构建未来的应用程序时做出明智的架构选择,并确保这些系统能够快速响应市场和技术的变化。