SpringCloud —— Sleuth 分布式请求链路跟踪

前文

SpringCloud 简介

SpringCloud 版本选型

SpringCloud 工程构建

SpringCloud —— Eureka 注册中心

SpringCloud —— Eureka 集群

SpringCloud —— 服务注册进 Eureka 集群

SpringCloud —— Eureka 自我保护

SpringCloud —— SpringCloud Consul 实现服务注册中心

SpringCloud —— 三个注册中心的异同点

SpringCloud —— Ribbon

SpringCloud —— Ribbon 负载均衡算法

SpringCloud —— OpenFeign

SpringCloud —— Hystrix 简介

SpringCloud —— Hystrix 断路器

SpringCloud —— HystrixDashboard 服务监控

SpringCloud —— Gateway 网关

SpringCloud —— Config 配置中心

概述

为什么会出现这个技术?需要解决哪些问题?

在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求会形成一条复杂的分布式服务调用链路,链路中的任何一环节出现高延时或错误都会引起整个请求最后的失败
在这里插入图片描述

什么是 Sleuth ?

SpringCloud Sleuth 提供了一套完整的服务跟踪的解决方案,在分布式系统中提供追踪解决方案并且兼容支持了 zipkin

SpringCloud Sleuth GitHub 地址
在这里插入图片描述

搭建链路监控步骤

zipkin

在这里插入图片描述

下载

SpringCloud F 版开始已不需要自己构建 Zipkin Server 了,只需要调用 jar 包即可

Zipkin jar 下载地址 https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/
在这里插入图片描述
本文使用的是 2.12.9 版本

运行 jar

这是下载的 jar 包
在这里插入图片描述
运行 jar 包非常简单,只需要运行以下命令即可

java -jar zipkin.jar

在这里插入图片描述
这图案有点意思啊
在这里插入图片描述

运行控制台

运行 jar 之后就可以访问 Zipkin 的控制台了,访问地址 http://localhost:9411/zipkin/
在这里插入图片描述

服务提供者

pom.xml 依赖

<dependencies>
    <!--包含了sleuth+zipkin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    <!--eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <!--mysql-connector-java-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--jdbc-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.yml

server:
  port: 8001

spring:
  application:
    name: demo-provider-payment
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      # 采样率值介于 0 到 1 之间,则表示全部采集
      probability: 1
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource      # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver          # MySQL 驱动包
    url: jdbc:mysql://localhost:3306/数据库名?useSSL=false
    username: 用户名
    password: 密码

eureka:
  client:
    # 表示是否将自己注册进 EurekaServer 默认为 true
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息,默认为 true,单节点无所谓,集群必须设置为 true 才能配合 Ribbon 使用负载均衡
    fetchRegistry: true
    service-url:
      # 注册地址
      # defaultZone: http://localhost:7001/eureka
      # 集群版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
  instance:
    instance-id: payment8001
    perfer-ip-address: true
  server:
    # 关闭自我保护机制,保证不可用服务被及时剔除
    enable-self-preservation: false


mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.java.springcloud.entity   # 所有 entity 别名类所在包

主要新增以下配置
在这里插入图片描述

业务类

package com.java.springcloud.controller;

import com.java.springcloud.entity.CommonResult;
import com.java.springcloud.entity.Payment;
import com.java.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * @author Woo_home
 * @create 2020/3/24 12:11
 */

@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    @Resource
    private DiscoveryClient discoveryClient;

    @Value("${server.port}")
    private String serverPort;

    private Logger logger = Logger.getLogger("log");

    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = paymentService.create(payment);
        logger.info("***** 插入结果 :" + result);
        if (result > 0) {
            return new CommonResult(200,"插入数据库成功,serverPort: " + serverPort,result);
        } else {
            return new CommonResult(404,"插入数据失败",null);
        }
    }


    @GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);
        logger.info("***** 查询结果 :" + payment + " " +serverPort);

        // 如果不为 null 表示有数据,查询成功
        if (payment != null) {
            return new CommonResult(200,"查询成功,serverPort:" + serverPort,payment);
        } else {
            return new CommonResult(404,"没有对应记录,查询ID:" + id,null);
        }
    }

    @GetMapping(value = "/payment/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            logger.info("******element: " + service);
        }

        List<ServiceInstance> instances = discoveryClient.getInstances("DEMO-PROVIDER-PAYMENT");
        for (ServiceInstance instance : instances) {
            logger.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }

        return this.discoveryClient;
    }

    @GetMapping(value = "/payment/lb")
    public String getPaymentLB() {
        return serverPort;
    }

    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout() {
        // 暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }

    @GetMapping("/payment/zipkin")
    public String paymentZipkin() {
        return "hi, i am payment zipkin server fall back, welcome to Woo_home 哈哈";
    }
}

