主頁 > 後端開發 > Spring Cloud(H版)女朋友看了都會的超詳細保姆級筆記!看完還不會算我輸!

Spring Cloud(H版)女朋友看了都會的超詳細保姆級筆記!看完還不會算我輸!

2021-05-03 07:27:18 後端開發

1. 微服務架構理論

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tjPWmmpo-1619837391777)(E:\學習筆記\圖片\image-20201019134302836.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LdaZgyUq-1619837391779)(E:\學習筆記\圖片\image-20201019134502724.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VXwGAeeu-1619837391780)(E:\學習筆記\圖片\image-20201019134832352.png)]



1.1. SpringCloud簡介

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Mt9XOLHL-1619837391782)(E:\學習筆記\圖片\image-20201019134723201.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RVWFRFyR-1619837391783)(E:\學習筆記\圖片\image-20201019134932544.png)]



1.2. SpringCloud技術堆疊

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6HEZhhYK-1619837391785)(E:\學習筆記\圖片\image-20201019135425161.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UuGEPEUM-1619837391785)(E:\學習筆記\圖片\image-20201019135542664.png)]




2. 環境搭建

2.1. Boot和Cloud版本選擇

  • 依賴關系:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tYDO627a-1619837391786)(E:\學習筆記\圖片\image-20201019140734313.png)]

  • 最終定型

  • Boot已經有2.2.4而且符合規范,為啥要選2.2.2?

    官網推薦



2.2. Cloud組件停更說明

  • 停更引發的 “升級慘案”

    • 停更不停用

    • 變更

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-oYTLWLND-1619837391787)(E:\學習筆記\圖片\image-20201019142526851.png)]



2.3. 父工程Project空間新建

  • 微服務Cloud整體聚合父工程Project



2.4. 父工程pom檔案

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.springcloud</groupId>
    <artifactId>cloud2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!--統一管理jar包版本-->
    <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <junit.version>4.12</junit.version>
            <lombok.version>1.18.10</lombok.version>
            <log4j.version>1.2.17</log4j.version>
            <mysql.version>5.1.47</mysql.version>
            <druid.version>1.1.16</druid.version>
            <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!--子模塊繼承之后,提供作用:鎖定版本+子module不用謝groupId和version-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </dependency>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--spring cloud 阿里巴巴-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!-- druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <!--mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!--log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>


2.5. DependencyManagerment和Dependencies

  • DependencyManagerment:

    • Maven使用dependencyManagement元素來提供了一種管理依賴版本號的方式,
    • 通常會在一個組織或者專案的最頂層的父POM中看到dependencyManagement元素
    • 使用pom.xml中的dependencyManagement元素能讓所有在子專案中參考一個依賴而不用顯式的列出版本號,Maven 會沿著父子層次向上走,直到找到一個擁有dependencyManagement元素的專案,然后它就會使用這個dependencyManagement元素中指定的版本號,
    • 這樣做的好處就是:如果有多個子專案都參考同一樣依賴,則可以避免在每個使用的子專案里都宣告一個版本號,這樣當想升級或切換到另一個版本時,只需要在頂層父容器里更新,而不需要一個一個子專案的修改﹔另外如果某個子專案需要另外的一個版本,只需要宣告version就可,
    • dependencyManagement里只是宣告依賴,并不實作引入,因此子專案需要顯示的宣告需要用的依賴,
    • 如果不在子專案中宣告依賴,是不會從父專案中繼承下來的;只有在子專案中寫了該依賴項,并且沒有指定具體版本,才會從父專案中繼承該項,并且version和scope都讀取自父pom;如果子專案中指定了版本號,那么會使用子專案中指定的jar版本,
  • 跳過單元測驗:




3. 專案初始模塊搭建

3.1 支付模塊

3.1.1 支付模塊搭建(上)

