一、背景

随着业务的发展,系统规模越来越大,各微服务直接的调用关系也变得越来越复杂。通常一个由客户端发起的请求在后端系统中会经过多个不同的微服务调用协同产生最后的请求结果,几乎每一个前端请求都会形成一条复杂的分布式服务调用链路,对每个请求实现全链路跟踪,可以帮助我们快速发现错误根源以及监控分析每条请求链路上性能瓶颈。
针对分布式服务跟踪,Spring Cloud Sleuth提供了一套完整的解决方案。

二、原理

参考《SpringCloud微服务实战》第11章。
先查看跟踪日志了解每项的含义

2019-02-27 20:40:56.419  INFO [service-a,e79b41414a56743d,e79b41414a56743d,true] 8276 --- [nio-9001-exec-5] cn.sp.controller.ServiceController       : ==<Call Service-a>==
  1. 第一个值service-a:记录了应用的名称,也就是spring.application.name的值。
  2. 第二个值e79b41414a56743d:SpringCloudSleuth生成的一个ID,叫TraceID,它用来标识一条请求链路。一条请求链路中包含一个TraceID,多个 SpanID。
  3. 第三个值e79b41414a56743d,SpringCloudSleuth生成的另外一个ID,叫SpanID,它表示一个基本的工作单元,比如发送一个HTTP请求。
  4. 第四个值true:表示是否要将该信息输出到Zipkin等服务中收集和展示。

三、编码

3.1创建一个Eureka注册中心

这个之前的文章有,故省略

3.2调用者service-a

1.创建项目引入依赖

  1. <dependency> 

  2. <groupId>org.springframework.boot</groupId> 

  3. <artifactId>spring-boot-starter-web</artifactId> 

  4. </dependency> 

  5. <dependency> 

  6. <groupId>org.springframework.cloud</groupId> 

  7. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 

  8. </dependency> 

  9. <dependency> 

  10. <groupId>org.springframework.cloud</groupId> 

  11. <artifactId>spring-cloud-starter-sleuth</artifactId> 

  12. </dependency> 

  13. <dependency> 

  14. <groupId>org.springframework.cloud</groupId> 

  15. <artifactId>spring-cloud-starter-zipkin</artifactId> 

  16. </dependency> 

其实spring-cloud-starter-zipkin中已经有了sleuth的依赖,spring-cloud-starter-sleuth可以省略。
2. 启动类

@EnableEurekaClient
@SpringBootApplication
public class ServiceAApplication { public static void main(String[] args) {
SpringApplication.run(ServiceAApplication.class, args);
} @Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
  1. ServiceController
@RestController
public class ServiceController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired
private RestTemplate restTemplate; @GetMapping("/service-a")
public String test(){
logger.info("==<Call Service-a>==");
return restTemplate.getForEntity("http://service-b/test",String.class).getBody();
}
}

这里的url(http://service-b/test)用的是服务名当虚拟域名而不是ip+端口号的形式,至于为什么可以访问可以查看这篇文章【Spring Cloud中restTemplate是如何通过服务名主求到具体服务的】。

4.配置文件application.yml

  1. spring: 

  2. application: 

  3. name: service-a 

  4. zipkin: 

  5. base-url: http://localhost:9411 

  6. # 抽样收集的百分比,默认10% 

  7. sleuth: 

  8. sampler: 

  9. probability: 1 

  10. eureka: 

  11. client: 

  12. serviceUrl: 

  13. defaultZone: http://localhost:8761/eureka/ 

  14. server: 

  15. port: 9001 

3.3被调用者service-b

1.创建项目引入依赖pom文件同上
2.启动类添加注解 @EnableEurekaClient
3.ServiceController

@RestController
public class ServiceController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @GetMapping("/test")
public String test(){
logger.info("==<Call Service-b>==");
return "OK";
}
}

4.配置文件application.yml

  1. spring: 

  2. application: 

  3. name: service-b 

  4. zipkin: 

  5. base-url: http://localhost:9411 

  6. # 抽样收集的百分比,默认10% 

  7. sleuth: 

  8. sampler: 

  9. probability: 1 

  10. eureka: 

  11. client: 

  12. serviceUrl: 

  13. defaultZone: http://localhost:8761/eureka/ 

  14. server: 

  15. port: 9002 

