1. 微服務架構理論
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tjPWmmpo-1619837391777)(E:\學習筆記\圖片\image-20201019134302836.png)]](https://img.uj5u.com/2021/05/03/241099030715221.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LdaZgyUq-1619837391779)(E:\學習筆記\圖片\image-20201019134502724.png)]](https://img.uj5u.com/2021/05/03/2410990307152246.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VXwGAeeu-1619837391780)(E:\學習筆記\圖片\image-20201019134832352.png)]](https://img.uj5u.com/2021/05/03/2410990307152247.png)
1.1. SpringCloud簡介
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Mt9XOLHL-1619837391782)(E:\學習筆記\圖片\image-20201019134723201.png)]](https://img.uj5u.com/2021/05/03/241099030715222.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RVWFRFyR-1619837391783)(E:\學習筆記\圖片\image-20201019134932544.png)]](https://img.uj5u.com/2021/05/03/2410990307152248.png)
1.2. SpringCloud技術堆疊
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6HEZhhYK-1619837391785)(E:\學習筆記\圖片\image-20201019135425161.png)]](https://img.uj5u.com/2021/05/03/2410990307152249.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UuGEPEUM-1619837391785)(E:\學習筆記\圖片\image-20201019135542664.png)]](https://img.uj5u.com/2021/05/03/2410990307152250.png)
2. 環境搭建
2.1. Boot和Cloud版本選擇
-
依賴關系:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tYDO627a-1619837391786)(E:\學習筆記\圖片\image-20201019140734313.png)]](https://img.uj5u.com/2021/05/03/2410990307152251.png)
-
最終定型

-
Boot已經有2.2.4而且符合規范,為啥要選2.2.2?
官網推薦:

2.2. Cloud組件停更說明
-
停更引發的 “升級慘案”
-
停更不停用

-
變更
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-oYTLWLND-1619837391787)(E:\學習筆記\圖片\image-20201019142526851.png)]](https://img.uj5u.com/2021/05/03/2410990307152254.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)]](https://img.uj5u.com/2021/05/03/2410990307152262.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)]](https://img.uj5u.com/2021/05/03/241099030715224.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)]](https://img.uj5u.com/2021/05/03/241099030715225.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)]](https://img.uj5u.com/2021/05/03/241099030715226.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)]](https://img.uj5u.com/2021/05/03/241099030715227.png)
-
maven命令clean install
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pAr0l2Ez-1619837391791)(E:\學習筆記\圖片\image-20201020154744466.png)]](https://img.uj5u.com/2021/05/03/241099030715228.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)]](https://img.uj5u.com/2021/05/03/2410990307152267.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)]](https://img.uj5u.com/2021/05/03/241099030715229.png)
-
使用**@LoadBalanced**賦予RestTemplate負載均衡能力
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KJXZUKia-1619837391793)(E:\學習筆記\圖片\image-20201021193030686.png)]](https://img.uj5u.com/2021/05/03/2410990307152274.png)
-
4.9. actuator微服務資訊完整
-
主機名稱:服務名稱的修改


-
訪問資訊有IP顯示
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SPMWrKmX-1619837391794)(E:\學習筆記\圖片\image-20201021202543439.png)]](https://img.uj5u.com/2021/05/03/2410990307152212.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)]](https://img.uj5u.com/2021/05/03/2410990307152213.png)
4.11. Eureka自我保護理論知識
-
故障現象
保護模式主要用于一組客戶端和Eureka Server之間存在網路磁區場景下的保護,一旦進入保護模式,
Eureka Server將會嘗試保護其服務注冊表中的資訊,不再洗掉服務注冊表中的資料,也就是不會注銷任何微服務,![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-snxY8zso-1619837391795)(E:\學習筆記\圖片\image-20201021204851468.png)]](https://img.uj5u.com/2021/05/03/2410990307152214.png)
一句話:某時刻某一個微服務不可用了,Eureka不會立刻清理,依舊會對該微服務的資訊進行保存,屬于CAP里面的AP分支

4.12. 禁止Eureka自我保護
-
注冊中心7001
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hhZYcC26-1619837391797)(E:\學習筆記\圖片\image-20201021210941801.png)]](https://img.uj5u.com/2021/05/03/2410990307152215.png)

-
客戶端
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ICMKCptS-1619837391798)(E:\學習筆記\圖片\image-20201021211257021.png)]](https://img.uj5u.com/2021/05/03/2410990307152216.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)]](https://img.uj5u.com/2021/05/03/2410990307152278.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集成 |
|---|---|---|---|---|---|
| Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
| Consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
| Zookeeper | Java | CP | 支持 | 客戶端 | 已集成 |
-
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)]](https://img.uj5u.com/2021/05/03/2410990307152285.png)
-
postForObject方法/postForEntity方法
-
post方法
-
get方法
-
7.3 Ribbon核心組件IRule
-
IRule:根據特定演算法中從服務串列中選取一個要訪問的服務
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7efCcNz5-1619837391800)(E:\學習筆記\圖片\image-20201026155245168.png)]](https://img.uj5u.com/2021/05/03/2410990307152286.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)]](https://img.uj5u.com/2021/05/03/2410990307152289.png)
-
原始碼分析(下標+cas+自旋鎖)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jrZYlSgV-1619837391801)(E:\學習筆記\圖片\image-20201026162227396.png)]](https://img.uj5u.com/2021/05/03/2410990307152290.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)]](https://img.uj5u.com/2021/05/03/2410990307152291.png)
-
Feign和OpenFeign的區別
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FbsIdHvk-1619837391803)(E:\學習筆記\圖片\image-20201026165100732.png)]](https://img.uj5u.com/2021/05/03/2410990307152219.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)]](https://img.uj5u.com/2021/05/03/2410990307152220.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)]](https://img.uj5u.com/2021/05/03/2410990307152221.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)]](https://img.uj5u.com/2021/05/03/2410990307152222.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)]](https://img.uj5u.com/2021/05/03/2410990307152296.png)
9.13 總結

熔斷型別:
- 打開:請求不再進行呼叫當前服務,內部設定時鐘一般為MTTR(平均故障處理時間),當打開時長達到所設時鐘則進入半熔斷狀態
- 關閉:熔斷關閉不會對服務進行熔斷
- 半開:部分請求根據規則呼叫當前服務,如果請求成功且符合規則則認為當前服務恢復正常,關閉熔斷
斷路器開啟或者關閉的條件:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3HtfcUn0-1619837391806)(E:\學習筆記\圖片\image-20201101200525906.png)]](https://img.uj5u.com/2021/05/03/2410990307152298.png)
斷路器打開之后:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-freUlAqV-1619837391806)(E:\學習筆記\圖片\image-20201101200728676.png)]](https://img.uj5u.com/2021/05/03/2410990307152299.png)
?
9.14 Hystrix作業流程

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)]](https://img.uj5u.com/2021/05/03/2410990307152224.png)
-
一圈
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5CQIjtaa-1619837391809)(E:\學習筆記\圖片\image-20201104163338229.png)]](https://img.uj5u.com/2021/05/03/2410990307152225.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9XkDk8gb-1619837391810)(E:\學習筆記\圖片\image-20201104163328904.png)]](https://img.uj5u.com/2021/05/03/2410990307152226.png)
-
一線:用來記錄2分鐘內流量的相對變化,可以通過它來觀察到流量的上升和下降趨勢,
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iq98yE69-1619837391810)(E:\學習筆記\圖片\image-20201104163415409.png)]](https://img.uj5u.com/2021/05/03/24109903071522100.png)
-
整個圖說明
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HcFx0Qk5-1619837391811)(E:\學習筆記\圖片\image-20201104163505504.png)]](https://img.uj5u.com/2021/05/03/24109903071522101.png)
-
整個圖說明
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Woosko1H-1619837391812)(E:\學習筆記\圖片\image-20201104163532012.png)]](https://img.uj5u.com/2021/05/03/24109903071522102.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)]](https://img.uj5u.com/2021/05/03/24109903071522104.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AzrHkiS6-1619837391813)(E:\學習筆記\圖片\image-20201130112116079.png)]](https://img.uj5u.com/2021/05/03/24109903071522105.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 配置路由的兩種方式
-
上述的yaml配置
-
代碼中注入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會根據注冊中心注冊的服務劃表,以注冊中心上微服務名為路徑創建動態路由進行轉發,從而實作動態路由的功能
-
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
-
After Route Predicate:
public class Test { public static void main(String[] args) { ZonedDateTime zbj = ZonedDateTime.now(); System.out.println(zbj); } }
-
Before Route Predicate、Between Route Predicate與上面類似
-
Cookie Route Predicate:




-
Header Route Predicate

![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Q9eS4g72-1619837391813)(E:\學習筆記\圖片\image-20210419172521954.png)]](https://img.uj5u.com/2021/05/03/2410990307152231.png)
-
Host Route Predicate:

![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y1icktN2-1619837391814)(E:\學習筆記\圖片\image-20210419172638825.png)]](https://img.uj5u.com/2021/05/03/2410990307152232.png)
-
Method Route Predicate:

-
Path Route Predicate:
就是 -Path
-
Query Route Predicate:

總結
說白了,Predicate就是為了實作一組匹配規則,讓請求過來找到對應的Route進行處理,
10.8 Filter
介紹
- 路由器指的是Spring框架中GatewayFilter的實體,使用過濾器,可以在請求被路由前或者之后對請求進行修改,
- 路由過濾器可用于修改進入的HTTP請求和回傳的HTTP回應,路由過濾器只能指定路由進行使用,
- Spring Cloud Gateway內置了多種路由過濾器,他們都由GatewayFilter的工廠類來產生
- 生命周期:pre、post
- 種類:GatewayFilter、GlobalFilter
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2Qtr6p25-1619837391815)(E:\學習筆記\圖片\image-20210420150001605.png)]](https://img.uj5u.com/2021/05/03/24109903071522112.png)
-
自定義過濾器:實作兩個介面,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 分布式配置中心介紹
? 微服務意味著要將單體應用中的業務拆分成一個個子服務,每個服務的粒度相對較小,因此系統中會出現大量的服務,由于每個服務都需要必要的配置資訊才能運行,所以一套集中式的、動態的配置管理設施是必不可少的,
介紹
-
SpringCloud Config為微服務架構中的微服務提供集中化的外部配置支持,配置服務器為各個不同微服務應用的所有環境提供了一個中心化的外部配置,
-
SpringCloud Config分為服務端和客戶端兩部分,
-
服務端也稱為分布式配置中心,它是一個獨立的微服務應用,用來連接配置服務器并為客戶端提供獲取配置資訊,加密/解密資訊等訪問介面,
客戶端則是通過指定的配置中心來管理應用資源,以及與業務相關的配置內容,并在啟動的時候從配置中心獲取和加載配置資訊配置服務器默認采用git來存盤配置資訊,這樣就有助于對環境配置進行版本管理,并且可以通過git客戶端工具來方便的管理和訪問配置內容
11.2 配置總控中心搭建
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2xSC65Hn-1619837391815)(E:\學習筆記\圖片\image-20210420160930035.png)]](https://img.uj5u.com/2021/05/03/24109903071522114.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pLXNBrNm-1619837391816)(E:\學習筆記\圖片\image-20210420161052125.png)]](https://img.uj5u.com/2021/05/03/2410990307152235.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-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> -
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 -
主啟動類
@SpringBootApplication @EnableConfigServer public class ConfigCenterMain3344 { public static void main(String[] args) { SpringApplication.run(ConfigCenterMain3344.class,args); } } -
windows下修改hosts檔案,增加映射
127.0.0.1 config-3344.com -
測驗通過Config微服務是否可以從GitHub上獲取配置內容:啟動3344,http://config-3344.com:3344/main/config-dev.yml

配置讀取規則
-
/{label}/{application}-fprofile}.yml