微服務模塊:

  • 建module

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ksgvtI5p-1619837391788)(E:\學習筆記\圖片\image-20201019164020294.png)]

  • 改pom

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>cloud2020</artifactId>
            <groupId>com.atguigu.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>cloud-provider-payment8081</artifactId>
    
        <dependencies>
            <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>
    
    
    </project>
    
  • 寫yml

    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource     #當前資料源操作型別
        driver-class-name: org.gjt.mm.mysql.Driver    #mysqL驅動包
        url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: 123456
    
    
    mybatis:
      mapperLocations:  classpath:mapper/*.xml
      type-aliases-package: com.atguigu.springcloud.entities   #所有Entity別名類所在包
    
  • 主啟動類

    package com.atguigu.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class,args);
        }
    }
    
  • 業務類



3.1.2 支付模塊搭建(中)

業務類:

  • 建表sql

    CREATE TABLE `payment`(
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
    `serial` VARCHAR(200) DEFAULT '',
    PRIMARY KEY (`id`)
    )ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
    
  • entities

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nXFF5eN3-1619837391789)(E:\學習筆記\圖片\image-20201019195441201.png)]

    package com.atguigu.springcloud.entities;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CommonResult<T> {
        private Integer code;
        private String message;
        private T date;
    
        public CommonResult(Integer code,String message){
            this(code,message,null);
        }
    }
    
  • dao

    • 介面PaymentDao

      public int add(Payment payment);
      public Payment getPaymentById(@Param("id") Long id);
      
    • mybatis映射檔案PaymentMapper.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.atguigu.springcloud.dao.PaymentDao">
          
          <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
              insert into payment(serial) values(#{serial});
          </insert>
          
          <resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment">
              <id column="id" property="id" jdbcType="BIGINT"/>
              <id column="serial" property="serial" jdbcType="VARCHAR"/>
          </resultMap>
          <select id="getPaymentById" parameterType="Long" resultType="BaseResultMap">
              select * from payment where id=#{id};
          </select>
          
      </mapper>
      
  • service

     public interface PaymentService {
         public int add(Payment payment);
         public Payment getPaymentById(@Param("id") Long id);
     }
    
     @Service
     public class PaymentServiceImpl implements PaymentService {
         @Resource
         private PaymentDao paymentDao;
    
         public int add(Payment payment){
             return paymentDao.add(payment);
         }
         public Payment getPaymentById(@Param("id") Long id){
             return paymentDao.getPaymentById(id);
         }
     }
    
  • controller

    @RestController
        @Slf4j
        public class PaymentController {
            @Resource
            private PaymentService paymentService;
    
            @PostMapping(value="/payment/create")
            public CommonResult create(Payment payment){
                int result=paymentService.add(payment);
                log.info("******插入結果:"+result);
                if(result>0){
                    return new CommonResult(200,"插入資料庫成功",result);
                }else {
                    return new CommonResult(444,"插入資料庫失敗",null);
                }
            }
    
            @GetMapping(value="/payment/get/{id}")
            public CommonResult getPaymentById(@PathVariable("id") Long id){
                Payment payment = paymentService.getPaymentById(id);
                log.info("******插入結果:"+payment);
                if(payment!=null){
                    return new CommonResult(200,"查詢成功",payment);
                }else {
                    return new CommonResult(444,"沒有對應記錄,查詢ID:"+id,null);
                }
            }
        }
    


3.1.3. 支付模塊搭建(下)

  • 測驗:

    • 瀏覽器對Post請求不支持測驗,需要用Postman
    • 需要自測通過
  • 總結:

    • 建module
    • 改pom
    • 寫yml
    • 主啟動類
    • 業務類


3.2. 熱部署Devtools

  • 添加devtools依賴

     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId	>spring-boot-devtools</artifactId>
         <scope>runtime</scope>
         <optional>true</optional>
     </dependency>
    
  • 添加插件到父類的pom.xml里面

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
  • 開啟自動編譯選項

  • 更新池

    ctrl+shift+alt+/

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NylfpnuJ-1619837391790)(E:\學習筆記\圖片\image-20201020112602081.png)]



3.3 消費者模塊

3.3.1. 消費者訂單模塊(上)

  • pom

     <?xml version="1.0" encoding="UTF-8"?>
     <project xmlns="http://maven.apache.org/POM/4.0.0"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
         <parent>
             <artifactId>cloud2020</artifactId>
             <groupId>com.atguigu.springcloud</groupId>
             <version>1.0-SNAPSHOT</version>
         </parent>
         <modelVersion>4.0.0</modelVersion>
    
         <artifactId>cloud-consumer-order80</artifactId>
    
         <dependencies>
             <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.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>
    
    
     </project>
    
  • yml

    server:  port: 80
    
  • 業務類:

    • entities

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YUC2Q0nG-1619837391790)(E:\學習筆記\圖片\image-20201020120154484.png)]

    • RestTemplate

      • RestTemplate提供了多種便捷訪問遠程Http服務的方法,是一種簡單便捷的訪問restful服務模塊類,是Spring提供的用于訪問Reset服務的客戶端模塊工具類

      • 使用:

        使用restTemplate訪問restful介面非常簡單,url:rest請求地址,requestMap:請求引數,ResponseBean.class:Http回應轉換被轉換成的物件型別,要寫一個配置類

    • controller

      @RestController
      @Slf4j
      public class OrderController {
      
          public static final String PAYMENT_URL="http://localhost:8001";
      
          @Resource
          private RestTemplate restTemplate;
      
          @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);
          }
      }
      
  • 測驗



3.3.2 消費者訂單模塊(下)

  • 在插入時候,前端顯示正確,但是資料庫中的serial卻沒有?

    • RequestBody

  • Dashboard

    • 通過修改idea的workspace.xml的方式來快速打開Run Dashboard視窗(.idea------>workspace.xml)

    • 開啟Run DashBoard



3.4. 工程重構

問題:不同模塊中有重復部分:entityes,需要進行重構

  • 新建module

  • pom依賴

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>cloud2020</artifactId>
            <groupId>com.atguigu.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>cloud-api-commons</artifactId>
    
        <dependencies>
            <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>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.1.0</version>
            </dependency>
        </dependencies>
    
    
    </project>
    
  • entities

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6EQfUUiO-1619837391791)(E:\學習筆記\圖片\image-20201020154515034.png)]

  • maven命令clean install

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pAr0l2Ez-1619837391791)(E:\學習筆記\圖片\image-20201020154744466.png)]

  • 訂單80和支付8001分別改造

    • 洗掉各自原先有的entities檔案夾

    • 各自粘貼POM內容

      <dependency>    <!--引入自己定義的API通用包-->
          <groupId>com.atguigu.springcloud</groupId>
          <artifactId>cloud-api-commons</artifactId>
          <version>${project.version}</version>
      </dependency>
      



4. Eurake

4.1. Eureka基礎知識

  • 什么是服務治理?

    Spring Cloud封裝了Netflix公司開發的Eureka模塊來實作服務治理

    在傳統的rpc遠程呼叫框架中,管理每個服務與服務之間依賴關系比較復雜,管理比較復雜,所以需要使用服務治理,管理服務與服務之間依賴關系,可以實作服務呼叫、負載均衡、容錯等,實作服務發現與注冊,

  • 什么是服務注冊?

    Eureka采用了CS的設計架構,Eureka erver作為服務注冊功能的服務器,它是服務注冊中心,而系統中的其他微服務,使用Eureka的客戶端連接到Eureka Server并維持心跳連接,這樣系統的維護人員就可以通過Eureka Server來監控系統中各個微服務是否正常運行,

    在服務注冊與發現中,有一個注冊中心,當服務器啟動的時候,會把當前自己服務器的資訊比加服務地址通訊地址等以別名方式注冊到注冊中心上,另一方(消費者服務提供者),以該別名的方式去注冊中心上獲取到實際的服務通訊地址,然后再實作本地RPC呼叫

    RPC遠程呼叫框架核心設計思想在于注冊中心,因為使用注冊中心管理每個服務與服務之間的一個依賴關系(服務治理概念),在任何rpc遠程框架中,都會有一個注冊中心(存放服務地址相關資訊(介面地址)

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qTUnIIYk-1619837391792)(E:\學習筆記\圖片\image-20201020161208165.png)]

  • Eureka兩組件:

    • Eureka Serve:提供服務注冊服務

      各個微服務節點通過配置啟動后,會在Eureka Server中進行注冊,這樣Eureka Server中的服務注冊表中將會存盤所有可用服務節點的資訊,服務節點的資訊可以在界面中直觀看到,

    • Eureka Client:通過注冊中心進行訪問

      是一個Java客戶端,用于簡化Eureka Server的互動,客戶端同時也具備一個內置的、使用輪詢(round-robin)負載演算法的負載均衡器,在應用啟動后,將會向Eureka Server發送心跳(默認周期為30秒),如果Eureka Server在多個心跳周期內沒有接收到某個節點的心跳,EurekaServer將會從服務注冊表中把這個服務節點移除(默認90秒)



4.2. Eureka服務端安裝

  • Idea生成EurekaServe端服務注冊中心(物業公司)

    • 建Module

    • 改POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
      
          <artifactId>cloud-eureka-serve7001</artifactId>
      
          <dependencies>
              <!--eureka-server-->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
              </dependency>
              <!--引入自己定義的api通用包,可以使用Payment支付Entity -->
              <dependency>
              <groupId>com.atguigu.springcloud</groupId>
              <artifactId>cloud-api-commons</artifactId>
              <version>${project.version}</version>
              </dependency>
              <!--boot web actuator-->
              <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.springframework.boot</groupId>
                  <artifactId>spring-boot-devtools</artifactId>
                  <scope>runtime</scope>
                  <optional>true</optional>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
              </dependency>
      
          </dependencies>
      
      
      </project>
      
    • 寫YML

      server:
        port: 7001
      eureka:
        instance:
          hostname: localhost #eureka服務端的實體名稱
        client:
          #false表示不向注冊中心注冊自己,
          register-with-eureka: false
          #false表示自己端就是注冊中心,我的職責就是維護服務實體,并不需要去檢索服務
          fetch-registry: false
          service-url:
      #沒置與Eureka Server互動的地址查詢服務和注冊服務都需要依賴這個地址,
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      
    • 主啟動

      package com.atguigu.springcloud;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      @SpringBootApplication
      public class EurekaMain7001 {
      
          public static void main(String[] args) {
              SpringApplication.run(EurekaMain7001.class,args);
          }
      
      }
      
    • 測驗

      localhost:7001



4.3. 支持微服務8001入駐Eureka

  • 修改pom

      <!--Eureka Client-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
    
    
  • 改yml

      eureka:
          client:
          #表示是否將自己注冊進EurekaServer默認為true .
          register-with-eureka: true
          #是否從EurekaServer抓取已有的注冊資訊,默認為true,單節點無所謂,集群必須設定為true才能配合ribbon使用負戴均衡
          fetchRegistry: true
          service-url:
              defaultZone: http://localhost:7001/eureka
    
    
    
  • 修改修改8001微服務客戶端

        @SpringBootApplication
        @EnableEurekaClient
        public class PaymentMain8001 {
            public static void main(String[] args) {
                SpringApplication.run(PaymentMain8001.class,args);
            }
        }
    
  • 測驗

    • 先要啟動EurekaServer

    • 自我保護機制:

    • 注冊名:



4.4. 支持微服務80入駐Eureka

  • 改Pom

      <dependency>
          <groupId>org. springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
    
    
  • 改yml

      spring:
        application:
          name: cloud-order-service
      eureka:
        client:
               #表示是否將自己注冊進EurekaServer默認為true .
          register-with-eureka: true
              #是否從EurekaServer抓取已有的注冊資訊,默認為true,單節點無所謂,集群必須設定為true才能配合ribbon使用負裁均衡
          fetchRegistry: true
          service-url:
            defaultZone: http://localhost:7001/eureka
    
  • 修改微服務80

      @SpringBootApplication
      @EnableEurekaClient
      public class OrderMain80 {
          public static void main(String[] args) {
              SpringApplication.run(OrderMain80.class,args);
          }
      }
    
  • 測驗



4.5. Eureka集群原理說明



4.6. Eureka集群環境搭建

思想:相互注冊 相互守望

  • 新建cloud-eureka-server7002

  • POM(與上面的一樣)

  • 修改映射組態檔

    • 找到C:\Windows\System32\drivers\etc路徑下的hosts檔案

  • YML

    • 7001

      server:
        port: 7001
      eureka:
        instance:
          hostname: eureka7001.com #eureka服務端的實體名稱
        client:
          #false表示不向注冊中心注冊
          register-with-eureka: false
           #false表示自己端就是注冊中心,我的職責就是維護服務實體,并不需要去檢索服務
          fetch-registry: false
          service-url:
            defaultZone: http://eureka7002.com:7002/eureka/
      
    • 7002

      server:
        port: 7002
      eureka:
        instance:
          hostname: eureka7002.com #eureka服務端的實體名稱
        client:
          #false表示不向注冊中心注冊自己,
          register-with-eureka: false
          fetch-registry: false #false表示自己端就是注冊中心,我的職貴就是維護服務實體,并不鵬牌去檢索服務
          service-ur1:
             defaultZone:http://eureka7001.com:7001/eureka/
      
  • 主啟動(7002與7001一致)



4.7. 兩微服務注冊進集群

  • 支付服務8001發布到集群

    defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka#_集群版
    
  • 訂單服務發布到集群

    #集群版defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
    
  • 測驗

    先啟動7001,7002,再啟動8001,最后80



4.8. 支付微服務集群配置

  • 新建8002

  • POM一樣

  • 改yml(埠號)

  • 主啟動、業務類直接粘貼

  • 添加兩個支付服務的埠號區別!

  • 完成負載均衡

    • 訂單服務不可寫死

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JTXRWdV6-1619837391793)(E:\學習筆記\圖片\image-20201021192745721.png)]

    • 使用**@LoadBalanced**賦予RestTemplate負載均衡能力

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KJXZUKia-1619837391793)(E:\學習筆記\圖片\image-20201021193030686.png)]



4.9. actuator微服務資訊完整

  • 主機名稱:服務名稱的修改

  • 訪問資訊有IP顯示

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SPMWrKmX-1619837391794)(E:\學習筆記\圖片\image-20201021202543439.png)]



4.10. 服務發現Discover

  • 對于注冊進Eureka里面的微服務,可以通過服務發現來獲得該服務的資訊

  • 修改cloud-provider-payment8001的controller

      package com.atguigu.springcloud.controller;
    
      import com.atguigu.springcloud.entities.CommonResult;
      import com.atguigu.springcloud.entities.Payment;
      import com.atguigu.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;
    
    
      @Slf4j
      @RestController
      public class PaymentController {
          @Resource
          private PaymentService paymentService;
    
          @Value("${server.port}")
          private String serverPort;
    
          @Resource
          private DiscoveryClient discoveryClient;
    
          @PostMapping(value="/payment/create")
    
          public CommonResult add(@RequestBody Payment payment){
              int result=paymentService.add(payment);
              log.info("******插入結果:"+result);
              if(result>0){
                  return new CommonResult(200,"插入資料庫成功,serverPort:"+serverPort,result);
    
              }else {
                  return new CommonResult(444,"插入資料庫失敗",null);
              }
          }
    
    
          @GetMapping(value="/payment/get/{id}")
          public CommonResult getPaymentById(@PathVariable("id") Long id){
              Payment payment = paymentService.getPaymentById(id);
              log.info("******插入結果:"+payment+"哈哈哈");
              if(payment!=null){
                  return new CommonResult(200,"查詢成功,serverPort:"+serverPort,payment);
              }else {
                  return new CommonResult(444,"沒有對應記錄,查詢ID:"+id,null);
              }
          }
    
          @GetMapping(value="/payment/discovery")
          public Object discovery(){
              List<String> services = discoveryClient.getServices();
              for (String element : services) {
                  log.info("**********element:"+element);
              }
    
              List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
              for (ServiceInstance instance : instances) {
                  log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
              }
              return discoveryClient;
          }
    
    
      }
    
  • 修改主啟動類

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ajmlckII-1619837391795)(E:\學習筆記\圖片\image-20201021204632913.png)]



4.11. Eureka自我保護理論知識

  • 故障現象

    保護模式主要用于一組客戶端和Eureka Server之間存在網路磁區場景下的保護,一旦進入保護模式,
    Eureka Server將會嘗試保護其服務注冊表中的資訊,不再洗掉服務注冊表中的資料,也就是不會注銷任何微服務,

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-snxY8zso-1619837391795)(E:\學習筆記\圖片\image-20201021204851468.png)]

    一句話:某時刻某一個微服務不可用了,Eureka不會立刻清理,依舊會對該微服務的資訊進行保存,屬于CAP里面的AP分支



4.12. 禁止Eureka自我保護

  • 注冊中心7001

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hhZYcC26-1619837391797)(E:\學習筆記\圖片\image-20201021210941801.png)]

  • 客戶端

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ICMKCptS-1619837391798)(E:\學習筆記\圖片\image-20201021211257021.png)]

  • 測驗

    • 7001,8001配置
    • 先啟動7001,再啟動8001
    • 關閉8001



5. Zookeeper

5.1. 支付微服務入駐Zookeeper

  • zookeeper是一個分布式協調工具,可以實作注冊中心功能

  • 新建8004

  • POM(必須與本機安裝的Zookeeper版本號一致)

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-provider-payment8004</artifactId>
    
          <dependencies>
              <dependency>    <!--引入自己定義的API通用包-->
                  <groupId>com.atguigu.springcloud</groupId>
                  <artifactId>cloud-api-commons</artifactId>
                  <version>${project.version}</version>
              </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.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>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
                  <exclusions>
                      <exclusion>
                          <groupId>org.apache.zookeeper</groupId>
                          <artifactId>zookeeper</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
              <dependency>
                  <groupId>org.apache.zookeeper</groupId>
                  <artifactId>zookeeper</artifactId>
                  <version>3.4.10</version>
              </dependency>
          </dependencies>
      </project>
    
  • YML

      #8004表示注冊到zookeeper服務器的支付服務提供者埠號
      server :
        port: 8004
      #服務別名----注冊zookeeper.到注冊中心名稱
      spring:
        application:
          name: cloud- provider- payment
        cloud:
          zookeeper :
            connect-string: 10.98.12.226:2181
    
  • 主啟動類

      package com.atguigu.springcloud;
    
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
      @SpringBootApplication
      @EnableDiscoveryClient
      public class PaymentMain8004 {
          public static void main(String[] args) {
              SpringApplication.run(PaymentMain8004.class,args);
          }
      }
    
  • Controller

      package com.atguigu.springcloud.controller;
    
    
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
    
      import java.util.UUID;
    
      @RestController
      @Slf4j
      public class PaymentController {
          @Value("${server.port}")
          private String serverPort;
          @RequestMapping(value = "/payment/zk")
          public String paymentzk(){
              return "springcloud with zookeeper: " +serverPort+"\t"+ UUID.randomUUID().toString();
          }
    
      }
    
  • 測驗



5.2. 臨時節點和持久節點

結論:臨時節點

程序:停止了8004工程之后,會保留一段時間,然后再清除服務



5.3. 訂單微服務入駐Zookeeper

  • 新建order80

  • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-consumerzk-order80</artifactId>
          <dependencies>
              <dependency>    <!--引入自己定義的API通用包-->
                  <groupId>com.atguigu.springcloud</groupId>
                  <artifactId>cloud-api-commons</artifactId>
                  <version>${project.version}</version>
              </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.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>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
                  <exclusions>
                      <exclusion>
                          <groupId>org.apache.zookeeper</groupId>
                          <artifactId>zookeeper</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
              <dependency>
                  <groupId>org.apache.zookeeper</groupId>
                  <artifactId>zookeeper</artifactId>
                  <version>3.4.10</version>
              </dependency>
          </dependencies>
    
      </project>
    
  • YML

      server:
        port: 80
      spring:
        application:
          name: cloud-consumer-order
        cloud:
      #注冊到zookeeper地址
          zookeeper:
            connect-string: 10.98.12.226:2181
    
  • 主啟動

      package com.atguigu.springcloud;
    
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
      @SpringBootApplication
      @EnableDiscoveryClient
      public class OrderZKMain80 {
          public static void main(String[] args) {
              SpringApplication.run(OrderZKMain80.class,args);
          }
      }
    
  • Controller

      package com.atguigu.config;
    
      import org.springframework.cloud.client.loadbalancer.LoadBalanced;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.client.RestTemplate;
    
      @Configuration
      public class ApplicationContextConfig {
          @Bean
          @LoadBalanced
          public RestTemplate getRestTemp(){
              return new RestTemplate();
          }
      }
    
      package com.atguigu.controller;
    
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;
      import org.springframework.web.client.RestTemplate;
    
      import javax.annotation.Resource;
    
      @RestController
      @Slf4j
      public class OrderZKController {
          public static final String INVOKE_URL="http://cloud-provider-payment";
    
          @Resource
          private RestTemplate restTemplate;
    
          @GetMapping(value = "/consumer/payment/zk")
          public String paymentInfo(){
              String result=restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
              return result;
          }
      }
    



6. Consul

6.1. Consul概述及安裝

  • Consul是一套開源的分布式服務發現和配置管理系統,由HashiCorp公司用Go語言開發,

  • 提供了微服務系統中的服務治理、配置中心、控制總線等功能,這些功能中的每一個都可以根據需要單獨使用,也可以一起使用以構

    建全方位的服務網格,總之Consul提供了一種完整的服務網格解決方案,

  • 它具有很多優點,包括:基于raft協議,比較簡潔;支持健康檢查,同時支持HTTP和DNS協議支持跨資料中心的WAN集群提供圖形界面跨

    平臺,支持Linux、Mac、Windows

  • 能干嘛?

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-n8OBZ4DH-1619837391799)(E:\學習筆記\圖片\image-20201023212657227.png)]

安裝之后一定要將consul.exe的目錄配置到環境變數中 :

  • 使用開發模式啟動:



6.2. 服務提供者注冊進Consul

  • 新建8006

  • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-providerconsul-payment8006</artifactId>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-consul-discovery</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.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>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
          </dependencies>
    
      </project>
    
  • YML

      ##consuL服務埠號
      server:
        port: 8006
    
      spring:
        application:
          name: consul-provider-payment
        ####consuL注冊中心地址
        cloud:
          consul:
            host: localhost
            port: 8500
            discovery:
        #hostname: 127.0.0.1
              service-name: ${spring.application.name}
    
  • 主啟動類

  • 業務類

      package com.atguigu.controller;
    
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
    
      import java.util.UUID;
    
      @RestController
      @Slf4j
      public class PaymentController {
          @Value("${server.port}")
          private String serverPort;
          @RequestMapping(value = "/payment/consul")
          public String paymentConsul(){
              return "springcloud with consul: " +serverPort+"\t"+ UUID.randomUUID().toString();
          }
      }
    
  • 測驗



6.3. 消費者注冊進Consul

  • 新建Moduleorder80

  • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-consumerconsul-order80</artifactId>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-consul-discovery</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.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>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
          </dependencies>
    
      </project>
    
  • YML

      #轉#consuL服務埠號
      server:
        port: 80
      spring:
        application:
          name: cloud-consumer-order
      ##非非consuL注冊中心地址
        cloud:
          consul:
            host: localhost
            port: 8500
            discovery:
      #hostname: 127.0.0.1
              service-name: ${spring.application.name}
    
  • 主啟動類

  • 配置Bean

      package com.atguigu.springcloud.config;
    
      import org.springframework.cloud.client.loadbalancer.LoadBalanced;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.client.RestTemplate;
    
      @Configuration
      public class ApplicationContextConfig {
          @Bean
          @LoadBalanced
          public RestTemplate getRestTemplate(){
              return new RestTemplate();
          }
      }
    
  • Controller

      package com.atguigu.springcloud.controller;
    
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.client.RestTemplate;
    
      import javax.annotation.Resource;
    
      public class OrderConsulController {
          public static final String INVOKE_URL="http://consul-provider-payment";
    
          @Resource
          private RestTemplate restTemplate;
    
          @GetMapping(value = "/consumer/payment/consul")
          public String paymentInfo(){
              String result=restTemplate.getForObject(INVOKE_URL+"payment/consul",String.class);
              return result;
          }
      }
    
  • 測驗



6.4. 三個注冊中心的異同

組件名語言CAP服務健康檢查對外暴露介面Spring Cloud集成
EurekaJavaAP可配支持HTTP已集成
ConsulGoCP支持HTTP/DNS已集成
ZookeeperJavaCP支持客戶端已集成
  • CAP

    • C:Consistency(強一致性)
      A:Availability 可用性)
      P:Partition tolerance(磁區容錯性)

      CAP理論關注粒度是資料,而不是整體系統設計的策略

    • 最多只能同時較好的滿足兩個,

      CAP理論的核心是:一個分布式系統不可能同時很好的滿足一致性,可用性和磁區容錯性這三個需求,因此,根據CAР原理將NoSQL資料庫分成了滿足CA原則、滿足CP原則和滿足AP原則三大類:

CP:滿足一致性,磁區容錯性的系統,通常性能不是特別高,

AP:滿足可用性,磁區容錯性的系統,通常可能對—致性要求低一些

CA:單點集群,滿足—致性,可用性的系統,通常在可擴展性上不太強大:




7. Ribbon

7.1. 概述

  • Spring Cloud Ribbon是基于Netflix Ribbon實作的一套客戶端負載均衡的工具,

  • 簡單的說,Ribbon是Netflix發布的開源專案,主要功能是提供客戶端的軟體負載均衡演算法和服務呼叫,Ribbon客戶端組件提供一系列完善的配置項如連接超時,重試等,簡單的說,就是在組態檔中列出Load Balancer(簡稱LB)后面所有的機器,Ribbon會自動的幫助你基于某種規則(如簡單輪詢,隨機連接等)去連接這些機器,我們很容易使用Ribbon實作自定義的負載均衡演算法,

  • 能干嘛?

    • LB(負載均衡)
  • 一句話:負載均衡+RestTemplate呼叫

  • LB(負載均衡)

    • 簡單的說就是將用戶的請求平攤的分配到多個服務上,從而達到系統的HA(高可用),常見的負載均衡有軟體Nginx,LVS,硬體F5等,

    • Ribbon本地負載均衡客戶端VS Nginx服務端負載均衡區別:

      • Nginx是服務器負載均衡,客戶端所有請求都會交給nginx,然后由nginx實作轉發請求,即負載均衡是由服務端實作的,
      • Ribbon本地負載均衡,在呼叫微服務介面時候,會在注冊中心上獲取注冊資訊服務串列之后快取到JVM本地,從而在本地實作RPC遠程服務呼叫技術
    • 集中式LB:

      即在服務的消費方和提供方之間使用獨立的LB設施(可以是硬體,如F5,也可以是軟體,如nginx),由該設施負責把訪問請求通過某種策略轉發至服務的提供方

    • 行程內LB:

      將LB邏輯集成到消費方,消費方從服務注冊中心獲知有哪些地址可用,然后自己再從這些地址中選擇出一個合適的服務器,Ribbon就屬于行程內LB,它只是一個類別庫,集成于消費方行程,消費方通過它來獲取到服務提供方的地址,



7.2 Ribbon演示

  • Ribbon其實就是一個軟負載均衡的客戶端組件,他可以和其他所需請求的客戶端結合使用,和eureka結合只是其中的一個實體,

  • Ribbon在作業時分成兩步:
    其中Ribbon提供了多種策略:比如輪詢、隨機和根據回應時間加權,

    • 第一步先選擇EurekaServer ,它優先選擇在同一個區域內負載較少的server.
    • 第二步再根據用戶指定的策略,在從server取到的服務注冊串列中選擇一個地址
  • 在新版的Eurake的jar包中已經整合了Ribbon!

  • RestTemplate

    • getForObject方法/getForEntity方法

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cCKNNj4A-1619837391800)(E:\學習筆記\圖片\image-20201026153328814.png)]

    • postForObject方法/postForEntity方法

    • post方法

    • get方法



7.3 Ribbon核心組件IRule

  • IRule:根據特定演算法中從服務串列中選取一個要訪問的服務

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7efCcNz5-1619837391800)(E:\學習筆記\圖片\image-20201026155245168.png)]

  • 如何替換當前的負載規則?----- 修改order80

    • 注意配置細節

    • 新建package

    • 新建MySelfRule規則

      package com.atguigu.myrule;
      
      import com.netflix.loadbalancer.IRule;
      import com.netflix.loadbalancer.RandomRule;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      public class MySelfRule {
          @Bean
          public IRule myRule(){
              return new RandomRule(); //定義為隨機
          }
      }
      
    • 主啟動類添加@RibbonClient

    • 測驗



7.4 默認負載輪詢演算法原理

  • 原理

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Idh5CBbr-1619837391801)(E:\學習筆記\圖片\image-20201026161055399.png)]

  • 原始碼分析(下標+cas+自旋鎖)

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jrZYlSgV-1619837391801)(E:\學習筆記\圖片\image-20201026162227396.png)]




8. OpenFeign

8.1 概述

  • Feign是一個宣告式WebService客戶端,使用Feign能讓撰寫Web Service客戶端更加簡單,

  • 它的使用方法是定義一個服務介面然后在上面添加注解,Feign也支持可拔插式的編碼器和解碼器,Spring Cloud對Feign進行了封裝,使其支持了Spring MVC標準注解和HttpMessageConverters,Feign可以與Eureka和Ribbon組合使用以支持負載均衡

  • 能干嘛?

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qPVqoUsV-1619837391802)(E:\學習筆記\圖片\image-20201026164658540.png)]

  • Feign和OpenFeign的區別

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FbsIdHvk-1619837391803)(E:\學習筆記\圖片\image-20201026165100732.png)]



8.2 使用步驟

  • 介面+注解:微服務呼叫介面+@FeignClient

  • 新建order80

  • pom

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-consumer-feign-order80</artifactId>
          <dependencies>
    
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-openfeign</artifactId>
              </dependency>
    
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
              </dependency>
    
              <dependency>    <!--引入自己定義的API通用包-->
                  <groupId>com.atguigu.springcloud</groupId>
                  <artifactId>cloud-api-commons</artifactId>
                  <version>${project.version}</version>
              </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.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>
    
      </project>
    
  • YML

      server:
        port: 80
    
      eureka:
        client:
          register-with-eureka: false
          service-url:
            defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
    
  • 主啟動類

      package com.atguigu.springcloud;
    
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.openfeign.EnableFeignClients;
    
      @SpringBootApplication
      @EnableFeignClients
      //@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
      public class OrderFeignMain80 {
          public static void main(String[] args) {
              SpringApplication.run(OrderFeignMain80.class,args);
          }
      }
    
  • 業務類

      package com.atguigu.springcloud.service;
    
      import com.atguigu.springcloud.entities.CommonResult;
      import com.atguigu.springcloud.entities.Payment;
      import org.springframework.cache.annotation.Cacheable;
      import org.springframework.cloud.openfeign.EnableFeignClients;
      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.stereotype.Component;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
    
      @Component
      @FeignClient(value = "CLOUD-PAYMENT-SERVICE")
      public interface PaymentFeignService {
          @GetMapping(value="/payment/get/{id}")
          public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
      }
    
      package com.atguigu.springcloud.controller;
    
      import com.atguigu.springcloud.entities.CommonResult;
      import com.atguigu.springcloud.entities.Payment;
      import com.atguigu.springcloud.service.PaymentFeignService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RestController;
    
      import javax.annotation.Resource;
    
      @RestController
      @Slf4j
      public class OrderFeignController {
    
          @Resource
          private PaymentFeignService paymentFeignService;
    
          @GetMapping(value="/consumer/payment/get/{id}")
          public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
              return paymentFeignService.getPaymentById(id);
          }
      }
    


8.3 OpenFeign超時控制

  • 超時設定,故意設定超時演示出錯

    • 8001寫暫停程式

      @GetMapping(value = "/payment/feign/timeout")
      public String paymentFeignTimeout(){
          try {
              TimeUnit.SECONDS.sleep(3);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          return serverPort;
      }
      
    • 80添加超時方法PaymentFeignService

      @GetMapping(value = "/payment/feign/timeout")
      public String paymentFeignTimeout();
      
    • 80添加超時方法OrderFeignController

      @GetMapping(value = "consumer/payment/feign/timeout")
      public String paymentFeignTimeout(){
          //openfeign-ribbon 客戶端消費者一般默認等待1s
          return paymentFeignService.paymentFeignTimeout();
      }
      
    • 測驗

      報錯,時間超時!(OpenFeign默認只等待1s,等不到就報錯)

  • 開啟OpenFeign客戶端超時控制

      server:
        port: 80
    
      spring:
        application:
          name: cloud-order-service
      eureka:
        client:
          register-with-eureka: false
          fetchRegistry: true
          service-url:
            defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
    
      #沒置feign客戶端超時時間(OpenFeign默認支持ribbon)
      ribbon:
        #指的是建立連接所用的時間,適用于網路狀況正常的情況下,兩端連接所用的時間
        ConnectTimeout: 5000
        #指的是逮立連接后從服務器瀆取到可用資源所用的既間
        ReadTimeout: 5000
    


8.4 OpenFeign日志列印功能

  • Feign 提供了日志列印功能,我們可以通過配置來調整日志級別,從而了解Feign中Http請求的細節,說白了就是對Feign介面的呼叫情況進行監控和輸出

  • 日志級別:

    • NONE:默認的,不顯示任何日志;
    • BASIC:僅記錄請求方法、URL、回應狀態碼及執行時間;
    • HEADERS:除了BASIC中定義的資訊之外,還有請求和回應的頭資訊;
    • FULL:除了HEADERS中定義的資訊之外,還有請求和回應的正文及元資料,
  • 配置日志bean

      package com.atguigu.springcloud.config;
    
      import feign.Logger;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
    
    
    
      @Configuration
      public class FeignConfig {
          @Bean
          Logger.Level feignLoggerLevel(){
              return Logger.Level.FULL;
          }
      }
    
  • YML檔案中開啟日志的Feign客戶端




9. Hystrix

9.1 概述

  • Hystrix是一個用于處理分布式系統的延遲和容錯的開源庫,在分布式系統里,許多依賴不可避免的會呼叫失敗,比如超時、例外等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分布式系統的彈性,
  • "斷路器”本身是一種開關裝置,當某個服務單元發生故障之后,通過斷路器的故障監控(類似熔斷保險絲),向呼叫方回傳一個符合預期的、可處理的備選回應(FallBack),而不是長時間的等待或者拋出呼叫方無法處理的例外,這樣就保證了服務呼叫方的執行緒不會被長時間、不必要地占用,從而避免了故障在分布式系統中的蔓延,乃至雪崩,


9.2 概念

  • 服務降級:服務器忙,請稍后再試,不讓客戶端等待并且立刻回傳一個友好提示,fallback

    • 哪些情況會出現服務降級?
      • 程式運行例外
      • 超時
      • 服務熔斷
      • 執行緒池/信號量打滿
  • 服務熔斷:類比保險絲達到最大服務訪問后,直接拒絕訪問,拉閘限電,然后呼叫服務降級的方式并回傳友好提示(保險絲)

  • 服務限流:秒殺高并發等操作,嚴禁一窩蜂地擁擠,大家排隊,一秒鐘N個,有序進行



9.3 支付微服務搭建

  • 構建:

    • 7001改pom,守望自己

    • 新建熔斷的8001

    • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
      
          <artifactId>cloud-provider-hystrix-payment8001</artifactId>
          <dependencies>
      
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
              </dependency>
      
      
              <!--Eureka Client-->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
              </dependency>
      
      
              <dependency>    <!--引入自己定義的API通用包-->
                  <groupId>com.atguigu.springcloud</groupId>
                  <artifactId>cloud-api-commons</artifactId>
                  <version>${project.version}</version>
              </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>
      
      </project>
      
    • YML

      server:
        port: 8001
      spring:
        application:
          name: cloud-provider-hystrix-payment
      eureka:
        client:
          register-with-eureka: true
          fetch-registry: true
          service-url:
            #defaultZone: http://eureka7001.com:7001/eureka, http:/ /eureka7002.com:7002/eureka
            defaultzone:http://eureka7001.com:7001/eureka
      
    • 主啟動

    • 業務類

      package com.atguigu.springcloud.controller;
      
      import com.atguigu.springcloud.service.PaymentService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RestController;
      
      import javax.annotation.Resource;
      
      @RestController
      @Slf4j
      public class PaymentController {
          @Resource
          private PaymentService paymentService;
      
          @Value("${server.port}")
          private String servePort;
      
          @GetMapping("/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id){
              String result = paymentService.paymentInfo_OK(id);
              log.info("*********result"+result);
              return result;
          }
      
          @GetMapping("/payment/hystrix/timeout/{id}")
          public String paymentInfo_TIMEOUT(@PathVariable("id") Integer id){
              String result = paymentService.paymentInfo_TIMEOUT(id);
              log.info("*********result"+result);
              return result;
          }
      }
      
      package com.atguigu.springcloud.service;
      
      import org.springframework.stereotype.Service;
      
      import java.util.concurrent.TimeUnit;
      
      @Service
      public class PaymentService {
          public String paymentInfo_OK(Integer id){
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_OK,id:"+id+"\t"+"哈哈";
          }
      
          public String paymentInfo_TIMEOUT(Integer id){
              int timeNumber=3;
              try {
                  TimeUnit.SECONDS.sleep(3);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_TIMEOUT,id:"+id+"\t"+"哈哈"+"耗時s"+timeNumber;
          }
      }
      


9.4 高并發測驗后卡頓

  • Jmeter壓測測驗:20000個并發訪問paymentInfo_timeout
    • 結果:兩個都在轉圈圈,被卡死
    • 原因:Tomcat的默認作業執行緒數被打滿了,沒有多余的執行緒來分解壓力和處理
    • 結論:自測都很慢,如果消費者也來訪問,只能干等,最終80不滿意,8001直接被拖死


9.5 訂單微服務呼叫支付服務

  • 新建

  • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-consumer-hystrix-order80</artifactId>
    
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
              </dependency>
    
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-openfeign</artifactId>
              </dependency>
    
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-netflix-hystrix</artifactId>
              </dependency>
    
    
    
    
              <dependency>    <!--引入自己定義的API通用包-->
                  <groupId>com.atguigu.springcloud</groupId>
                  <artifactId>cloud-api-commons</artifactId>
                  <version>${project.version}</version>
              </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.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>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-netflix-eureka-client</artifactId>
              </dependency>
          </dependencies>
    
    
      </project>
    
  • YML

  • 主啟動

  • 業務類

      package com.atguigu.springcloud.service;
    
      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.stereotype.Component;
      import org.springframework.stereotype.Service;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
    
      @Component
      @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
      public interface PaymentHystrixService {
          @GetMapping("/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id);
    
          @GetMapping("/payment/hystrix/timeout/{id}")
          public String paymentInfo_TIMEOUT(@PathVariable("id") Integer id);
    
      }
    
      package com.atguigu.springcloud.controller;
    
      import com.atguigu.springcloud.service.PaymentHystrixService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RestController;
    
      import javax.annotation.Resource;
    
      @RestController
      @Slf4j
      public class OrderHystrixController {
          @Resource
          private PaymentHystrixService paymentHystrixService;
    
          @GetMapping("/consumer/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id){
              String result=paymentHystrixService.paymentInfo_OK(id);
              return result;
          }
    
          @GetMapping("/consumer/payment/hystrix/timeout/{id}")
          public String paymentInfo_TIMEOUT(@PathVariable("id") Integer id){
              String result=paymentHystrixService.paymentInfo_TIMEOUT(id);
              return result;
          }
      }
    
  • 測驗

    • 高并發情況下特別慢,有時候甚至會白頁
  • 原因:

    • 8001同一層次的其他介面服務被困死了,因為tomcat執行緒池里面的作業執行緒已經被搶占完了
    • 80此時呼叫8001,客戶端訪問緩慢,轉圈圈


9.6 降級容錯的維度要求

  • 超時導致服務器變慢(轉圈)
  • 出錯(宕機或程式運行出錯)
  • 解決
    • 8001超時了,80不能一直卡死等待,必須有服務降級
    • 對方8001宕機了,80不能一直卡死等待,必須有服務降級
    • 對方8001可以,80自己出故障或者自我要求(比方自己的等待時間小于服務提供者),自己處理降級


9.7 服務降級支付側

  • 降級配置:@HystrixCommand

  • 8001自身找問題

    • 設定自身呼叫超時時間的峰值,峰值內可以正常運行
    • 超過需要有兜底方法處理,作服務降級fallback
  • 8001fallback

    • 業務類啟用:@HystrixCommand

      package com.atguigu.springcloud.service;
      
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
      import com.netflix.ribbon.proxy.annotation.Hystrix;
      import org.springframework.stereotype.Service;
      
      import java.util.concurrent.TimeUnit;
      
      @Service
      public class PaymentService {
          public String paymentInfo_OK(Integer id){
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_OK,id:"+id+"\t"+"哈哈";
          }
      
      
          @HystrixCommand(fallbackMethod = "paymentInfo_TIMEOUTHandler",commandProperties = {
                  @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
          })
          public String paymentInfo_TIMEOUT(Integer id){
              int timeNumber=5;
              try {
                  TimeUnit.SECONDS.sleep(timeNumber);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_TIMEOUT,id:"+id+"\t"+"哈哈"+"耗時s"+timeNumber;
          }
      
          public String paymentInfo_TIMEOUTHandler(Integer id){
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_TIMEOUTHandler,id:"+id+"\t"+"o(╥﹏╥)o";
      
          }
      }
      
    • 主啟動類激活:@EnableCircuitBreaker

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EGlhmnH6-1619837391803)(E:\學習筆記\圖片\image-20201027152321380.png)]



9.8 服務降級訂單側

  • 熱部署對注解里面的屬性修改不太敏感,建議重啟

  • YML

  • 主啟動:EnableHystrix

  • 業務類

      package com.atguigu.springcloud.controller;
    
      import com.atguigu.springcloud.service.PaymentHystrixService;
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RestController;
    
      import javax.annotation.Resource;
      import java.util.concurrent.TimeUnit;
    
      @RestController
      @Slf4j
      public class OrderHystrixController {
          @Resource
          private PaymentHystrixService paymentHystrixService;
    
          @GetMapping("/consumer/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id){
              String result=paymentHystrixService.paymentInfo_OK(id);
              return result;
          }
    
          @GetMapping("/consumer/payment/hystrix/timeout/{id}")
          @HystrixCommand(fallbackMethod = "paymentInfo_TIMEOUTHandler",commandProperties = {
                  @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500 ")
          })
          public String paymentInfo_TIMEOUT(Integer id){
              String result = paymentHystrixService.paymentInfo_TIMEOUT(id);
              return result;
          }
    
          public String paymentInfo_TIMEOUTHandler(Integer id){
              return "我是消費者80,支付系統8001繁忙,請稍后再試!o(╥﹏╥)o";
    
          }
      }
    


9.9 全域服務降級DefaultProperties

問題:

  • 每個業務方法對飲一個兜底的方法,代碼膨脹
  • 統一和自定義分開

解決:

  • 代碼膨脹:@DefaultProperties(defaultFallback=" ")

    • 設定全域降級

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KSqAJLiN-1619837391804)(E:\學習筆記\圖片\image-20201027162534179.png)]

    • 兜底方法

      //全域fallback
      public String payment_Globel_FallbackMethod(){
          return "Global全域處理資訊,請稍后再試o(╥﹏╥)o";
      }
      
    • 使用兜底方法



9.10 統配服務降級FeignFallback

  • 修改order80

  • 新建一個類,實作Service介面

      package com.atguigu.springcloud.service;
    
      public class PaymentFallbackService implements PaymentHystrixService{
          @Override
          public String paymentInfo_OK(Integer id) {
              return "-----PaymentFallbackService fall back o(╥﹏╥)o";
          }
    
          @Override
          public String paymentInfo_TIMEOUT(Integer id) {
              return "------PaymentFallbackService fall back o(╥﹏╥)o";
          }
      }
    
  • YML

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nfe5FpBM-1619837391805)(E:\學習筆記\圖片\image-20201027164346626.png)]

  • Sercice介面

      package com.atguigu.springcloud.service;
    
    
      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.stereotype.Component;
      import org.springframework.stereotype.Service;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
    
      @Component
      @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
      public interface PaymentHystrixService {
          @GetMapping("/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id);
    
          @GetMapping("/payment/hystrix/timeout/{id}")
          public String paymentInfo_TIMEOUT(@PathVariable("id") Integer id);
      }
    


9.11 服務熔斷

  • 熔斷機制是應對雪崩效應的一種微服務鏈路保護機制,當扇出鏈路的某個微服務出錯不可用或者回應時間太長時,會進行服務的降級,進而熔斷該節點微服務的呼叫,快速回傳錯誤的回應資訊,

  • 當檢測到該節點微服務呼叫回應正常后,恢復呼叫鏈路

  • 在Spring Cloud框架里,熔斷機制通過Hystrix實作,Hystrix會監控微服務間呼叫的狀況

    當失敗的呼叫到一定閾值,預設是5秒內20次呼叫失敗,就會啟動熔斷機制,熔斷機制的注解是@HystrixCommand,



9.12 服務熔斷案例

  • 修改8001

  • PaymentService

      package com.atguigu.springcloud.service;
    
      import cn.hutool.core.util.IdUtil;
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
      import com.netflix.ribbon.proxy.annotation.Hystrix;
      import org.springframework.stereotype.Service;
      import org.springframework.web.bind.annotation.PathVariable;
    
      import java.util.concurrent.TimeUnit;
    
      @Service
      public class PaymentService {
          public String paymentInfo_OK(Integer id){
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_OK,id:"+id+"\t"+"哈哈";
          }
    
    
          @HystrixCommand(fallbackMethod = "paymentInfo_TIMEOUTHandler",commandProperties = {
                  @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")
          })
          public String paymentInfo_TIMEOUT(Integer id){
              int timeNumber=3;
              try {
                  TimeUnit.SECONDS.sleep(timeNumber);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              return "執行緒池:"+Thread.currentThread().getName()+" paymentInfo_TIMEOUT,id:"+id+"\t"+"哈哈"+"耗時s"+timeNumber;
          }
    
          public String paymentInfo_TIMEOUTHandler(Integer id){
              return "執行緒池:"+Thread.currentThread().getName()+" 8001系統忙,請稍后再試!id:"+id+"\t"+"o(╥﹏╥)o";
    
          }
    
          //服務熔斷
    
          @HystrixCommand(fallbackMethod= "paymentcircuitBreaker_fallback" ,commandProperties = {
                  @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),  //是否開啟斷路器
                  @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),  //請求次數
                  @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),  //時間視窗期
                  @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失敗率達到多少后跳閘
          })
          public String paymentCircuitBreaker(@PathVariable("id")Integer id){
                if(id < 0)
                  {
                      throw new RuntimeException("******id 不能負數");
                  }
                  String serialNumber = IdUtil.simpleUUID();
                  return Thread.currentThread() .getName()+"\t"+"呼叫成功,流水號:" +serialNumber;
          }
          public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
              return "id不能負數,請稍后再試,/(ToT)/~~id: " +id;
          }
      }
    
  • PaymentController

      package com.atguigu.springcloud.controller;
    
      import com.atguigu.springcloud.service.PaymentService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RestController;
    
      import javax.annotation.Resource;
      @RestController
      @Slf4j
      public class PaymentController {
          @Resource
          private PaymentService paymentService;
    
          @Value("${server.port}")
          private String servePort;
    
          @GetMapping("/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id){
              String result = paymentService.paymentInfo_OK(id);
              log.info("*********result"+result);
              return result;
          }
    
          @GetMapping("/payment/hystrix/timeout/{id}")
          public String paymentInfo_TIMEOUT(@PathVariable("id") Integer id){
              String result = paymentService.paymentInfo_TIMEOUT(id);
              log.info("*********result"+result);
              return result;
          }
    
          //服務熔斷
          @GetMapping("/payment/circuit/{id}")
          public String paymentCoircuitBreaker(@PathVariable("id") Integer id){
              String  result = paymentService.paymentCircuitBreaker(id);
              log.info("************result:"+result);
              return result;
          }
      }
    
  • 測驗

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nAPVRqOa-1619837391805)(E:\學習筆記\圖片\image-20201101195909086.png)]



9.13 總結

熔斷型別:

  • 打開:請求不再進行呼叫當前服務,內部設定時鐘一般為MTTR(平均故障處理時間),當打開時長達到所設時鐘則進入半熔斷狀態
  • 關閉:熔斷關閉不會對服務進行熔斷
  • 半開:部分請求根據規則呼叫當前服務,如果請求成功且符合規則則認為當前服務恢復正常,關閉熔斷

斷路器開啟或者關閉的條件:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3HtfcUn0-1619837391806)(E:\學習筆記\圖片\image-20201101200525906.png)]

斷路器打開之后:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-freUlAqV-1619837391806)(E:\學習筆記\圖片\image-20201101200728676.png)]

?



9.14 Hystrix作業流程

img



9.15 Dashboard搭建

9.15.1 概述

? 除了隔離依賴服務的呼叫以外,Hystrixi還提供了準實時的呼叫監控(Hystrix Dashboard),Hystrix會持續地記錄所有通過Hystrix發起的請求的執行資訊,并以統計報表和圖形的形式展示給用戶,包括每秒執行多少請求多少成功,多少失敗等,Netflix通過hystrix-metrics-event-stream專案實作了對以上指標的監控,Spring Cloud也提供了Hystrix Dashboard的整合,對監控內容轉化成可視化界面,



9.15.2 儀表盤9001

  • 新建cloud-consumer-hystrix-dashboard9001

  • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-consumer-hystrix-dashboard9001</artifactId>
    
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</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>
    
    
      </project>
    
  • YML

    server:  port: 9001
    
  • 新注解@EnableHystrixDashboard

      package com.atguigu.springcloud;
    
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
    
      @SpringBootApplication
      @EnableHystrixDashboard
      public class HystrixDashboardMain9001 {
          public static void main(String[] args) {
              SpringApplication.run(HystrixDashboardMain9001.class,args);
          }
      }
    
  • 所有Provider微服務提供類(8001,8002,8003)都需要監控依賴配置

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
    
  • 啟動9001

    訪問 http://localhost:9001/hystrix



9.15.3 監控實戰

  • 修改8001

    • 新版本Hystrix需要在主啟動類MainAppHystrix8001中指定監控路徑

      /**
       *此敲置是為了服務監控面配置,與服務容錯本身無關,springcLoud升級后的坑
       *ServletRegistrationBean因為springboot的默認路徑不是"/hystrix.stream",
       *只要在自己的專案里配置上下面的servlet就可以了
      */
          @Bean
          public ServletRegistrationBean getServlet(){
              HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
              ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
              registrationBean.setLoadOnStartup(1);
              registrationBean.addUrlMappings("/hystrix.stream");
              registrationBean.setName("HystrixMetricsStreamServlet");
              return registrationBean;
          }
      
  • 測驗:啟動一個Eurake或者3個集群

  • 觀察監控視窗:

    • 9001監控8001:填寫監控地址:http://localhost:8001/hystrix.stream

    • 測驗地址:

      • http://localhost:8001/payment/circuit/31
      • http://localhost:8001/payment/circuit/-31
      • 上述測驗通過 ok
      • 先訪問正確地址,再訪問錯誤地址,再正確地址,會發現斷路器都是慢慢放開的
    • 如何看圖?

      • 七色

        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ajELAGiv-1619837391808)(E:\學習筆記\圖片\image-20201104163257215.png)]

      • 一圈

        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5CQIjtaa-1619837391809)(E:\學習筆記\圖片\image-20201104163338229.png)]

        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9XkDk8gb-1619837391810)(E:\學習筆記\圖片\image-20201104163328904.png)]

      • 一線:用來記錄2分鐘內流量的相對變化,可以通過它來觀察到流量的上升和下降趨勢,

        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iq98yE69-1619837391810)(E:\學習筆記\圖片\image-20201104163415409.png)]

      • 整個圖說明

        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HcFx0Qk5-1619837391811)(E:\學習筆記\圖片\image-20201104163505504.png)]

      • 整個圖說明

        [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Woosko1H-1619837391812)(E:\學習筆記\圖片\image-20201104163532012.png)]