主要新增以下代码
在这里插入图片描述

服务消费者(调用方)

pom.xml 依赖

<dependencies>
   <!--包含了sleuth+zipkin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.yml

server:
  port: 80

spring:
  application:
    # 服务名称
    name: demo-order-service
  zipkin:
    base-url: http://localhost:9411
    sleuth:
      sampler:
        # 采样率值介于 0 到 1 之间,则表示全部采集
        probability: 1


eureka:
  client:
    # 表示是否将自己注册进 EurekaServer 默认为 true
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 Ribbon 使用负载均衡
    fetch-registry: true
    service-url:
      # 注册地址
      # defaultZone: http://localhost:7001/eureka
      # 集群版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

主要新增以下配置
在这里插入图片描述

业务类

package com.java.springcloud.controller;

import com.java.springcloud.entity.CommonResult;
import com.java.springcloud.entity.Payment;
import com.java.springcloud.lb.LoadBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
import java.util.List;

/**
 * @author Woo_home
 * @create 2020/3/24 14:11
 */

@RestController
@Slf4j
public class OrderController {

    //public static final String PAYMENT_URL = "http://localhost:8001";
    public static final String PAYMENT_URL = "http://DEMO-PROVIDER-PAYMENT";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DiscoveryClient discoveryClient;

    // 引入自定义的负载均衡算法
    @Resource
    private LoadBalancer loadBalancer;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id,CommonResult.class);
    }

    @GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
        ResponseEntity<CommonResult> forEntity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
        if (forEntity.getStatusCode().is2xxSuccessful()) {
            return forEntity.getBody();
        } else {
            return new CommonResult<>(404,"操作失败");
        }
    }

    @GetMapping("/consumer/payment/postForEntity/create")
    public CommonResult<Payment> create2(Payment payment) {
        return restTemplate.postForEntity(PAYMENT_URL + "/payment/create", payment, CommonResult.class).getBody();
    }

    @GetMapping(value = "/consumer/payment/lb")
    public String getPaymentLB() {
        List<ServiceInstance> instances = discoveryClient.getInstances("DEMO-PROVIDER-PAYMENT");
        if (instances == null || instances.size() <= 0) {
            return null;
        }

        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        URI uri = serviceInstance.getUri();

        return restTemplate.getForObject(uri + "/payment/lb",String.class);
    }


    @GetMapping("/consumer/payment/zipkin")
    public String paymentZipkin() {
        String result = restTemplate.getForObject("http://localhost:8001" + "/payment/zipkin/", String.class);
        return result;
    }
}

主要新增以下代码
在这里插入图片描述

依次启动 7001/8001/80

在这里插入图片描述
依次启动这三个服务

测试

访问 http://localhost/consumer/payment/zipkin
在这里插入图片描述
再次刷新 zipkin 控制台的时候,就会出现两个服务名称
在这里插入图片描述
选择订单服务点击查找
在这里插入图片描述
会显示该服务响应的时长,依赖哪个服务
在这里插入图片描述
继续点击该服务进去可以查看该服务调用的链路
在这里插入图片描述
还可以查看具体的类、请求方法、地址、路径
在这里插入图片描述
在这里插入图片描述
点击依赖选项还可以对依赖进行分析
在这里插入图片描述


代码已上传至码云 代码下载地址,感兴趣的朋友可以下载运行下
在这里插入图片描述


SpringCloud 相关文章阅读

SpringCloud 简介

SpringCloud 版本选型

SpringCloud 工程构建

SpringCloud —— Eureka 注册中心

SpringCloud —— Eureka 集群

SpringCloud —— 服务注册进 Eureka 集群

SpringCloud —— Eureka 自我保护

SpringCloud —— SpringCloud Consul 实现服务注册中心

SpringCloud —— 三个注册中心的异同点

SpringCloud —— Ribbon

SpringCloud —— Ribbon 负载均衡算法

SpringCloud —— OpenFeign

SpringCloud —— Hystrix 简介

SpringCloud —— Hystrix 断路器

SpringCloud —— HystrixDashboard 服务监控

SpringCloud —— Gateway 网关

SpringCloud —— Config 配置中心

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章