本文出自 [ 慌途L ]
最近开始写博客,一些问题可能了解也不够透彻,写一下快速入门并且踩过的坑,希望大家少踩坑。本文简单介绍一下springcloud的服务链路追踪,不足之处希望大家指出,我改正。不喜勿喷!
这篇文章主要讲述服务追踪组件zipkin,Spring Cloud Sleuth集成了zipkin组件
spring cloud sleuth主要功能就是在分布式系统中提供追踪解决方案,并兼容了zipkin,Zipkin是一个链路跟踪工具,可以用来监控微服务集群中调用链路的通畅情况,你只需要在pom文件中引入相应的依赖即可
微服务架构上通过业务来划分服务的,通过REST调用,对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用会越来越复杂。
注:假设实现一个完整的业务,需要服务A调用服务B,服务B调用服务C,服务C再调用服务D,然后又有一系列的回调,服务D回调服务C,服务C再回调服务B。诸如此类,如果调用的服务多,链路长,那么出现了问题没有一个完整的追踪很难发现问题,所以需要服务链路追踪。
zipkin作用
根据依赖关系进行全链路追踪的工具
查看每个接口、每个service的执行速度(定位问题发生点或者寻找性能瓶颈)
zipkin跟踪系统的目的:
zipkin为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪;
zipkin通过采集跟踪数据可以帮助开发者深入了解在分布式系统中某一个特定的请求时如何执行的;
假如我们现在有一个用户请求超时,我们就可以将这个超时的请求调用链展示在界面当中;我们可以很快度的定位到导致响应很慢的服务究竟是什么。如果对这个服务细节也很很清晰,那么我们还可以定位是服务中的哪个问题导致超时;
zipkin系统让开发者可通过一个Web前端轻松的收集和分析数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。
zipkin核心数据结构
Span:一个请求(包含一组Annotation和BinaryAnnotation);它是基本工作单元,一次链路调用 (可以是RPC,DB等没有特定的限制) 创建
一个span,通过一个64位ID标识它。span通过还有其他的数据,例如描述信息,时间戳,key-value对的(Annotation)tag信息,parent-id
等,其中parent-id可以表示span调用链路来源,通俗的理解span就是一次请求信息。
span在不断的启动和停止,同时记录了时间信息,当你创建了一个span,你必须在未来的某个时刻停止它
Trace:类似于树结构的Span集合,表示一条调用链路,存在唯一标识traceId
通过traceId、spanId和parentId,被收集到的span会汇聚成一个tree,从而提供出一个request的整体流程。(这也是zipkin的工作原理)
Annotation:用于定位一个request的开始和结束,cs/sr/ss/cr含有额外的信息,比如说时间点
cs:Client Start,表示客户端发起请求一个span的开始;
sr:Server Receive,表示服务端收到请求;
ss:Server Send,表示服务端完成处理,并将结果发送给客户端;
cr:Client Received,表示客户端获取到服务端返回信息一个span的结束(客户端成功接收到服务端的回复,如果cr减去cs时间戳便
可得到 客户端从服务端获取回复的所有所需时间 );
当这个annotation被记录了,这个RPC也被认为完成了。
BinaryAnnotation:用途:提供一些额外信息,一般已key-value对出现。
将Span和Trace在一个系统中使用Zipkin注解的过程图形化(如下):
我创建的主要由三个工程组成:一个server-zipkin,它的主要作用使用ZipkinServer 的功能,收集调用数据,并展示;一个service-aaa,对外暴露hi接口;一个service-bbb,对外暴露bbb接口;这两个service可以相互调用;并且只有调用了,server-zipkin才会收集数据的,这就是服务追踪。
下面以idea开发工具为例
3.1 构建server-zipkin
建一个原生spring-boot工程取名为server-zipkin,选择web依赖,再拷贝下面的两个io依赖在pom文件中进行引入:
<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.0modelVersion>
<groupId>com.huangtugroupId>
<artifactId>server-zipkinartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<name>server-zipkinname>
<description>Demo project for Spring Bootdescription>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.4.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>io.zipkin.javagroupId>
<artifactId>zipkin-serverartifactId>
<version>2.9.4version>
dependency>
<dependency>
<groupId>io.zipkin.javagroupId>
<artifactId>zipkin-autoconfigure-uiartifactId>
<version>2.9.4version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
project>
在其程序入口类, 加上注解@EnableZipkinServer,开启ZipkinServer的功能:
@SpringBootApplication
@EnableZipkinServer//开启ZipkinServer
public class ServerZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ServerZipkinApplication.class, args);
}
}
在配置文件application.properties指定服务端口:
#配置服务及端口
server.port=7777
3.2 构建service-aaa
注意:构建service-aaa项目可直接在idea中选择依赖包,不需要手动加入。
在其pom文件中引入起步依赖spring-cloud-starter-zipkin,代码如下:
<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.0modelVersion>
<groupId>com.huangtugroupId>
<artifactId>service-hiartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<name>service-hiname>
<description>Demo project for Spring Bootdescription>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.4.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR1spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
在其配置文件application.properties指定zipkin server的地址,头通过配置“spring.zipkin.base-url”指定:
server.port=7778
spring.zipkin.base-url=http://localhost:7778
spring.application.name=service-aaa
通过引入spring-cloud-starter-zipkin依赖和设置spring.zipkin.base-url就可以了。
对外暴露接口:
@SpringBootApplication
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHiApplication.class, args);
}
private static final Logger LOG = Logger.getLogger(ServiceHiApplication.class.getName());
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping(value = "/hi", method = RequestMethod.GET)
public String callHome(){
LOG.log(Level.INFO, "calling trace service-aaa ");
return restTemplate.getForObject("http://localhost:7779/hi", String.class);
}
@RequestMapping(value = "/aaa", method = RequestMethod.GET)
public String info(){
LOG.log(Level.INFO, "calling trace service-aaa ");
return "i'm service-aaa";
}
}
3.3 构建service-bbb
创建过程痛service-bbb,引入相同的依赖,配置下spring.zipkin.base-url
在其配置文件application.properties指定zipkin server的地址,头通过配置“spring.zipkin.base-url”指定:
server.port=7779
spring.zipkin.base-url=http://localhost:7777
spring.application.name=service-aaa
对外暴露接口:
@SpringBootApplication
@RestController
public class ServiceMiyaApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceMiyaApplication.class, args);
}
private static final Logger LOG = Logger.getLogger(ServiceMiyaApplication.class.getName());
@RequestMapping(value = "/hi", method = RequestMethod.GET)
public String home(){
LOG.log(Level.INFO, "hi is being called");
return "hi i'm service-bbb!";
}
@RequestMapping(value = "/bbb", method = RequestMethod.GET)
public String info(){
LOG.log(Level.INFO, "info is being called");
return restTemplate.getForObject("http://localhost:7778/aaa",String.class);
}
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3.4 启动工程,进行演示
1.依次启动上面的三个工程,打开浏览器访问:http://localhost:7777/,会出现以下界面:
注意:如果页面一直在加载中,我们可以发现后台已经报错了
java.lang.IllegalArgumentException: Prometheus requires that all meters with the same name have the same set of tag keys. There is already an existing meter containing tag keys [method, status, uri]. The meter you are attempting to register has keys [exception, method, status, uri].
需要在server-zipkin项目的application.properties中加入:
management.metrics.web.server.auto-time-requests=false
2.服务service-aaa访问自己:http://localhost:7778/aaa,浏览器出现:
i’m service-aaa
3.服务service-aaa访问服务service-bbb:http://localhost:7778/hi,浏览器出现:
hi i’m service-bbb!
4.服务service-bbb访问自己:http://localhost:7778/hi,浏览器出现:
hi i’m service-bbb!
5.服务service-bbb访问服务service-aaa:http://localhost:7778/bbb,浏览器出现:
i’m service-aaa
6.下面我们可以看到这个图,蓝色代表调用接口成功,如果为红色则代表调用接口失败:
1:使用zipkin,必须使用java8
2:在生产环境,不会对每个请求都进行采样追踪(降低trace对整个服务的性能损耗)
zipkin还有很多需要学习的地方,在以后的深入理解后会再写文章分享给大家。
至此,谢谢大家的阅读,才疏学浅,写下一点浅薄之谈,希望对大家有帮助。
最后提醒大家一下:
在SpringCloud2.0版本和1.0版本在依赖名称上已经发生了一些变化,所以有些同学可能已经踩到这个坑了,在这里简单讲解一下,比如:
2.0版本的依赖名称为:spring-cloud-starter-netflix-eureka-server
1.0版本的依赖名称为:spring-cloud-starter-eureka-server
所以大家可以多看文档,分清2.0版本和1.0版本的区别,一些依赖名称,或者断路器的访问路径都会有一些变化。