3.4创建zipkin-server

  1. pom.xml
  1. <dependency> 

  2. <groupId>io.zipkin.java</groupId> 

  3. <artifactId>zipkin-server</artifactId> 

  4. <version>2.12.2</version> 

  5. <exclusions> 

  6. <exclusion> 

  7. <groupId>org.springframework.boot</groupId> 

  8. <artifactId>spring-boot-starter-log4j2</artifactId> 

  9. </exclusion> 

  10. </exclusions> 

  11. </dependency> 

  12. <!-- https://mvnrepository.com/artifact/io.zipkin.java/zipkin-autoconfigure-ui --> 

  13. <dependency> 

  14. <groupId>io.zipkin.java</groupId> 

  15. <artifactId>zipkin-autoconfigure-ui</artifactId> 

  16. <version>2.12.2</version> 

  17. </dependency> 

2.启动类添加注解 @EnableZipkinServer
注意: 这里我排除了log4j的依赖,因为已经有了相同的类文件启动会报错。

四、测试

  1. 依次启动eureka注册中,service-a,service-b,zipkin-server
  2. 访问http://localhost:8761/看到有两个注册实例,说明启动成功。
  3. 游览器访问http://localhost:9001/service-a请求服务A
    如果报错日志打印java.lang.IllegalStateException: No instances available for service-b,那可能是服务B还没注册完成等会儿再试下即可。
  4. 正常情况会看到游览器显示 OK
    服务A的日志如下:
2019-02-27 21:18:05.119  INFO [service-a,3e487761c9b13a2e,3e487761c9b13a2e,true] 8276 --- [nio-9001-exec-9] cn.sp.controller.ServiceController       : ==<Call Service-a>==

服务B的日志如下:

2019-02-27 21:18:05.128  INFO [service-b,3e487761c9b13a2e,8d49352c6645c6f9,true] 13860 --- [nio-9002-exec-8] cn.sp.controller.ServiceController       : ==<Call Service-b>==
  1. 访问http://localhost:9411/zipkin/进入可视化界面

点击查找,服务名选择service-a即可看到最近的统计数据,还可以根据条件进行筛选。

点击依赖,依赖分析就可以看到服务之前的依赖关系。

完整代码地址。

五、总结

基本是根据《SpringCloud微服务实战》这本书来的,但是中间还是踩了几个坑,比如开始报No instances available for service-b的时候我一直以为是代码哪里出了问题,浪费了很多时间。

SpringCloudSleuth除了把请求链路数据整合到Zipkin中外,还可以保存到消息队列,ELK等,还算比较强大。但是除了HTTP请求,不知道对于GRPC这样的通信方式是否也能实现链路跟踪。

查了下资料支持Grpc的,demo地址:https://github.com/tkvangorder/sleuth-grpc-sample

官方文档:https://cloud.spring.io/spring-cloud-sleuth/single/spring-cloud-sleuth.html#_grpc