-
/{application}-{profile}.yml

-
/{application}/{profile}[/{label}]

配置細節
- label:分支名
- name:服務名
- profile:環境(dev/test/prod)
11.3 客戶端配置與測驗
-
新建cloud-config-client-3355
-
POM
-
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 -
修改config-dev.yml配置并且提交到github,比如加個變數age或者版本號version
-
主啟動類
@SpringBootApplication @EnableEurekaClient public class ConfigClientMain3355 { public static void main(String[] args) { SpringApplication.run(ConfigClientMain3355.class,args); } } -
業務類
@RestController public class ConfigClientController { @Value("${config.info}") private String configInfo; @GetMapping("/configInfo") public String getConfigInfo(){ return configInfo; } } -
測驗:7001,3344,3355,然后訪問http://localhost:3355/configInfo

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

11.4 動態重繪手動版
修改3355模塊:
-
POM引入actuator監控
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> -
修改yml,暴露監控埠
#暴露監控埠 management: endpoints: web: exposure: include: "*" -
@RefreshScope業務類Controller修改
@RestController @RefreshScope public class ConfigClientController { @Value("${config.info}") private String configInfo; @GetMapping("/configInfo") public String getConfigInfo(){ return configInfo; } } -
此時修改github由2->1,發現沒生效啊!
-
需要運維人員發個post請求重繪3355:curl -X POST “http://localhost:3355/actuator/refresh”
新的問題:多個微服務客戶端,能否廣播,一次通知,處處生效,大范圍自動重繪?
12. bus訊息總線
12.1 概述
-
Bus只支持兩種訊息代理,RabbitMQ和Kafka
-
可以實作配置的自動重繪

