SpringCloud-微服務架構編碼構建
- 2021 年 5 月 4 日
- 筆記
SpringCloud
Spring Cloud為開發人員提供了快速構建分散式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智慧路由,微代理,控制匯流排)。分散式系統的協調導致了樣板模式, 使用Spring Cloud開發人員可以快速地支援實現這些模式的服務和應用程式。他們將在任何分散式環境中運行良好,包括開發人員自己的筆記型電腦電腦,裸機數據中心,以及Cloud Foundry等託管平台
常用幫助文檔
微服務模組
- 建模組
- 改pom
- 寫YML
- 主啟動
- 業務類
1.父工程空間構建
![]() |
---|
![]() |
![]() |
![]() |
![]() |
![]() |
1.2 父工程pom
<!-- 統一管理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>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.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>
<!-- 子模組繼承之後,提供作用:鎖定版本+子modlue不用寫groupId和version -->
<dependencyManagement>
<dependencies>
<!--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 alibaba 2.1.0.RELEASE-->
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</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>
1.3 Maven中的DependencyManagement和Dependencies
dependencyManagement
Maven 使用dependencyManagement 元素來提供了一種管理依賴版本號的方式。
通常會在一個組織或者項目的最頂層的父POM 中看到dependencyManagement 元素。
使用pom.xml 中的dependencyManagement 元素能讓所有在子項目中引用一個依賴而不用顯式的列出版本號。
Maven 會沿著父子層次向上走,直到找到一個擁有dependencyManagement 元素的項目,然後它就會使用這個
dependencyManagement 元素中指定的版本號。
這樣做的好處就是:如果有多個子項目都引用同一樣依賴,則可以避免在每個使用的子項目里都聲明一個版本號,這樣當想升級或切換到另一個版本時,只需要在頂層父容器里更新,而不需要一個一個子項目的修改 ;另外如果某個子項目需要另外的一個版本,只需要聲明version就可。
-
dependencyManagement里只是聲明依賴,並不實現引入,因此子項目需要顯示的聲明需要用的依賴。
-
如果不在子項目中聲明依賴,是不會從父項目中繼承下來的;只有在子項目中寫了該依賴項,並且沒有指定具體版本, 才會從父項目中繼承該項,並且version和scope都讀取自父pom;
-
如果子項目中指定了版本號,那麼會使用子項目中指定的jar版本。
1.4maven中跳過單元測試
1 配置
<build><!-- maven中跳過單元測試 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
2 IDEA工具支援(推薦)
2.支付模組構建
2.1 上
![]() |
---|
![]() |
2.1.1 改子模組的pom
<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>
2.1.2 寫子模組的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驅動包 com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: Zwf51162139.
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.wan.springcloud.entities # 所有Entity別名類所在包
2.1.3 主啟動類
@SpringBootApplication
public class PaymentMain8081 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8081.class,args);
}
}
2.1.4 業務類
2.1.5 測試
![]() |
![]() |
![]() |
![]() |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
3.消費者訂單模組
![]() |
---|
![]() |
參照生產者 |
![]() |
3.1.3主啟動類
@SpringBootApplication
public class MainApplication80 {
public static void main(String[] args) {
SpringApplication.run(MainApplication80.class,args);
}
}
3.1.5測試
![]() |
---|
![]() |
![]() |
![]() |
![]() |
![]() |
4.工程重構
1.系統有重複,需要重構
2.新建 cloud-api-commons
3.改pom
<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>
4.拷貝重複部分entitie
5.maven命令clean , install
6.訂單80和支付8001分別改造(刪除entities,粘貼pom)
![]() |
---|
![]() |
![]() |
刪除各自的entities![]() |
![]() |
<dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
<groupId>com.wan.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
5.Eureka基礎知識
5.1 什麼是服務治理
Spring Cloud 封裝了 Netflix 公司開發的 Eureka 模組來實現服務治理
在傳統的rpc遠程調用框架中,管理每個服務與服務之間依賴關係比較複雜,管理比較複雜,所以需要使用服務治理,管理服務於服務之間依賴關係,可以實現服務調用、負載均衡、容錯等,實現服務發現與註冊。
5.2什麼是服務註冊與發現
Eureka採用了CS的設計架構,Eureka Server 作為服務註冊功能的伺服器,它是服務註冊中心。而系統中的其他微服務,使用 Eureka的客戶端連接到 Eureka Server並維持心跳連接。這樣系統的維護人員就可以通過 Eureka Server 來監控系統中各個微服務是否正常運行。
在服務註冊與發現中,有一個註冊中心。當伺服器啟動的時候,會把當前自己伺服器的資訊 比如 服務地址通訊地址等以別名方式註冊到註冊中心上。另一方(消費者|服務提供者),以該別名的方式去註冊中心上獲取到實際的服務通訊地址,然後再實現本地RPC調用RPC遠程調用框架核心設計思想:在於註冊中心,因為使用註冊中心管理每個服務與服務之間的一個依賴關係(服務治理概念)。在任何rpc遠程框架中,都會有一個註冊中心(存放服務地址相關資訊(介面地址))
下左圖是Eureka系統架構,右圖是Dubbo的架構,請對比
5.3 Eureka包含兩個組件:Eureka Server和Eureka Client
Eureka Server提供服務註冊服務
各個微服務節點通過配置啟動後,會在EurekaServer中進行註冊,這樣EurekaServer中的服務註冊表中將會存儲所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀看到。
EurekaClient通過註冊中心進行訪問
是一個Java客戶端,用於簡化Eureka Server的交互,客戶端同時也具備一個內置的、使用輪詢(round-robin)負載演算法的負載均衡器。在應用啟動後,將會向Eureka Server發送心跳(默認周期為30秒)。如果Eureka Server在多個心跳周期內沒有接收到某個節點的心跳,EurekaServer將會從服務註冊表中把這個服務節點移除(默認90秒)
6.IDEA生成eurekaServer端服務註冊中心
![]() |
---|
![]() |
![]() |
![]() |
![]() |
![]() |
7.Eureka集群環境搭建
![]() |
---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
8.Eureka自我保護
概述
保護模式主要用於一組客戶端和Eureka Server之間存在網路分區場景下的保護。一旦進入保護模式,
Eureka Server將會嘗試保護其服務註冊表中的資訊,不再刪除服務註冊表中的數據,也就是不會註銷任何微服務。
如果在Eureka Server的首頁看到以下這段提示,則說明Eureka進入了保護模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.
RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE
為什麼會產生Eureka自我保護機制?
為了防止EurekaClient可以正常運行,但是 與 EurekaServer網路不通情況下,EurekaServer不會立刻將EurekaClient服務剔除
什麼是自我保護模式?
默認情況下,如果EurekaServer在一定時間內沒有接收到某個微服務實例的心跳,EurekaServer將會註銷該實例(默認90秒)。但是當網路分區故障發生(延時、卡頓、擁擠)時,微服務與EurekaServer之間無法正常通訊,以上行為可能變得非常危險了——因為微服務本身其實是健康的,此時本不應該註銷這個微服務。Eureka通過「自我保護模式」來解決這個問題——當EurekaServer節點在短時間內丟失過多客戶端時(可能發生了網路分區故障),那麼這個節點就會進入自我保護模式。
在自我保護模式中,Eureka Server會保護服務註冊表中的資訊,不再註銷任何服務實例。
它的設計哲學就是寧可保留錯誤的服務註冊資訊,也不盲目註銷任何可能健康的服務實例。一句話講解:好死不如賴活著
綜上,自我保護模式是一種應對網路異常的安全保護措施。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留)也不盲目註銷任何健康的微服務。使用自我保護模式,可以讓Eureka集群更加的健壯、穩定。