概述

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


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 {@Autowiredprivate 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 {@Autowiredprivate 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 {@Autowiredprivate 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 {@Autowiredprivate ZipkinProperties zipkinProperties;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate BraveClientHttpRequestInterceptor clientInterceptor;@Autowiredprivate ServletHandlerInterceptor serverInterceptor;@Beanpublic Sender sender() {return OkHttpSender.create( zipkinProperties.getEndpoint() );}@Beanpublic Reporter<Span> reporter() {return AsyncReporter.builder(sender()).build();}@Beanpublic Brave brave() {return new Brave.Builder(zipkinProperties.getService()).reporter(reporter()).build();}@Beanpublic SpanNameProvider spanNameProvider() {return new SpanNameProvider() {@Overridepublic String spanName(HttpRequest httpRequest) {return String.format("%s %s",httpRequest.getHttpMethod(),httpRequest.getUri().getPath());}};}@PostConstructpublic void init() {List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();interceptors.add(clientInterceptor);restTemplate.setInterceptors(interceptors);}@Overridepublic 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接口,可以看到从发送请求到收到响应信息的所有详细步骤:

后记

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

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

  • Docker容器可视化监控中心搭建
  • 利用K8S技术栈打造个人私有云连载文章
  • 利用ELK搭建Docker容器化应用日志中心

微服务调用链追踪中心搭建相关推荐

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

    概述 一个完整的微服务系统包含多个微服务单元,各个微服务子系统存在互相调用的情况,形成一个 调用链.一个客户端请求从发出到被响应 经历了哪些组件.哪些微服务.请求总时长.每个组件所花时长 等信息我们有 ...

  2. 微服务调用链追踪框架Skywalking,看完你就懂了!

    思维导图 文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary 概述 **skywalking**又是一个优秀的国产开源框 ...

  3. 微服务调用链追踪方案

    zipkin调用链追踪,主要可以知道,服务与服务之间的调用关系,调用的时间,数据信息 1. Trace:一个完整Trace 由一组Span组成,这一组Span必须具有相同的TraceID:Span具有 ...

  4. 微服务调用链日志追踪分析

    一.技术原理 1.1 背景 微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元.由于服务单元数量众多,业务的复杂性,如果出现了错误和异常,很难去定位.主要体现在,一个 ...

  5. 微服务调用链监控开源工具CAT

    1 监控在微服务架构的地位 2 为何需要调用链监控? 在初期的单体应用,应用都打在一个包中,无分布式概念,监控也只需对一些埋点监控. 但是微服务时代下,很多服务在各自的包,一旦出现问题,没有调用链监控 ...

  6. 微服务调用链的原理和选型

    原文:https://juejin.im/post/5cde874e6fb9a07f091b713c 微服务是一个分布式非常复杂系统,如果没有一套调用链监控,如果服务之间依赖出现问题就很难进行调位 下 ...

  7. springboot2 springcloud Greenwich.SR3 构建微服务--1.eureka注册中心搭建

    本一系列springcloud的文章主主要讲应用, 也会涉及到一些原理的讲解. 写了几句自己这段时间看书,总结的微服务的东西送给你们 : 道为源,源分多支为术,如龙生九子,九子各不同,然皆为龙也. 凡 ...

  8. spring cloud+dotnet core搭建微服务架构:配置中心续(五)

    前言 上一章最后讲了,更新配置以后需要重启客户端才能生效,这在实际的场景中是不可取的.由于目前Steeltoe配置的重载只能由客户端发起,没有实现处理程序侦听服务器更改事件,所以还没办法实现彻底实现这 ...

  9. springboot 之 微服务调用 之 链路追踪

    说明:本文来自 本篇主要内容 一.为什么要用链路追踪? 1.1 因:拆分服务单元 微服务架构其实是一个分布式的架构,按照业务划分成了多个服务单元. 由于服务单元的数量是很多的,有可能几千个,而且业务也 ...

  10. 调用链追踪系统在伴鱼:实践篇

    我们介绍了伴鱼在调用链追踪领域的调研工作,本篇继续介绍伴鱼的调用链追踪实践.在正式介绍前,简单交代一下背景:2015 年,在伴鱼服务端起步之时,技术团队就做出统一使用 Go 语言的决定.这个决定的影响 ...

最新文章

  1. 关于TensorFlow报错ModuleNotFoundError: No module named ‘imutils‘
  2. Mysql 新建用户并分配所有权限
  3. 探讨浏览器CSS选择器的权重!!!
  4. 华三实现vlan通过
  5. 烟草局计算机笔试,2020年广西南宁烟草局什么时候笔试?
  6. 工作223:状态管理里面取值
  7. 静态成员函数与静态数据的使用
  8. 怎么用php myadmin连接远程MYSQL数据库
  9. 用matlab实现人脸识别,Matlab实现简单的人脸识别程序
  10. Tenserflow 情感分类
  11. office2016鼠标右键没有新建word等
  12. ramda 函数 list
  13. win7虚拟机详细搭建过程
  14. 学习 MySQL 需要知道的 28 个小技巧
  15. 代谢组学助力研究“线粒体闪烁”,揭示细胞“返老还童”的新奥秘
  16. 重磅直播丨迈向移动数字金融 —— 神州信息并购云核网络线上发布会
  17. 帝国CMS 批量修改信息标题方法
  18. Windows实用工具推荐
  19. Nautre综述:鸟枪法宏基因组-从取样到数据分析(1)2万字带你系统入门宏基因组实验和分析...
  20. element的table组件,表头合并(合并表头单元格)

热门文章

  1. error: crosses initialization of ‘std::string xx变量‘
  2. Jruby On Rails 的安装及部署实践
  3. 中信证券:降准并非货币宽松 缺口或达9000亿
  4. 计算机主机显卡安装,电脑显卡驱动怎么安装
  5. php html block,html blockquote怎么用?blockquote标签的用法介绍
  6. 微信小程序|基于小程序实现打卡功能
  7. 带壳截图 android,给手机截屏带个「套」:带壳截图应用合辑
  8. bi 工具 市场排行榜_bi工具市场排行榜,国内BI软件排名
  9. UVa12235 Help Bubu
  10. Java常用英语汇总(面试必备)