【SpringCloud构建微服务系列】分布式链路跟踪Spring Cloud Sleuth的更多相关文章

  1. Spring cloud系列十四 分布式链路监控Spring Cloud Sleuth

    1. 概述 Spring Cloud Sleuth实现对Spring cloud 分布式链路监控 本文介绍了和Sleuth相关的内容,主要内容如下: Spring Cloud Sleuth中的重要术语 ...

  2. 【SpringCloud构建微服务系列】微服务网关Zuul

    一.为什么要用微服务网关 在微服务架构中,一般不同的微服务有不同的网络地址,而外部客户端(如手机APP)可能需要调用多个接口才能完成一次业务需求.例如一个电影购票的手机APP,可能会调用多个微服务的接 ...

  3. 【SpringCloud构建微服务系列】Feign的使用详解

    一.简介 在微服务中,服务消费者需要请求服务生产者的接口进行消费,可以使用SpringBoot自带的RestTemplate或者HttpClient实现,但是都过于麻烦. 这时,就可以使用Feign了 ...

  4. 【SpringCloud构建微服务系列】使用Spring Cloud Config统一管理服务配置

    一.为什么要统一管理微服务配置 对于传统的单体应用而言,常使用配置文件来管理所有配置,比如SpringBoot的application.yml文件,但是在微服务架构中全部手动修改的话很麻烦而且不易维护 ...

  5. 【SpringCloud构建微服务系列】学习断路器Hystrix

    一.Hystrix简介 在微服务架构中经常包括多个服务层,比如A为B提供服务,B为C和D提供服务,如果A出故障了就会导致B也不可用,最终导致C和D也不可用,这就形成了雪崩效应. 所以为了应对这种情况, ...

  6. SpringCloud(7)服务链路追踪Spring Cloud Sleuth

    1.简介 Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案,并且兼容支持了 zipkin,你只需要在pom文件中引入相应的依赖即可.本文主要讲述服务追踪组件zipki ...

  7. 史上最简单的SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth)(Finchley版本)

    转载请标明出处: 原文首发于:>https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f9-sleuth/ 本文出自方志朋的博客 这篇文章主 ...

  8. 史上最简单的SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth)

    这篇文章主要讲述服务追踪组件zipkin,Spring Cloud Sleuth集成了zipkin组件. 注意情况: 该案例使用的spring-boot版本1.5.x,没使用2.0.x, 另外本文图3 ...

  9. SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth)

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 ,博主地址:http://blog.csdn.net/forezp. http://blog.csdn.net/forezp/art ...

随机推荐

  1. tornado之模板扩展

    当我们有多个模板的时候,很多模板之间其实相似度很高.我们期望可以重用部分网页代码.这在tornado中可以通过extends语句来实现.为了扩展一个已经存在的模板,你只需要在新的模板文件的顶部放上一句 ...

  2. 12.HTML DOM 允许 JavaScript 改变 HTML 元素的内容。

    1,改变 HTML 输出流 <script> document.write(Date()); </script> 2,改变 HTML 内容 <script> doc ...

  3. 【C++基础学习】引用和指针、重载、函数、内存管理

    第一部分:引用VS指针 引用的含义:变量的别名 注意:变量不能只有别名,必须有一个真实的变量与之相对应 基本数据类型的引用 对别名本身的操作和它的实体的操作是一样的 1.基本数据类型的引用 类型 &a ...

  4. Express中的Ejs模板传值问题

    在Ejs模板传值过程中,route下的变量值通过res.sender()中的变量参数传给views, 这时在views中若该变量在javascript代码中使用,可直接使用该变量,不必使用<% ...

  5. Shell之内容匹配与格式输出

    对于大文本或者有些特定格式的文本,有时我们要查找特定内容或定位指定的区域,这样就需要内容匹配. 关于内容匹配,我们常使用的有几个命令: grep,支持正则,查找包含有匹配项的行. cut,提取指定的列 ...

  6. 在react jsx中,为什么使用箭头函数和bind容易出现问题

    在之前的文章中,已经说明如何避免在react jsx中使用箭头函数和bind(https://medium.freecodecamp.o... 但是没有提供一个清晰的demo展示为什么要这样做. 现在 ...

  7. DHCP request error:Timed out waiting for dhcpcd to start【转】

    本文转载自:http://blog.csdn.net/zvivi521/article/details/9166899 [init.svc.dhcpcd_eth0]: [stopped] I/Serv ...

  8. sdut oj 1163 C语言实验——排列 (当初不会递归生成排列,这个题目现在才补上 刘汝佳给出了写法 *【模板】 当然有生成全排列的函数存在 )

    C语言实验——排列 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 有4个互不相同的数字,请按序输出由其中三个不重复数字组成的排列 ...

  9. 从Github上下载了项目,导入Android Studio,gradle 报错,应该怎么修改

    一.从Github上获取源代码 我这里是直接下载ZIP文件 二.在本机的Android Studio上新建一个空白项目,目的主要是与刚从Github上下载的项目文件结构做对比 三.替换gradle文件 ...

  10. Linux档案属性

    输入命令:ls -al 档案类型权限: 第一個字元代表这个档案是『目录.档案或链接档等等』: 当为[ d ]则是目录: 当为[ - ]则是目录: 若是[ l ]则表示为链接档(link file): ...