新版本SpringCloud sleuth整合zipkin

SpringCloud Sleuth 简介

Spring Cloud Sleuth为Spring Cloud实现了分布式跟踪解决方案。

Spring Cloud Sleuth借鉴了Dapper的术语。

Span:基本的工作单元。Span包括一个64位的唯一ID,一个64位trace码,描述信息,时间戳事件,key-value 注解(tags),span处理者的ID(通常为IP)。

Trace:一组Span形成的树形结构。

Annotation:用于及时记录存在的事件。常用的Annotation如下:

  • cs:客户端发送(client send) 客户端发起一个请求,表示span开始
  • sr:服务器接收(server received) 服务器接收到客户端的请求并开始处理,sr - cs 的时间为网络延迟
  • ss:服务器发送(server send) 服务器处理完请求准备返回数据给客户端。ss - sr 的时间表示服务器端处理请求花费的时间
  • cr:客户端接收(client received) 客户端接收到处理结果,表示span结束。 cr - cs 的时间表示客户端接收服务端数据的时间

下图展示了Span和Trace在系统中的联系

SpringCloud Sleuth 默认采用 Http 方式将 span 信息传输给 Zipkin

在application.properties文件中指定

spring.zipkin.sender.type=web

使用 RabbitMQ 异步发送 span 信息

为什么选择 RabbitMQ 消息中间件发送 span 信息

  • sleuth 默认采用 http 通信方式,将数据传给 zipkin 作页面渲染,但是 http 传输过程中如果由于不可抗因素导致 http 通信中断,那么此次通信的数据将会丢失。而使用中间件的话,RabbitMQ 消息队列可以积压千万级别的消息,下次重连之后可以继续消费。
  • 随着线程增多,并发量提升之后,RabbitMQ 异步发送数据明显更具有优势。
  • RabbitMQ 支持消息、队列持久化,可以通过消息状态落库、重回队列、镜像队列等技术手段保证其高可用。

示例

示例简介

示例包含sleuth-search、sleuth-cart、sleuth-order三个系统,用来模拟电商系统中下单的流程,用户可以搜索商品然后立即下单,也可以搜索多个商品后加入购物车,然后下单,调用情况即 search -> cart -> order,或 search -> order。

示例使用 RestTemplate 来完成三个系统间的 http 请求响应,请求方式也都遵循Restful风格。

版本说明

版本一定要对应好,一些低版本的SpringBoot无法兼容新版本的SpringCloud和zipkin

工具 版本
SpringBoot 2.1.6.RELEASE
SpringCloud Greenwich.SR3
zipkin 2.16.2

项目结构

demo-cloudsleuth
    |- sleuth-search
    |- sleuth-cart
    |- sleuth-order
    pom.xml

导入依赖

    <!-- 引入 springboot 和 springcloud 父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
        </dependency>
        <!-- Springboot 相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

配置 RestTemplate,RestTemplate是SpringBoot提供的封装好的http工具类,可以帮助我们简化http的使用。

package com.anqi.cart.resttmplate;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        return factory;
    }
}

三个系统下的application.properties,端口分别是8081 8082 8083

#server.port=8081 server.port=8082
server.port=8083
server.servlet.context-path=/

spring.zipkin.base-url=http://localhost:9411/
spring.zipkin.service.name=sleuth-cart

#使用默认 http 方式收集 span 需要配置此项
#spring.zipkin.sender.type=web

#sleuth 使用 rabbitmq 来向 zipkin 发送数据
spring.zipkin.sender.type=rabbit
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

#设置采样率默认为 0.1 注意之前的版本是percentage 新版本中更换为 probability
spring.sleuth.sampler.probability=1

三个系统下的RestTemplate的配置,用来简化 http 请求

package com.anqi.cart.resttmplate;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        return factory;
    }
}
@RequestMapping("cart")
@RestController
public class CartController {
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    CartService cartService;
    private static final String orderUrl = "http://localhost:8084/order/create";

    @GetMapping("/add/{cartId}")
    public String addToCart(@PathVariable("cartId") String cartId) {
        cartService.addProductToCart(cartId, "小米8");
        ResponseEntity<String> res = restTemplate.getForEntity(orderUrl, String.class);
        return res.getBody();
    }
}
@RequestMapping("order")
@RestController
public class OrderController {
    @GetMapping("/create")
    public String creatOrder() {
        System.out.println("create order");
        return "create_order";
    }
}
@RestController
public class SearchController {
    @Autowired
    RestTemplate restTemplate;

    private static final String cartUrl = "http://localhost:8083/cart/add/1";
    private static final String orderUrl = "http://localhost:8084/order/create";

    @GetMapping("/search")
    public String search() {
        ResponseEntity<String> cartRes = restTemplate.getForEntity(cartUrl, String.class);
        ResponseEntity<String> orderRes = restTemplate.getForEntity(orderUrl, String.class);
        return "cart:" + cartRes.getBody() + "- order:" + orderRes.getBody();

    }
}

