分布式服务跟踪Sleuth - Spring Cloud系列(七)

本文章基于spring-boot-starter-parent 2.0.6RELEASE,spring-cloud-dependencies Finchley.SR2。

Sleuth是什么

在复杂的微服务架构系统中,几乎每一个前端请求都会形成一条复杂的分布式服务调用链路,在每条链路中任意一个依赖服务出现较大延迟或错误的时候都有可能导致请求的失败。这时候,对于每一个请求进行全链路调用的跟踪就变的越来越重要。

针对上述问题,Spring Cloud Sleuth为Spring Cloud提供了分布式服务跟踪的解决方案。Sleuth借用了 Dapper的术语,下面来看下Sleth使用的基础术语:

初始化 span 被称为"rootspan",该 span的 id和 trace的 ID相等。

  • span: 又名跨度,基本工作单元,发送RPC和向RPC发送响应一样,都是一个新的跨度。span用一个64为id唯一标识,是另一个也是用64为id标识的trace的一部分。span还包含其他数据,例如描述、时间戳事件、键值对的注解(标签), span ID、span父 ID、进程id(通常是IP地址)等。
  • Trace: 一组共享"rootspan"的 span组成的树状结构称为 trace,trace也用一个64位的ID唯一标识, trace中的所有 span都共享该 trace的ID
  • Annotation: 用来记录事件的存在
    • cs: 客户端发起一个请求,该annotation描述了span的开始。
    • sr: 服务端获得请求开始处理,sr时间戳减去cs时间戳,可以得到网络延迟。
    • ss: 该annotation表明服务端完成了请求处理(当向客户端发送响应的时候), ss时间戳减去sr时间戳,可以得到服务端的请求处理时间。
    • cr: 标识span的结束,客户端成功接收到服务端的响应。cr时间戳减去cs时间戳得到从客户端发送请求到服务器响应的整个时间。

下图展示了Span和Trace在系统中的样子:
span和trace交互
下图展示上图中Span的父子关系:
span父子关系

Sleuth使用

项目中引入Sleuth

借助之前文章中的示例,我们来集成Sleuth。

  • 服务注册中心: eureka,直接使用之前的工程即可
  • 服务调用方: user
  • 服务提供方: order

集成Sleuth只需要在user和order工程的pom文件中引入依赖即可:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-sleuth</artifactId>
	<version>2.0.2.RELEASE</version>
</dependency>

微服务应用一:User
项目启动类 AppUserApplication

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class AppUserApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppUserApplication.class);
    }
}

配置类 AppConfig

@Configuration
public class AppConfig {

   @Bean
   @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

application.yml

spring:
  application:
    name: user-micro #此实例注册到eureka服务端的name
  sleuth:
    sampler:
      probability: 1.0 #request采样的数量 默认是0.1,即抽样采集10%的请求数据就,这里我们改为全部采集

server:
  port: 5000

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka
    register-with-eureka: true
  instance:
    instance-id: user #此实例注册到eureka服务端的唯一的实例ID
    prefer-ip-address: true #是否显示IP地址
    
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

UserController

@RestController
public class UserController {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    RestTemplate restTemplate;

    @RequestMapping("/getOrder.do")
    @HystrixCommand(fallbackMethod = "getOrderFullBack")
    public R getOrder() {
        logger.info("===call trace1===");
        Object object =  restTemplate.getForObject("http://localhost:7000/getOrder.do", Object.class);
        return R.success("操作成功", object);
    }
    
	public R getOrderFullBack() {
        return R.error("系统正在维护中,请稍后重试");
    }
}

微服务应用二:Order
系统启动类 AppOrderApplication

@SpringBootApplication
@EnableEurekaClient
public class AppOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppOrderApplication.class);
    }
}

application.yml

server:
  port: 7000

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka
  instance:
    instance-id: order #此实例注册到eureka服务端的唯一的实例ID
    prefer-ip-address: true #是否显示IP地址

spring:
  application:
    name: order-micro #此实例注册到eureka服务端的name
  sleuth:
    sampler:
      probability: 1.0

OrderController

@RestController
public class OrderController {
    Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/getOrder.do")
    public Map<String, Object> getOrder() throws Exception {
        logger.info("===call trace2===");
        Map<String,Object> map = new HashMap();
        map.put("key","order");
        return map;
    }
}

启动user、order、eureka等工程,浏览器访问http://localhost:5000/getOrder.do,控制台中会发现比平时多了些信息,如红框所示:
sletuh

  • 第一个值:user-micro,代表应用名称。
  • 第二个值:869ffd33b153f65b,代表Trace ID,用来表示一条链路,一条请求链路中包含一个Trace ID,多个Span ID。
  • 第三个值:5535fbccacf306b5,代表Span ID,表示一个基本的工作单元,比如一次HTTP请求。
  • 第四个值:false,表示是否要将改信息收集到Zipkin等服务中来收集和展示。

