资讯专栏INFORMATION COLUMN

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

Pines_Cheng / 691人阅读

摘要:一个客户端请求从发出到被响应经历了哪些组件哪些微服务请求总时长每个组件所花时长等信息我们有必要了解和收集,以帮助我们定位性能瓶颈进行性能调优,因此监控整个微服务架构的调用链十分有必要,本文将阐述如何使用搭建微服务调用链追踪中心。


概述

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

注: 本文首发于 My 公众号 CodeSheep ,可 长按扫描 下面的 小心心 来订阅 ↓ ↓ ↓


Zipkin初摸

正如 Ziplin官网 所描述,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:

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


部署Zipkin服务

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

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

完成之后浏览器打开:localhost:9411可以看到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中加入如下依赖:



    4.0.0

    com.hansonwang99
    ZipkinTool
    1.0-SNAPSHOT
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    6
                    6
                
            
        
    
    jar

    
        
            org.springframework.boot
            spring-boot
            2.0.1.RELEASE
            provided
        
        
            org.springframework
            spring-webmvc
            4.3.7.RELEASE
            provided
        
        
            io.zipkin.brave
            brave-spring-web-servlet-interceptor
            4.0.6
        
        
            io.zipkin.brave
            brave-spring-resttemplate-interceptors
            4.0.6
        
        
            io.zipkin.reporter
            zipkin-sender-okhttp3
            0.6.12
        
        
            org.projectlombok
            lombok
            RELEASE
            compile
        
    

编写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 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 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这个微服务,可以看到其调用链的上下游!


2. 查找调用链

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

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

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

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

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

后记

作者更多的原创文章在此,欢迎观赏

My Personal Blog

作者更多的SpringBt实践文章在此:

Spring Boot应用监控实战

SpringBoot应用部署于外置Tomcat容器

ElasticSearch搜索引擎在SpringBt中的实践

初探Kotlin+SpringBoot联合编程

Spring Boot日志框架实践

SpringBoot优雅编码之:Lombok加持


如果有兴趣,也可以抽点时间看看作者一些关于容器化、微服务化方面的文章:

利用K8S技术栈打造个人私有云 连载文章

从一份配置清单详解Nginx服务器配置

Docker容器可视化监控中心搭建

利用ELK搭建Docker容器化应用日志中心

RPC框架实践之:Apache Thrift

RPC框架实践之:Google gRPC

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

Docker容器跨主机通信

Docker Swarm集群初探

高效编写Dockerfile的几条准则



文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/27272.html

相关文章

  • 利用Zipkin追踪Mysql数据库调用

    摘要:注本文首发于公众号,可长按或扫描下面的小心心来订阅扩展组件是在微服务调用链追踪中心搭建一文中编写的与通信的工具组件,利用其追踪微服务调用链的,现在我们想追踪数据库调用链的话,可以扩展一下其功能。 showImg(https://segmentfault.com/img/remote/1460000014751186); 概述 在前面:微服务调用链追踪中心搭建 一文中我们利用Zipki...

    姘存按 评论0 收藏0
  • RPC框架实践之:Apache Thrift

    摘要:在文章微服务调用链追踪中心搭建一文中模拟出来的调用链就是一个远程调用的例子,只不过这篇文章里是通过这种同步调用方式,利用的是协议在应用层完成的,这种方法虽然奏效,但有时效率并不高。 showImg(https://segmentfault.com/img/remote/1460000014858219); 一、概述 RPC(Remote Procedure Call)即 远程过程调...

    Gilbertat 评论0 收藏0
  • RPC框架实践之:Apache Thrift

    摘要:在文章微服务调用链追踪中心搭建一文中模拟出来的调用链就是一个远程调用的例子,只不过这篇文章里是通过这种同步调用方式,利用的是协议在应用层完成的,这种方法虽然奏效,但有时效率并不高。 showImg(https://segmentfault.com/img/remote/1460000014858219); 一、概述 RPC(Remote Procedure Call)即 远程过程调...

    keithxiaoy 评论0 收藏0
  • 利用ELK搭建Docker容器化应用日志中心

    摘要:概述应用一旦容器化以后,需要考虑的就是如何采集位于容器中的应用程序的打印日志供运维分析。 showImg(https://segmentfault.com/img/remote/1460000014146680); 概述 应用一旦容器化以后,需要考虑的就是如何采集位于Docker容器中的应用程序的打印日志供运维分析。典型的比如 SpringBoot应用的日志 收集。本文即将阐述如何利...

    周国辉 评论0 收藏0

发表评论

0条评论

Pines_Cheng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<