运行结果分析

默认 http 传输 span 信息

启动Zipkin

java -jar zipkin-server-2.16.2-exec.jar

网页中手动访问

http://localhost:8082/search

我们访问zipkin站点查询调用情况

http://localhost:9411/zipkin/traces/94b954d843012ca9

可以从下图中完整清晰的看到三个系统的调用关系

下图为zipkin调用预览,我们请求四次http://localhost:8082/search来更直观的观察数据。在以下界面中,较为简洁的显示Span的个数以及调用总时延。

我们进入一个完整的调用链后访问其中的一个节点得到以下数据。

以下为一次全链路追踪的详细信息,包含7个span的所有信息,以上看到的页面展示均有以下数据加以渲染而成。

[
  {
    "traceId": "94b954d843012ca9",
    "parentId": "bab70b1e69a5f3e3",
    "id": "96387b33a823ca8f",
    "kind": "SERVER",
    "name": "get /order/create",
    "timestamp": 1569060494069123,
    "duration": 1161,
    "localEndpoint": {
      "serviceName": "sletuth-order",
      "ipv4": "192.168.0.107"
    },
    "remoteEndpoint": {
      "ipv4": "127.0.0.1",
      "port": 49863
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/order/create",
      "mvc.controller.class": "OrderController",
      "mvc.controller.method": "creatOrder"
    },
    "shared": true
  },
  {
    "traceId": "94b954d843012ca9",
    "parentId": "94b954d843012ca9",
    "id": "90f7e5cfa89e0d80",
    "kind": "SERVER",
    "name": "get /order/create",
    "timestamp": 1569060494076287,
    "duration": 1296,
    "localEndpoint": {
      "serviceName": "sletuth-order",
      "ipv4": "192.168.0.107"
    },
    "remoteEndpoint": {
      "ipv4": "127.0.0.1",
      "port": 49864
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/order/create",
      "mvc.controller.class": "OrderController",
      "mvc.controller.method": "creatOrder"
    },
    "shared": true
  },
  {
    "traceId": "94b954d843012ca9",
    "parentId": "94b954d843012ca9",
    "id": "bab70b1e69a5f3e3",
    "kind": "CLIENT",
    "name": "get",
    "timestamp": 1569060494063693,
    "duration": 10374,
    "localEndpoint": {
      "serviceName": "sleuth-search",
      "ipv4": "192.168.0.107"
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/cart/add/1"
    }
  },
  {
    "traceId": "94b954d843012ca9",
    "parentId": "94b954d843012ca9",
    "id": "90f7e5cfa89e0d80",
    "kind": "CLIENT",
    "name": "get",
    "timestamp": 1569060494074966,
    "duration": 2848,
    "localEndpoint": {
      "serviceName": "sleuth-search",
      "ipv4": "192.168.0.107"
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/order/create"
    }
  },
  {
    "traceId": "94b954d843012ca9",
    "id": "94b954d843012ca9",
    "kind": "SERVER",
    "name": "get /search",
    "timestamp": 1569060494062631,
    "duration": 16332,
    "localEndpoint": {
      "serviceName": "sleuth-search",
      "ipv4": "192.168.0.107"
    },
    "remoteEndpoint": {
      "ipv6": "::1",
      "port": 49859
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/search",
      "mvc.controller.class": "SearchController",
      "mvc.controller.method": "search"
    }
  },
  {
    "traceId": "94b954d843012ca9",
    "parentId": "bab70b1e69a5f3e3",
    "id": "96387b33a823ca8f",
    "kind": "CLIENT",
    "name": "get",
    "timestamp": 1569060494067090,
    "duration": 3197,
    "localEndpoint": {
      "serviceName": "sleuth-cart",
      "ipv4": "192.168.0.107"
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/order/create"
    }
  },
  {
    "traceId": "94b954d843012ca9",
    "parentId": "94b954d843012ca9",
    "id": "bab70b1e69a5f3e3",
    "kind": "SERVER",
    "name": "get /cart/add/{cartid}",
    "timestamp": 1569060494066140,
    "duration": 8150,
    "localEndpoint": {
      "serviceName": "sleuth-cart",
      "ipv4": "192.168.0.107"
    },
    "remoteEndpoint": {
      "ipv4": "127.0.0.1",
      "port": 49862
    },
    "tags": {
      "http.method": "GET",
      "http.path": "/cart/add/1",
      "mvc.controller.class": "CartController",
      "mvc.controller.method": "addToCart"
    },
    "shared": true
  }
]

使用 RabbitMQ 情况

启动 zipkin,注意参数

java -jar zipkin-server-2.16.2-exec.jar --RABBIT_ADDRESSES=localhost:5672 --RABBIT_USER=guest --RABBIT_PASSWORD=guest --RABBIT_VIRTUAL_HOST=/

启动 rabbitmq

rabbitmq-server