-
Spring Cloud Bus能管理和傳播分布式系統間的訊息,就像一個分布式執行器,可用于廣播狀態更改、事件推送等,也可以當作微服務間的通信通道,
12.2 環境配置
-
安裝erlang:http://erlang.org/download/otp_win64_21.3.exe
-
rabbitmq:https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe
-
進入rabbitmq安裝的sbin目錄下,命令列輸入:.\rabbitmq-plugins enable rabbitmq_management

-
開始目錄啟動rabbit.start,測驗是否成功:http://localhost:15672,成功進入,登錄賬號密碼均是guest
12.3 動態重繪全域廣播
環境搭建
-
再制作一個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; } } -
設計思想:
-
利用訊息總線觸發一個客戶端/bus/refresh,而重繪所有客戶端的配置
-
利用訊息總線觸發一個服務端ConfigServer的/bus/refresh端點,而重繪所有客戶端的配置
-
圖二的架構顯然更加適合,圖—不適合的原因如下:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-69vSQx9x-1619837391817)(E:\學習筆記\圖片\image-20210421153536027.png)]](https://img.uj5u.com/2021/05/03/2410990307152240.png)
-
實作
-
給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'
-
-
給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
-
-
給cloud-config-client-3366客戶端添加訊息總線支持:跟上面3355一樣
-
測驗:
- 修改github版本號,發送POST請求,一次發送,處處生效!
12.4 動態重繪定點通知
只通知3355,不通知3366:
-
公式: http://localhost:配置中心的埠號/actuator/bus-refresh/{destination}
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Ac844H32-1619837391818)(E:\學習筆記\圖片\image-20210421162442393.png)]](https://img.uj5u.com/2021/05/03/2410990307152241.png)
13. Stream訊息驅動
介紹
- 官方定義Spring Cloud Stream是一個構建訊息驅動微服務的框架,
- 它可以屏蔽底層訊息中間件的差異,降低切換成本,統一訊息的編程模型,
設計思想
-
它為什么可以統一底層差異?
通過定義系結器Binder作為中間層,實作應用程式和訊息中間件細節上的解耦隔離
-
Binder:
-
INPUT:對應消費者
-
OUTPUT:對應生產者
-
通信方式遵循發布-訂閱模式:Topic主題進行廣播
-

13.1 常用注解介紹
標準流程套路
- Binder:連接中間件
- Channel:通道,是佇列Queue的一種抽象,在訊息通訊系統中就是實作存盤和轉發的媒介,通過Channel對隊伍進行配置
- Source和Sink:簡單理解為輸入輸出
編碼API和常用注解

13.2 生產者
-
新建cloud-stream-rabbitmq-provider8801
-
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> -
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地址 -
主啟動類
@EnableEurekaClient @SpringBootApplication public class StreamMQMain8801 { public static void main(String[] args) { SpringApplication.run(StreamMQMain8801.class,args); } } -
業務類
-
發送訊息介面
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(); } }
-
-
測驗:7001、rabbitmq、8801、訪問http://localhost:8801/sendMessage,然后在rabbitmq監控頁面查看!
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aIB0yM4t-1619837391818)(E:\學習筆記\圖片\image-20210422104312245.png)]](https://img.uj5u.com/2021/05/03/2410990307152242.png)
13.3 消費者
-
新建cloud-stream-rabbitmq-consumer8802
-
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> -
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地址 -
主啟動類
@SpringBootApplication public class StreamMQMain8802 { public static void main(String[] args) { SpringApplication.run(StreamMQMain8802.class,args); } } -
業務類
@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); } } -
測驗8801發送訊息8802接受:訪問http://localhost:8801/sendMessage