10. GateWay網關

10.1 概述

  • Cloud全家桶中有個很重要的組件就是網關,在1.x版本中都是采用的Zuul網關,但在2.x版本中,zuul的升級就一直跳票,SpringCloud最后自己研發了一個網關替代了Zuul------------SpringCloud GateWay
  • gateWay是原zuul1.x版本的替換,是在Spring生態系統之上構建的API網關服務,基于Spring5,Spirng Boot2和Project Reactor等技術
  • GateWay旨在提供一種簡單而有效的方式來對API進行路由,以及提供一些強大的過濾器功能,例如:熔斷、限流、重試等
  • SpringCloud GateWay使用的Webflux中的reactor-netty回應式編程組件,底層使用了Netty通訊框架


10.2 非阻塞異步模式

  • Spring Cloud Gateway具有如下特性:

    • 基于Spring Framework 5,Project Reactor和Spring Boot 2.0進行構建;
    • 動態路由:能夠匹配任何請求屬性;
    • 可以對路由指定Predicate(斷言)和Filter(過濾器);
    • 集成Hystrix的斷路器功能;
    • 集成Spring Cloud服務發現功能;
    • 易于撰寫的 Predicate(斷言)和Filter(過濾器);
    • 請求限流功能;
    • 支持路徑重寫,
  • SpringCloud GateWay和Zuul的區別

    • Zuul1.x基于Servlet2.5 IO模型使用阻塞架構
    • SpringCloud GateWay使用非阻塞API
  • WebFlux是什么?

    • 區別于SpringMVC,不需要依賴Servlet API,它是完全異步非阻塞的,并且基于Reactor來實作回應式流規范,