在测试的时候发现 mq 和以上方式时延相差无几,但是随着线程数的增加也就是并发量的增加,mq 传输时延将会大大低于 http。

原文地址:https://www.cnblogs.com/haixiang/p/11568659.html

时间: 2024-08-02 20:40:34

新版本SpringCloud sleuth整合zipkin的相关文章

spring cloud 入门系列八:使用spring cloud sleuth整合zipkin进行服务链路追踪

好久没有写博客了,主要是最近有些忙,今天忙里偷闲来一篇. =======我是华丽的分割线========== 微服务架构是一种分布式架构,微服务系统按照业务划分服务单元,一个微服务往往会有很多个服务单元,一个请求往往会有很多个单元参与,一旦请求出现异常,想要去定位问题点真心不容易,因此需要有个东西去跟踪请求链路,记录一个请求都调用了哪些服务单元,调用顺序是怎么样的以及在各个服务单元处理的时间长短.常见的服务链路追踪组件有google的dapper.twitter的zipkin.阿里的鹰眼等,它们

springcloud -- sleuth+zipkin整合rabbitMQ详解

为什么使用RabbitMQ? 我们已经知道,zipkin的原理是服务之间的调用关系会通过HTTP方式上报到zipkin-server端,然后我们再通过zipkin-ui去调用查看追踪服务之间的调用链路.但是这种方式存在一个隐患,如果微服务之间与zipkin服务端网络不通,或调用链路上的网络闪断,http通信收集方式就无法工作.而且zipkin默认是将数据存储在内存中的,如果服务端重启或宕机,就会导致数据丢失. 所以我们不仅将数据存储在zipkin-serve中,同时还能通过某个消息存储的容器将本

跟我学SpringCloud | 第十一篇:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪

SpringCloud系列教程 | 第十一篇:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如无特殊说明,本系列教程全采用以上版本 在分布式服务架构中,需要对分布式服务进行治理--在分布式服务协同向用户提供服务时,每个请求都被哪些服务处理?在遇到问题时,在调用哪个服务上发生了问题?在分析性能时,调用各个服务都花了多长时间?哪些调用可以并行执行?-- 为此,分布式

springcloud --- spring cloud sleuth和zipkin日志管理(spring boot 2.18)

前言 在spring cloud分布式架构中,系统被拆分成了许多个服务单元,业务复杂性提高.如果出现了异常情况,很难定位到错误位置,所以需要实现分布式链路追踪,跟进一个请求有哪些服务参与,参与的顺序如何,从而去明确一个问题. spring cloud sleuth 通常来说,一个分布式服务跟踪系统主要由三部分:数据收集.数据存储和数据展示. 对于大规模的分布式系统来说,数据存储可分为实时数据和全量数据两部分.实时数据用来排查故障,全量数据用于系统优化:数据展示涉及数据挖掘和分析. 名词解释 服务

Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】

Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版] 发表于 2018-04-24 | 随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请求可能最终需要调用很多次后端服务才能完成,当整个请求变慢或不可用时,我们是无法得知该请求是由某个或某些后端服务引起的,这时就需要解决如何快读定位服务故障点,以对症下药.于是就有了分布式系统调用跟踪的诞生. 现今业界分布式服务跟踪的理论基础主要来自于 Google 的一篇论文<Dapper, a Larg

SpringCloud Sleuth 分布式请求链路跟踪

一.概述 ? 在微服务框架中,一个客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败.SpringCloud Sleuth 提供了一套完整的服务跟踪的解决方案,在分布式系统中提供追踪解决方案并且兼容支持了zipkin .官方文档地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-sleut

Distributed traceability with Spring Cloud: Sleuth and Zipkin

I. Sleuth 0. Concept Trace A set of spans that form a call tree structure, forms the trace of the request. Span It is the basic unit of work, for example a call to a service. They are identified with a span ID and a trace ID to which span is owned. T

SpringCloud Sleuth 使用

1. 介绍   Spring-Cloud-Sleuth是Spring Cloud的组成部分之一,为SpringCloud应用实现了一种分布式追踪解决方案,其兼容了Zipkin, HTrace和log-based追踪 相关说明: zipkin Span:基本工作单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span通过一个64位ID唯一标识,trace以另一个64位ID表示,span还有其他数据信息,比如摘要.时间戳事件.关键值注释(tags).span的ID.以

Spring Sleuth和Zipkin跟踪微服务

原文地址:http://www.cnblogs.com/skyblog/p/6213683.html 随着微服务数量不断增长,需要跟踪一个请求从一个微服务到下一个微服务的传播过程, Spring Cloud Sleuth 正是解决这个问题,它在日志中引入唯一ID,以保证微服务调用之间的一致性,这样你就能跟踪某个请求是如何从一个微服务传递到下一个. 如果你有使用AOP拦截Servlet的经验,做一个基于AOP的简单服务统计和跟踪很容易.但要像Zipkin那样能够跟踪服务调用链就比较困难了.所谓调用