13.4 訊息重復消費及解決
重復消費問題
-
依照8002,克隆一份8003
-
啟動
-
兩個問題:
-
重復消費問題
如何解決?分組和 持久化屬性group


-
訊息持久化問題
-
解決
-
原理:微服務應用放置于同一個group中,就能夠保證訊息只會被其中一個應用消費一次,不同的組是可以消費的,同一個組內會發生競爭關系,只有其中一個可以消費,
-
YML(8802、8803):
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EsWr0rkc-1619837391819)(E:\學習筆記\圖片\image-20210422125744657.png)]](https://img.uj5u.com/2021/05/03/24109903071522124.png)
-
測驗
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搭建安裝
-
下載:http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/2.12.9/zipkin-server-2.12.9-exec.jar
-
當前目錄命令列中運行jar:java -jar zipkin-server-2.12.9-exec.jar
-
運行控制臺:http://localhost:9411/zipkin/
-
完整的鏈路呼叫:


-
Trace:類似于樹結構的Span集合,表示一條呼叫鏈路,存在唯一標識
-
span:表示呼叫鏈路來源,通俗理解span就是一次請求資訊
-
14.3 sleuch鏈路監控展現
-
修改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哈哈~"; }
-
-
修改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; }
-
-
80呼叫8001:http://localhost/consumer/payment/zipkin

-
查看http://localhost:9411/zipkin/:

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

