栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Cloud之-Spring Cloud Sleuth分布式请求链路跟踪- 16(个人笔记)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Cloud之-Spring Cloud Sleuth分布式请求链路跟踪- 16(个人笔记)

1、概述

在微服务框架中,一个客户端请求,从发起到后端系统中,会经历多个不同的微服务结点的调用,每一个请求都会形成一条复杂的分布式调用链路,链路中任何一个服务出现故障或延时都会导致整个请求最终的失败。

Spring Cloud Sleuth提供了一套完整的服务监控跟踪解决方案,兼容支持Zipkin数据展现。

2、搭建链路监控步骤 2-1、安装Zipkin

Spring Cloud从F版起就不需要自己构建Zipkin Server了,只需要调用jar包即可,Java环境JRE 8起。

2-1-1、linux或者macOS

在终端执行:curl -sSL https://zipkin.io/quickstart.sh | bash -s可以下载zipkin最新的jar包,下载后可执行java -jar zipkin.jar直接运行,再访问http://localhost:9411/zipkin/查看管理后台。

我这里自己改过存放路径zipkin.jar包路径,所以启动时要先进入zipkin.jar包根目录cd /Users/test/documents/Maven_Repository/zipkin下,再执行java -jar zipkin.jar。

2-1-2、windows

到 https://zipkin.io/pages/quickstart.html 官网下载zipkin-server-2.12.0-exec.jar包,在进入终端切换到包的根路执行 java -jar zipkin-server-2.12.0-exec.jar

2-1-3、docker

在终端执行 docker search openzipkin 搜索出很多个zipkin的镜像,选第一个就行 openzipkin/zipkin ,然后 docker run -d -p 9411:9411 openzipkin/zipkin 就能在 http://localhost:9411/zipkin/ 对zipkin的控制台进行访问。

2-1-4、Zipkin简单介绍


上图可以看到一个请求链路中,通过Trace Id作为唯一标识,通过Span Id作为请求信息,各个Span通过Parent Id关联起来。

2-2、服务提供者

这里使用cloud-provider-payment8001模块,修改pom.xml,加入spring-cloud-starter-zipkin依赖。



    
    
        cloud2020
        com.king.springcloud
        1.0-SNAPSHOT
    

    4.0.0

    
    cloud-provider-payment8001

    
        
        
            org.springframework.cloud
            spring-cloud-starter-zipkin
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
        
            com.king.springcloud
            cloud-api-commons
            ${project.version}
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        
        
        
            com.alibaba
            druid-spring-boot-starter
        
        
        
            mysql
            mysql-connector-java
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    


cloud-provider-payment8001模块修改application.yml文件:

# 配置服务端口号
server:
  port: 8001

# 配置应用信息
spring:
  application:
    name: cloud-provider-payment # 配置应用名称
  # 配置zipkin
  zipkin:
    base-url: http://localhost:9411 # zipkin监控后台地址
  # 配置sleuth
  sleuth:
    sampler:
      probability: 1 # 采样率介于0,1之间,1表示全部采集,一般使用0.5就够了
  # 配置数据源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource # 数据源类型
    driver-class-name: com.mysql.cj.jdbc.Driver # 数据库驱动
    url: jdbc:mysql://localhost:3306/cloud_DB_2020?useUnicode=true&charcaterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai # 数据库连接
    username: root # 数据库用户名
    password: rootroot # 数据库密码

# 配置eureka
eureka:
  client:
    register-with-eureka: true # 表示将自己注册进EurekaServer
    # 表示是否从Eureka抓取已有的注册信息,默认为true,单点无所谓,集群时候,必须设置成true,才能配合Ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka # 入驻的服务地址(单机模式)
#      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 入驻的服务地址(集群模式)
  instance:
    instance-id: payment8001 # 指定服务实例id
    prefer-ip-address: true # 访问路径可以显示IP地址
    lease-renewal-interval-in-seconds: 1 # Eureka客户端向服务端发送心跳时间间隔,单位为秒,默认为30秒
    lease-expiration-duration-in-seconds: 2 # Eureka服务端在接收到最后一次心跳后等待的时间上限,单位为秒,默认是90秒,超过后,微服务将被剔除

