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 配置中心

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