在一次服务请求链路的调用中,会保持并传递同一个Trace ID,从而将整个分布于不同微服务进程中的请求跟踪信息串联起来。从user和order的控制台可以看出,它们的Trace ID是相同的,因为处于同一条请求链路中。


从上面可以看出,sleuth对于分布式链路的跟踪仅仅是一些数据的记录,这些数据如果我们人为去整理和分析工作量很大,而且很麻烦。所以需要借助Zipkin来帮助我们处理和分析数据。

ZipKin是什么

Zipkin是Twitter的一个开源项目,它基于Google Dapper实现。可以用来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助查询跟踪数据以实现对分布式系统的请求链路监控,及时的发现微服务架构中存在的系统延时等问题。Zipkin还提供了一个友好的界面,帮助我们直观的搜索跟踪信息和分析请求链路明细。

Zipkin的基础架构如下,主要有4个核心组件构成:
zipkin架构

  • Clollector: 收集器组件,主要处理从给外部系统发送过来的跟踪信息。
  • Storage: 存储组件,主要处理收集器接收到的跟踪信息,默认存储到内存中,可以修改存储策略,通过使用其他存储组件比如将信息存储到数据库中。
  • API: API组件,主要用来提供外部访问接口,比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。
  • UI: 基于API组件实现的上层应用,比如Zipkin自带的控制台。

sleuth整合Zipkin

zipkin官网
zipkin github地址

第一步:搭建Zipkin Server
zipkin server
两种方式搭建zipkin server,一种是直接下载可执行jar包,另一种是执行红框里的命令。

在zipkin2.7.x以后便不支持自定义服务器需要使用官方的版本,如上所示。如果想自己搭建zipkin server请自行百度。

注意:jdk需要1.8及以上
直接下载可执行jar,当前最新版本是zipkin-server-2.12.1-exec.jar,命令行切换到jar包所在路径,执行java -jar zipkin-server-2.12.1-exec.jar,从控制台中打印的图标会发现zipkin是基于springboot的,默认端口号是9411。浏览器访问http://localhost:9411,可看到如下管理页面:
zipkin 控制台

第二步:为应用引入和配置Zipkin服务
在user工程和order工程中引入zipkin依赖(因为spring-cloud-starter-zipkin包含了spring-cloud-starter-sleuth依赖,可以只引入zipkin这一个依赖)。

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-zipkin</artifactId>
	<version>2.0.2.RELEASE</version>
</dependency>

在user工程和order工程application.yml中添加并指定zkpkin server的地址

spring:
  zipkin:
    base-url: http://localhost:9411  #指定Zipkin server地址

重启user和order,访问http://localhost:5000/getOrder.do即可看到zipkin的控制台中出现了一条链路信息。
user调用order
点击进去,可以看到整个链路的总耗时,以及各个服务调用的耗时等相关信息。
user调用order2
如果出错,也会看到详细的错误信息。把order工程停掉,再次请求http://localhost:5000/getOrder.do会发现zipkin控制台新增一条标红的记录,点击进去可查明细。
error1
error2
点击控制台右侧也可以查看依赖关系
user调用order3
关于zipkin的各种功能,读者请自行体验。

zipkin数据持久化

当zipkin重启后,我们会发现分布式链路数据全部被清空了,因为zipkin server默认是将数据存储在内存当中,所以每次重启都会造成信息丢失,并且当有大量跟踪信息是我们的内存存储也会成为瓶颈。所以通常我们需要将链路信息存储到外部组件中去,比如Mysql、或者ELK平台。

下面我们使用Elasticsearch来做数据持久化
Elasticsearch下载

下载到本地后,做些简单配置(这里不再介绍),进入根目录,执行bin/elasticsearch,windows机器上执行bin/elasticsearch.bat。启动后在浏览器中输入http://localhost:9200/看到如下页面说明启动成功。
elasticsearch

zipkin server使用elasticsearch存储功能
Zipkin包含一个StorageComponent,用于存储和查询span以及依赖链接。StorageComponent包含elasticsearch、mysql、Cassandra等,可以使用这些组件作为数据存储。停掉zipkin server,改用新命令启动STORAGE_TYPE=elasticsearch ES_HOSTS=localhost:9200 java -jar zipkin-server-2.12.1-exec.jar

可以测试几次请求,然后再次重启zipkin server,发现数据没有丢失,说明zipkin和elasticsearch整合成功。


------------本文结束感谢您的阅读------------
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值