# mybatis配置
mybatis:
    mapper-locations: classpath:mapper/*.xml # mapper文件的位置
    type-aliases-package: com.king.springcloud.entities # 所有实体类所在(别名)包

cloud-provider-payment8001模块修改控制层PaymentController.java文件:

package com.king.springcloud.controller;

import com.king.springcloud.entities.CommonResult;
import com.king.springcloud.entities.Payment;
import com.king.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.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
public class PaymentController {

    @Resource
    private PaymentService paymentService;

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

    
    @Resource
    private DiscoveryClient discoveryClient;

    @PostMapping("/payment/createPayment")
    public CommonResult createPayment(@RequestBody Payment payment){

        int result = paymentService.createPayment(payment);

        if (result > 0){
            log.info("------payment控制层------createPayment方法执行成功");
            return new CommonResult(200,"成功,执行服务器:" + serverPort, result);
        }
        log.info("------payment控制层------createPayment方法执行失败");
        return new CommonResult(500,"失败,执行服务器:" + serverPort);
    }

    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id) {

        Payment payment = paymentService.getPaymentById(id);

        if (!StringUtils.isEmpty(payment)){
            log.info("------payment控制层------getPaymentById方法执行成功.");
            return new CommonResult(200, "成功,执行服务器:" + serverPort, payment);
        }
        log.info("------payment控制层------getPaymentById方法执行失败,查询ID:{id}",id);
        return new CommonResult(500,"失败,执行服务器:" + serverPort);
    }

    @GetMapping("/payment/discovery")
    public Object discovery(){
        
        List services = discoveryClient.getServices();
        for (String element : services) {

            log.info("------element------:" + element);
            
        }

        List instances = discoveryClient.getInstances("CLOUD-PROVIDER-PAYMENT");
        for (ServiceInstance instance : instances) {

            log.info(instance.getServiceId() + "t" + instance.getHost() + "t" + instance.getPort() + "t" + instance.getUri());
        }

        return this.discoveryClient;
    }

    
    @GetMapping("/payment/loadBalance")
    public String getLoadBalancePort() {

        return serverPort;
    }

    
    @GetMapping("/payment/feign/timeout")
    public String paymentFeignTimeout() {
        try {
            // 睡眠3秒
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }

    
    @GetMapping("/payment/zipkin")
    public String paymentZipkin() {
        return "this is zipkin feedback";
    }
}
2-3、服务消费者

这里使用cloud-consumer-order80模块,修改pom.xml,同上加入spring-cloud-starter-zipkin依赖,application.yml和cloud-provider-payment8001修改方法一样。在cloud-consumer-order80模块OrderController中添加一个映射用于测试。



    
    
        cloud2020
        com.king.springcloud
        1.0-SNAPSHOT
    
    4.0.0

    
    cloud-consumer-order80

    
        
        
            org.springframework.cloud
            spring-cloud-starter-zipkin
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
        
            com.king.springcloud
            cloud-api-commons
            ${project.version}
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

cloud-consumer-order80模块的application.yml文件:

# 配置服务端口号
server:
  port: 80

# 配置应用信息
spring:
  application:
    name: cloud-consumer-order # 配置应用名称
  # 配置zipkin
  zipkin:
    base-url: http://localhost:9411 # zipkin监控后台地址
  # 配置sleuth
  sleuth:
    sampler:
      probability: 1 # 采样率介于0,1之间,1表示全部采集,一般使用0.5就够了

# 配置eureka
eureka:
  client:
    register-with-eureka: true # 表示将自己注册进EurekaServer
    # 表示是否从Eureka抓取已有的注册信息,默认为true,单点无所谓,集群时候,必须设置成true,才能配合Ribbon使用负载均衡
    fetch-registry: true
    service-url:
            defaultZone: http://localhost:7001/eureka # 入驻的服务地址(单机模式)
#      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 入驻的服务地址(集群模式)
  instance:
    instance-id: consumer-order80 # 指定服务实例id
    prefer-ip-address: true # 访问路径可以显示IP地址

cloud-consumer-order80模块的控制层OrderController.java文件:

package com.king.springcloud.controller;

import com.king.springcloud.balance.LoadBalancer;
import com.king.springcloud.entities.CommonResult;
import com.king.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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;

@Slf4j
@RestController
public class OrderController {
    
    public static final String PAYMENT_URL = "http://CLOUD-PROVIDER-PAYMENT";

    @Autowired
    private RestTemplate restTemplate;
    @Resource
    private LoadBalancer loadBalancer;
    @Autowired
    private DiscoveryClient discoveryClient;

    
    @GetMapping("/consumer/payment/create")
    public CommonResult create(Payment payment) {
        // postForObject写操作,按照JSON数据格式
        return restTemplate.postForObject(PAYMENT_URL + "/payment/createPayment", payment, CommonResult.class);
    }

    
    @GetMapping("/consumer/payment/create2")
    public CommonResult create2(Payment payment) {
        // postForEntity写操作,按照ResponseEntity数据格式
        return restTemplate.postForEntity(PAYMENT_URL + "/payment/create", payment, CommonResult.class).getBody();
    }

    
    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id) {
        // getForObject读操作,返回JSON对象
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    }

    
    @GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult getPaymentById2(@PathVariable("id") Long id) {
        // getForObject读操作,返回ResponseEntity对象包含了响应中的信息,比如响应头,响应状态码,响应体等
        ResponseEntity entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
        System.out.println("status code=" + entity.getStatusCode());
        System.out.println("headers=" + entity.getHeaders());

        // 判断请求状态是2xx
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        } else {
            return new CommonResult(404, "查找失败");
        }
    }

    
    // @GetMapping("/consumer/payment/loadBalance")
    // public String getPaymentLoadBalance() {
    //     // 通过discoveryClient对象获取服务提供者对应的应用名称大写获取所有服务实例
    //     List instances = discoveryClient.getInstances("CLOUD-PROVIDER-PAYMENT");
    //
    //     // 判断这个服务实例对象等于null或者个数等于0时直接返回null
    //     if (instances == null || instances.size() == 0) {
    //         return null;
    //     }
    //
    //     // 自定义的instances()方法拿到所有的服务实例,使用访问次数%服务实例数量求得目标服务的下标,返回下标对应的服务实例
    //     ServiceInstance instance = loadBalancer.instances(instances);
    //     URI uri = instance.getUri();// 获取这个实例的uri
    //     // /payment/loadBalance请求对应服务提供者controller中新加的映射方法,返回当前服务提供者的serverPort的值
    //     return restTemplate.getForObject(uri + "/payment/loadBalance", String.class);
    // }


    
    @GetMapping(value = "/consumer/payment/zipkin")
    public String paymentZipkin() {
        // getForObject读操作,返回JSON对象
        return restTemplate.getForObject(PAYMENT_URL + "/payment/zipkin", String.class);
    }
}
2-4、启动服务,进行测试

依次启动Eureka7001,Payment8001,Order80模块,浏览器请求http://localhost//consumer/payment/zipkin,之后返回Zipkin的管理后台,点击“查找”按钮,就可以看到刚刚请求,点进去请求,可以看到调用链路,依赖关系,调用耗时等等信息。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/319115.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号