10.3 GateWay作業流程

  • 路由(Route):構建網關的基本模塊,由id,目標URI,一系列的斷言和過濾器組成,如果斷言為true,則匹配該斷言,
  • 斷言(Predicate):參考的是Java8的java.util.function.Predicate,開發人員可以匹配HTTP請求中的所有內容(例如請求頭或請求引數),如果請求與斷言相匹配則進行路由
  • 過濾(Filter):指的是Spring框架中GateWayFilter的實作,使用過濾器,可以在請求被路由前或者之后對請求進行修改

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-27TiRgv0-1619837391812)(E:\學習筆記\圖片\image-20201130112043894.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AzrHkiS6-1619837391813)(E:\學習筆記\圖片\image-20201130112116079.png)]

總結:路由轉發+執行過濾器鏈



10.4 GateWay9527搭建

  • 新建Module

  • POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud2020</artifactId>
              <groupId>com.atguigu.springcloud</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
    
          <artifactId>cloud-gateway-gateway9527</artifactId>
    
          <dependencies>
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-gateway</artifactId>
              </dependency>
    
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
              </dependency>
    
    
              <dependency>    <!--引入自己定義的API通用包-->
                  <groupId>com.atguigu.springcloud</groupId>
                  <artifactId>cloud-api-commons</artifactId>
                  <version>${project.version}</version>
              </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>
    
    
      </project>
    
  • YML

  • 業務類

  • 主啟動類

      package com.atguigu.springcloud;
    
    
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
      @SpringBootApplication
      @EnableEurekaClient
      public class GateWayMain9527 {
          public static void main(String[] args) {
              SpringApplication.run(GateWayMain9527.class,args);
          }
      }
    
  • 9527網關做路由映射

  • YML新增網關配置

      server:
        port: 9527
    
      spring:
        application:
          name: cloud-gateway
        cloud:
          gateway:
            routes:
              - id: payment_routh
                uri:  http://localhost:8081
                predicates:
                  - Path=/payment/get/**
    
              - id: payment_routh2
                uri:  http://localhost:8001
                predicates:
                  - Path=/payment/lb/**
    
      eureka:
        instance:
          hostname: cloud-gateway-service
        client: #服務提供者provider注冊進eureka服務串列內
          service-url:
            register-with-eureka: true
            fetch-registry: true
            defaultZone:  http://eureka7001.com:7001/eureka
    
  • 測驗

  • YML配置說明



10.5 配置路由的兩種方式

  1. 上述的yaml配置

  2. 代碼中注入RouteLocator的Bean:在9527新建config檔案夾配置類!

     @Configuration
     public class GateWayConfig {
         @Bean
         public RouteLocator customRouterLocator(RouteLocatorBuilder routeLocatorBuilder){
             RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
             routes.route("path_route_atguigu",
                     r->r.path("/guonei")
                             .uri("http://news.baidu.com/guonei")).build();
    
             return routes.build();
         }
     }
    

    效果:



10.6 動態路由

? 默認情況下Gateway會根據注冊中心注冊的服務劃表,以注冊中心上微服務名為路徑創建動態路由進行轉發,從而實作動態路由的功能

  1. YML:

     server:
       port: 9527
    
     spring:
       application:
         name: cloud-gateway
       cloud:
         gateway:
           discovery:
             locator:
               enabled: true         #開啟從注冊中心動態創建路由的功能,利用微服務名進行路由
           routes:
             - id: payment_routh     #路由的ID,沒有固定規則但要求唯一,建議配合服務名
               uri:  lb://cloud-payment-service     #匹配后提供服務的路由地址
               predicates:
                 - Path=/payment/get/**    #斷言,路徑相匹配的進行路由
    
    
             - id: payment_routh2      #路由的ID,沒有固定規則但要求唯一,建議配合服務名
               uri:  lb://cloud-payment-service     #匹配后提供服務的路由地址
               predicates:
                 - Path=/payment/lb/**     #創言,路徑相匹配的進行路由
    
    
     eureka:
       instance:
         hostname: cloud-gateway-service
       client: #服務提供者provider注冊進eureka服務串列內
         service-url:
           register-with-eureka: true
           fetch-registry: true
           defaultZone:  http://eureka7001.com:7001/eureka
    
    


10.7 常用的predicate

  1. After Route Predicate:

     public class Test {
         public static void main(String[] args) {
             ZonedDateTime zbj = ZonedDateTime.now();
             System.out.println(zbj);
         }
     }
    

  2. Before Route Predicate、Between Route Predicate與上面類似

  3. Cookie Route Predicate:

  4. Header Route Predicate

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Q9eS4g72-1619837391813)(E:\學習筆記\圖片\image-20210419172521954.png)]

  5. Host Route Predicate:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y1icktN2-1619837391814)(E:\學習筆記\圖片\image-20210419172638825.png)]

  6. Method Route Predicate:

  7. Path Route Predicate:

    就是 -Path

  8. Query Route Predicate:

總結

說白了,Predicate就是為了實作一組匹配規則,讓請求過來找到對應的Route進行處理,



10.8 Filter

介紹

  1. 路由器指的是Spring框架中GatewayFilter的實體,使用過濾器,可以在請求被路由前或者之后對請求進行修改,
  2. 路由過濾器可用于修改進入的HTTP請求和回傳的HTTP回應,路由過濾器只能指定路由進行使用,
  3. Spring Cloud Gateway內置了多種路由過濾器,他們都由GatewayFilter的工廠類來產生
  4. 生命周期:pre、post
  5. 種類:GatewayFilter、GlobalFilter

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2Qtr6p25-1619837391815)(E:\學習筆記\圖片\image-20210420150001605.png)]

  1. 自定義過濾器:實作兩個介面,GlobalFilter、Ordered

    能干嘛?全域日志記錄,統一網關鑒權

     @Component
     @Slf4j
     public class MyLogGateWayFilter  implements GlobalFilter, Ordered
     {
         @Override
         public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
             log.info("*******************************come in MyLogGateWayFilter:   "+new Date());
             String uname = exchange.getRequest().getQueryParams().getFirst("uname");
             if(uname == null){
                 log.info("**************用戶名為null,非法用戶,┭┮﹏┭┮");
                 exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                 return exchange.getResponse().setComplete();
             }
             return chain.filter(exchange);
         }
    
         @Override
         public int getOrder() {
             return 0;
         }
     }
    




11. Config配置中心

11.1 分布式配置中心介紹

? 微服務意味著要將單體應用中的業務拆分成一個個子服務,每個服務的粒度相對較小,因此系統中會出現大量的服務,由于每個服務都需要必要的配置資訊才能運行,所以一套集中式的、動態的配置管理設施是必不可少的,

介紹

  1. SpringCloud Config為微服務架構中的微服務提供集中化的外部配置支持,配置服務器為各個不同微服務應用的所有環境提供了一個中心化的外部配置

  2. SpringCloud Config分為服務端和客戶端兩部分,

  3. 服務端也稱為分布式配置中心,它是一個獨立的微服務應用,用來連接配置服務器并為客戶端提供獲取配置資訊,加密/解密資訊等訪問介面,

    客戶端則是通過指定的配置中心來管理應用資源,以及與業務相關的配置內容,并在啟動的時候從配置中心獲取和加載配置資訊配置服務器默認采用git來存盤配置資訊,這樣就有助于對環境配置進行版本管理,并且可以通過git客戶端工具來方便的管理和訪問配置內容



11.2 配置總控中心搭建

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2xSC65Hn-1619837391815)(E:\學習筆記\圖片\image-20210420160930035.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pLXNBrNm-1619837391816)(E:\學習筆記\圖片\image-20210420161052125.png)]

  1. POM

     <?xml version="1.0" encoding="UTF-8"?>
     <project xmlns="http://maven.apache.org/POM/4.0.0"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
         <parent>
             <artifactId>cloud2020</artifactId>
             <groupId>com.atguigu.springcloud</groupId>
             <version>1.0-SNAPSHOT</version>
         </parent>
         <modelVersion>4.0.0</modelVersion>
    
         <artifactId>cloud-config-center-3344</artifactId>
         <dependencies>
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-config-server</artifactId>
             </dependency>
             <!--eureka-server-->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
             </dependency>
             <!--boot web actuator-->
             <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.springframework.boot</groupId>
                 <artifactId>spring-boot-devtools</artifactId>
                 <scope>runtime</scope>
                 <optional>true</optional>
             </dependency>
             <dependency>
                 <groupId>org.projectlombok</groupId>
                 <artifactId>lombok</artifactId>
             </dependency>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-test</artifactId>
                 <scope>test</scope>
             </dependency>
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
             </dependency>
    
         </dependencies>
    
    
     </project>
    
  2. YML

     server:
       port: 3344
    
     spring:
       application:
         name: cloud-config-center #注冊進Eureka服務器的微服務名
       cloud:
         config:
           server:
             git:
               uri: https://github.com/lyyrhf/springcloud-config.git #GitHub上面的git倉庫名字
               ##非#搜索目錄
               search-paths:
                 - springcloud-config
               username: 448191580@qq.com
               password: ran88518
               skip-ssl-validation: true
           ####讀取分支
           label: main
    
     #服務注冊至eureka地址
     eureka:
       client:
         service-url:
           defaultZone: http://localhost:7001/eureka
    
    
    
  3. 主啟動類

     @SpringBootApplication
     @EnableConfigServer
     public class ConfigCenterMain3344 {
         public static void main(String[] args) {
             SpringApplication.run(ConfigCenterMain3344.class,args);
         }
     }
    
  4. windows下修改hosts檔案,增加映射

    127.0.0.1	config-3344.com
    
  5. 測驗通過Config微服務是否可以從GitHub上獲取配置內容:啟動3344,http://config-3344.com:3344/main/config-dev.yml

配置讀取規則

  1. /{label}/{application}-fprofile}.yml

  2. /{application}-{profile}.yml

  3. /{application}/{profile}[/{label}]

配置細節

  1. label:分支名
  2. name:服務名
  3. profile:環境(dev/test/prod)


11.3 客戶端配置與測驗

  1. 新建cloud-config-client-3355

  2. POM

  3. bootstrap.yml:applicaiton .yml是用戶級的資源配置項,bootstrap.yml是系統級的,優先級更加高

     server:
       port: 3355
     spring:
       application:
         name: config-client
       cloud:
         #Config客戶端配置
         config:
           label: main     #分支名稱
           name: config  #組態檔名稱
           profile: dev   #讀取后緞名稱
           uri: http://localhost:3344    #配置中心地址k
           #上述3個綜合:master分支上config-dev.yml的組態檔被讀取http://config-3344.com:3344/moster/config-dev.yml
     #服務注冊到eureka地址
     eureka:
       client:
         service-url:
           defau1tZone: http://localhost:7001/eureka
    
  4. 修改config-dev.yml配置并且提交到github,比如加個變數age或者版本號version

  5. 主啟動類

     @SpringBootApplication
     @EnableEurekaClient
     public class ConfigClientMain3355 {
         public static void main(String[] args) {
             SpringApplication.run(ConfigClientMain3355.class,args);
         }
     }
    
  6. 業務類

     @RestController
     public class ConfigClientController {
         @Value("${config.info}")
         private String configInfo;
    
         @GetMapping("/configInfo")
         public String getConfigInfo(){
             return configInfo;
         }
     }
    
  7. 測驗:7001,3344,3355,然后訪問http://localhost:3355/configInfo

問題:分布式的動態重繪問題



11.4 動態重繪手動版

修改3355模塊:

  1. POM引入actuator監控

     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
     </dependency>
    
  2. 修改yml,暴露監控埠

     #暴露監控埠
     management:
       endpoints:
         web:
           exposure:
             include: "*"
    
  3. @RefreshScope業務類Controller修改

     @RestController
     @RefreshScope
     public class ConfigClientController {
         @Value("${config.info}")
         private String configInfo;
    
         @GetMapping("/configInfo")
         public String getConfigInfo(){
             return configInfo;
         }
     }
    
  4. 此時修改github由2->1,發現沒生效啊!

  5. 需要運維人員發個post請求重繪3355:curl -X POST “http://localhost:3355/actuator/refresh”

新的問題:多個微服務客戶端,能否廣播,一次通知,處處生效,大范圍自動重繪?




12. bus訊息總線

12.1 概述

  1. Bus只支持兩種訊息代理,RabbitMQ和Kafka

  2. 可以實作配置的自動重繪

  3. Spring Cloud Bus能管理和傳播分布式系統間的訊息,就像一個分布式執行器,可用于廣播狀態更改、事件推送等,也可以當作微服務間的通信通道,



12.2 環境配置

  1. 安裝erlang:http://erlang.org/download/otp_win64_21.3.exe

  2. rabbitmq:https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe

  3. 進入rabbitmq安裝的sbin目錄下,命令列輸入:.\rabbitmq-plugins enable rabbitmq_management

  4. 開始目錄啟動rabbit.start,測驗是否成功:http://localhost:15672,成功進入,登錄賬號密碼均是guest



12.3 動態重繪全域廣播

環境搭建

  1. 再制作一個3366:POM、YML、Controller差不多

     @RestController
     @RefreshScope
     public class ConfigClientController {
         @Value("${server.port}")
         private String serverPort;
    
         @Value("${config.info}")
         private String configInfo;
    
         @GetMapping("/configInfo")
         public String getConfigInfo(){
             return "serverPort: "+serverPort+"\t\n\n configInfo: "+configInfo;
         }
     }
    
  2. 設計思想:

    • 利用訊息總線觸發一個客戶端/bus/refresh,而重繪所有客戶端的配置

    • 利用訊息總線觸發一個服務端ConfigServer的/bus/refresh端點,而重繪所有客戶端的配置

    • 圖二的架構顯然更加適合,圖—不適合的原因如下:

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-69vSQx9x-1619837391817)(E:\學習筆記\圖片\image-20210421153536027.png)]

實作

  1. 給cloud-config-center-3344配置中心服務端添加訊息總線支持:

    • POM:

         <!--添加訊息總線RabbitMQ支持-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-bus-amqp</artifactId>
         </dependency>
      
    • YML:

         #rabbitmq相關配置
         rabbitmq:
           host: localhost
           port: 5672
           username:guest
           password:guest
      
         #rabbitmq相關配置,暴露bus重繪配置的端扣
         management:
           endpoints:    #暴露bus重繪配置的端扣
             web:
               exposure:
                 include: 'bus-refresh'
      
  2. 給cloud-config-client-3355客戶端添加訊息總線支持:

    • POM

         <!--添加訊息總線RabbitMQ支持-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-bus-amqp</artifactId>
         </dependency>
      
    • YML

       #rabbitmq相關配置
       rabbitmq:
         host: localhost
         port: 5672
         username: guest
         password: guest
      
  3. 給cloud-config-client-3366客戶端添加訊息總線支持:跟上面3355一樣

  4. 測驗:

    • 修改github版本號,發送POST請求,一次發送,處處生效!


12.4 動態重繪定點通知

只通知3355,不通知3366:

  1. 公式: http://localhost:配置中心的埠號/actuator/bus-refresh/{destination}

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Ac844H32-1619837391818)(E:\學習筆記\圖片\image-20210421162442393.png)]




13. Stream訊息驅動

介紹

  1. 官方定義Spring Cloud Stream是一個構建訊息驅動微服務的框架,
  2. 它可以屏蔽底層訊息中間件的差異,降低切換成本,統一訊息的編程模型,

設計思想

  1. 它為什么可以統一底層差異?

    通過定義系結器Binder作為中間層實作應用程式和訊息中間件細節上的解耦隔離

  2. Binder:

    • INPUT:對應消費者

    • OUTPUT:對應生產者

    • 通信方式遵循發布-訂閱模式:Topic主題進行廣播



13.1 常用注解介紹

標準流程套路

  1. Binder:連接中間件
  2. Channel:通道,是佇列Queue的一種抽象,在訊息通訊系統中就是實作存盤和轉發的媒介,通過Channel對隊伍進行配置
  3. Source和Sink:簡單理解為輸入輸出

編碼API和常用注解



13.2 生產者

  1. 新建cloud-stream-rabbitmq-provider8801

  2. POM

     <artifactId>cloud-stream-rabbitmq-provider8801</artifactId>
         <dependencies>
             <!--添加訊息總線RabbitMQ支持-->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
             </dependency>
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-config</artifactId>
             </dependency>
             <!--eureka-server-->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
             </dependency>
             <!--boot web actuator-->
             <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.springframework.boot</groupId>
                 <artifactId>spring-boot-devtools</artifactId>
                 <scope>runtime</scope>
                 <optional>true</optional>
             </dependency>
             <dependency>
                 <groupId>org.projectlombok</groupId>
                 <artifactId>lombok</artifactId>
             </dependency>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-test</artifactId>
                 <scope>test</scope>
             </dependency>
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
             </dependency>
    
         </dependencies>
    
     </project>
    
  3. YML

     server:
       port: 8801
    
     spring:
       application:
         name: cloud-stream-provider
       cloud:
         stream:
           binders: #在此處配置要系結的rabbitmq的服務資訊;
             defaultRabbit:    #表示定義的名稱,用于丁binding整合
               type: rabbit    #訊息組件型別
               environment:    #設定rabbitmq的相關的環境配置
                 spring:
                   rabbitmq:
                     host: localhost
                     port: 5672
                     username: guest
                     password: guest
           bindings:   #服務的整合處理
             output:   #這個名字是一個通道的名稱
               destination: studyExchange    #表示要使用的Exchange名稱定義
               content-type: application/json  #設定訊息型別,本次為json,文本則設定"text/plain"
               binder: defaultRabbit   #設定要系結的訊息服務的具體設定
    
    
     eureka:
       client: #客戶端進行Eureka注冊的配置
         service-url:
           defaultZone: http://localhost:7001/eureka
       instance:
         lease-renewal-interval-in-seconds: 2        #設定心跳的時間間隔(默認是30秒)
         lease-expiration-duration-in-seconds: 5     #如果現在超過了5秒的間隔(默認是90秒
         instance-id: send-8801.com                  #在資訊串列時顯示主機名稱
         prefer-ip-address: true                     #訪問的路徑變為IP地址
    
  4. 主啟動類

     @EnableEurekaClient
     @SpringBootApplication
     public class StreamMQMain8801 {
         public static void main(String[] args) {
             SpringApplication.run(StreamMQMain8801.class,args);
         }
     }
    
  5. 業務類

    • 發送訊息介面

         package com.atguigu.springcloud.service;
      
         public interface IMessageProvide {
             public String send();
         }
      
    • 發送訊息介面實作類

         @EnableBinding(Source.class)    //定義訊息的推送管道
         public class IMessageProviderImpl implements IMessageProvide {
      
             @Resource
             private MessageChannel output;
      
             @Override
             public String send() {
                 String serial = UUID.randomUUID().toString();
                 output.send(MessageBuilder.withPayload(serial).build());
                 System.out.println("*******serial: "+serial);
                 return null;
             }
         }
      
    • Controller

         @RestController
         public class SendMessageController {
             @Resource
             private IMessageProvide messageProvide;
      
             @GetMapping(value = "/sendMessage")
             public String sendMessage(){
                 return messageProvide.send();
             }
         }
      
  6. 測驗:7001、rabbitmq、8801、訪問http://localhost:8801/sendMessage,然后在rabbitmq監控頁面查看!

    	[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aIB0yM4t-1619837391818)(E:\學習筆記\圖片\image-20210422104312245.png)]



13.3 消費者

  1. 新建cloud-stream-rabbitmq-consumer8802

  2. POM

     <artifactId>cloud-stream-rabbitmq-provider8801</artifactId>
         <dependencies>
             <!--添加訊息總線RabbitMQ支持-->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
             </dependency>
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-config</artifactId>
             </dependency>
             <!--eureka-server-->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
             </dependency>
             <!--boot web actuator-->
             <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.springframework.boot</groupId>
                 <artifactId>spring-boot-devtools</artifactId>
                 <scope>runtime</scope>
                 <optional>true</optional>
             </dependency>
             <dependency>
                 <groupId>org.projectlombok</groupId>
                 <artifactId>lombok</artifactId>
             </dependency>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-test</artifactId>
                 <scope>test</scope>
             </dependency>
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
             </dependency>
    
         </dependencies>
    
     </project>
    
  3. YML

     server:
       port: 8802
    
     spring:
       application:
         name: cloud-stream-consumer
       cloud:
         stream:
           binders:          #在此處配置要系結的rabbitmq的服務資訊;
             defaultRabbit:      #表示定義的名稱,用子binding整合
               type: rabbit      #訊息組件型別
               environment:      #沒置rabbitmq的相關的環境鄗置
                 spring:
                   rabbitmq:
                     host: localhost
                     port: 5672
                     username: guest
                     password: guest
           bindings:     #服務的整合處理
             input:      #這個名字是一個通道的名稱
               destination: studyExchange  #表示要使用的Exchange名稱定義
               content-type: application/json    #設定訊息型別,本次為物件json,如果是文本則設定“text/plain”
               binder: defaultRabbit       #沒置婆系結的訊息服務的具體設定
    
     eureka:
       client: #客戶端進行Eureka注冊的配置
         service-url:
           defaultZone: http://localhost:7001/eureka
       instance:
         lease-renewal-interval-in-seconds: 2        #設定心跳的時間間隔(默認是30秒)
         lease-expiration-duration-in-seconds: 5     #如果現在超過了5秒的間隔(默認是90秒
         instance-id: send-8802.com                  #在資訊串列時顯示主機名稱
         prefer-ip-address: true                     #訪問的路徑變為IP地址
    
  4. 主啟動類

     @SpringBootApplication
     public class StreamMQMain8802 {
         public static void main(String[] args) {
             SpringApplication.run(StreamMQMain8802.class,args);
         }
     }
    
  5. 業務類

     @Controller
     @EnableBinding(Sink.class)
     public class ReceiveMessageListener {
    
         @Value("${server.port}")
         private String serverPort;
    
         @StreamListener(Sink.INPUT)
         public void input(Message<String> message){
             System.out.println("消費者1號,--------->接收到的訊息: "+message.getPayload()+"\t port: "+serverPort);
         }
     }
    
  6. 測驗8801發送訊息8802接受:訪問http://localhost:8801/sendMessage



13.4 訊息重復消費及解決

重復消費問題

  1. 依照8002,克隆一份8003

  2. 啟動

  3. 兩個問題:

    • 重復消費問題

      如何解決?分組和 持久化屬性group

    • 訊息持久化問題

解決

  1. 原理:微服務應用放置于同一個group中,就能夠保證訊息只會被其中一個應用消費一次,不同的組是可以消費的,同一個組內會發生競爭關系,只有其中一個可以消費,

  2. YML(8802、8803):

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EsWr0rkc-1619837391819)(E:\學習筆記\圖片\image-20210422125744657.png)]

  3. 測驗



13.5 訊息持久化

停掉8802、8803,去掉8802的group,保留8803的group,然后7001發送4條訊息,重啟8802、8803,8802的服務不會接收到訊息,而8803的服務可以重新獲取訊息進行消費,




14. Sleuch請求鏈路追蹤

14.1 概述

問題

? 在微服務框架中,一個由客戶端發起的請求在后端系統中會經過多個不同的的服務節點呼叫來協同產生最后的請求結果,每一個前段請求都會形成一條復雜的分布式服務呼叫鏈路,鏈路中的任何一環出現高延時或錯誤都會引起整個請求最后的失敗,

Sleuch是什么

? Spring Cloud Sleuth提供了一套完整的服務跟蹤的解決方案,在分布式系統中提供追蹤解決方案并且兼容支持了zipkin,



14.2 zipkin搭建安裝

  1. 下載:http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/2.12.9/zipkin-server-2.12.9-exec.jar

  2. 當前目錄命令列中運行jar:java -jar zipkin-server-2.12.9-exec.jar

  3. 運行控制臺:http://localhost:9411/zipkin/

    • 完整的鏈路呼叫:

    • Trace:類似于樹結構的Span集合,表示一條呼叫鏈路,存在唯一標識

    • span:表示呼叫鏈路來源,通俗理解span就是一次請求資訊



14.3 sleuch鏈路監控展現

  1. 修改8001模塊:

    • POM:

         <!--包含了sleuth+zipkin-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-zipkin</artifactId>
         </dependency>
      
    • YML

         zipkin:
           base-url: http://localhost:9411
         sleuth:
           sampler:
             #采樣率值介于0到1之間,1則表示全部采集
             probability: 1
      

    • 業務類:

         @GetMapping(value = "/payment/zipkin")
         public String paymentZipkin(){
             return "hi, i am paymentzipkin server fall back, welcome to atguigu, O(∩_∩)O哈哈~";
         }
      
  2. 修改80模塊

    • POM:同上

    • YML:同上

    • Controller:(沒加@loadbalance就這么寫)

         @GetMapping("/consumer/payment/zipkin")
         public String getPaymentZipkin(){
             String result = restTemplate.getForObject("http://localhost:8001"+"/payment/zipkin/",String.class);
             return result;
         }
      
         @GetMapping("/consumer/payment/zipkin")
         public String paymentZipkin(){
             String result = restTemplate.getForObject("http://cloud-payment-service"+"/payment/zipkin/",String.class);   //加@loadbalance了的
             return result;
         }
      
  3. 80呼叫8001:http://localhost/consumer/payment/zipkin

  4. 查看http://localhost:9411/zipkin/:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/282306.html

標籤:java

上一篇:帶作業流的springboot后臺管理專案,一個企業級快速開發解決方案

下一篇:Fdog系列(五):使用Qt模仿QQ實作登錄界面到主界面,功能篇。

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more