微服務概述
[馬丁福勒微服務論文]: https://martinfowler.com/articles/microservices.html
什麼是微服務
目前的微服務並沒有一個統一的標準,一般是以業務來劃分, 將傳統的一站式應用,拆分成一個個的服務,徹底去耦合,一個微服務就是單功能業務,只做一件事。與微服務相對的叫巨石
微服務與微服務架構
微服務是一種架構模式或者一種架構風格,提倡將單一應用程式劃分成一組小的服務,獨立部署,服務之間相互配合、相互協調,每個服務運行於自己的程序中。
服務與服務間採用輕量級通訊,如HTTP的RESTful API等,避免統一的、集中式的服務管理機制
微服務的優缺點
優點
1. 每個服務足夠內聚,足夠小,比較容易聚焦
2. 開發簡單且效率高,一個服務只做一件事情
3. 開發團隊小,一般2-5人足以(當然按實際為準)
4. 微服務是松耦合的,無論開發還是部署都可以獨立完成
5. 微服務能用不同的語言開發
6. 易於和第三方整合,微服務允許容易且靈活的自動整合部署(持續整合工具有Jenkins,Hudson,bamboo等)
8. 微服務允許你融合最新的技術
9. 微服務只是業務邏輯的程式碼,不會和HTML,CSS或其他介面元件融合。
10. 每個微服務都可以有自己的儲存能力,資料庫可自有也可以統一,十分靈活。
缺點
1. 開發人員要處理分散式系統的複雜性
2. 多服務運維難度,隨著服務的增加,運維的壓力也會增大
3. 依賴系統部署
4. 服務間通訊的成本
5. 資料的一致性
6. 系統整合測試
7. 效能監控的難度
微服務的技術棧
為什麼選SpringCloud作為微服務架構
選型依據
1. 整體解決方案和框架的成熟度
2. 社群熱度
3. 可維護性
4. 學習曲線
SpringCloud入門概述
Spring的三大模組:SpringBoot(構建),Spring Cloud(協調),Spring Cloud Data Flow(連線)
SpringCloud是什麼
分散式系統的簡化版(官方介紹)
SpringCloud基於SpringBoot提供了一整套微服務的解決方案,包括服務註冊與發現,配置中心,全鏈路監控,服務閘道器,負載均衡,熔斷器等元件,除了基於Netflix的開源元件做高度抽象封裝之外,還有一些選型中立的開源元件
SpringCloud利用SpringBoot的開發便利性巧妙地簡化了分散式系統的基礎設施開發,SpringCloud為開發人員提供了快速構建分散式系統的一些工具,包括配置管理、服務發現、斷路器、路由、微代理、事件匯流排,全域性所、決策精選、分散式會話等等,他們都可以用SpringBoot的開發風格做到一鍵啟動和部署。
一句話概括:SpringCloud是分散式微服務架構下的一站式解決方案,是各個微服務架構落地技術的幾何體,俗稱微服務全家桶
SpringCloud和SpringBoot的關係
SpringBoot:專注於快速方便的開發單個個體微服務(關注微觀)
SpringCloud:關注全域性的微服務協調治理框架,將SpringBoot開發的一個個單體微服務組合並管理起來(關注宏觀)
SpringBoot可以離開SpringCloud獨立使用,但是SpringCloud不可以離開SpringBoot,屬於依賴關係
Dubbo是怎麼到SpringCloud的?哪些優缺點去技術選型
對比
**最大區別:**
-Spring Cloud拋棄了RPC通訊,採用基於HTTP的REST方式。Spring Cloud犧牲了服務呼叫的效能,但是同時也避免了原生RPC帶來的問題。REST比RPC更為靈活,不存在程式碼級別的強依賴,在強調快速演化的微服務環境下,顯然更合適。
一句話:Dubbo像組裝機,Spring Cloud像一體機
-社群的支援與力度:Dubbo曾經停運了5年,雖然重啟了,但是對於技術發展的新需求,還是需要開發者自行去拓展,對於中小型公司,顯然顯得比較費時費力,也不一定有強大的實力去修改原始碼
總結
1. 解決的問題域不一樣:Dubbo的定位是一款RPC框架,Spring Cloud的目標是微服務架構下的一站式解決方案
SpringCloud的參考資料
[SpringCloud的中文參考資料]: https://springcloud.cc/spring-cloud-netflix.html
[SpringCloud的中文API]: https://springcloud.cc/spring-cloud-dalston.html
[SpringCloud中國社群]: http://springcloud.cn/
[SpringCloud中文網]: https://springcloud.cc/
構建SpringCloud工程
概述:SpringCloud工程由一個父工程和若干個Module組成
應該遵循的條件:約定 > 配置 > 編碼
RestTemplate類
介紹
RestTemplate是Spring提供的用於訪問Rest服務的客戶端模板工具集,提供了多種遠端訪問Http的方法
[RestTemplate的API]: https://docs.spring.io/spring/docs/5.0.6.RELEASE/javadoc-api/
意義
在一些不涉及實現方法的模組中(消費者),只需要呼叫其他服務暴露出的介面即可滿足的需求,使用RestTemplate類中的方法可以發出需要的HTTP請求並得到返回結果。(類似Ajax)
RestTemplate用法
#java
RestTemplate restTemplate = new RestTemplate();
url:請求地址
requestMap:請求引數
type.class:HTTP響應轉換成的物件型別
restTemplate.getForObject(url,type.class);
restTemplate.postForObject(url,requestMap,type.class);
構建父工程
建立一個Maven父工程並命名GAV
打包方式為POM
在pom.xml中定義各依賴的版本號(若Module中pom.xml的依賴沒有指定版本號,則會根據父工程的版本號加入依賴)
加入通用的依賴和外掛
構建Module
在父工程下新建Maven的Module,打包方式為jar
一般來時GAV中 GV隨父工程,自己定義A即可
在該Module下pom.xml中加入其它需要的依賴
正常開發即可
完成後先clean一下Maven專案,然後再install提供給其它模組呼叫
新增其它Module的依賴方法
直接引用其GAV即可
xml
<dependencies>
<dependency>
<groupId>com.lzl</groupId>
<artifactId>microservice-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
# 配置該module下的yml
微服務需要獨立的埠
微服務最重要的是取名字!!!!一定要給微服務配置一個名字!這個名字就是這個微服務對外暴露的名字!
- 配置該模組下的其它相關配置(如本例配置了mybatis)
```yml
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.XXX.entity
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
application:
name: microservicecloud-dept #為這個服務取名,非常重要!!!!!
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/cloudDB01
username: root
password: 123456
dbcp2:
min-idle: 5 #最小連線數
initial-size: 5 #初始化連線數
max-total: 10 #最大連線數
max-wait-millis: 200 #等待連線最長的超時時間
# 編寫主啟動類
- 記得主啟動類放在根包下,com.xxx.xxx
```java
package com.XXX;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Provider8001_APP {
public static void main(String[] args) {
SpringApplication.run(Provider8001_APP.class,args);
}
}
## SpringCloud新增元件的基本套路
1. 新增這個元件的maven座標GAV
2. 在啟動類上面標註啟動該元件(一般來說是@EnableXXXXX)
3. 編寫業務邏輯程式碼
Eureka服務註冊與發現
Eureka介紹及原理
理解
Eureka就像一個物業管理公司,其他微服務就像小區的住戶,每個住戶入住時都要向物業管理公司註冊,並定時向物業公司交管理費
#介紹
Eureka是一個基於REST的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。
Eureka主管服務註冊與發現,在微服務中,以後了這兩者,只需要使用服務的識別符號(就是那個在每個服務的yml檔案中取得服務名稱==),就可以訪問到服務,不需要修改服務呼叫的配置檔案
- Eureka遵循AP原則(高可用,分割槽容錯性),因為使用了自我保護機制所以保證了高可用
原理
Eureka使用的是C-S結構(客戶端-服務端)
兩大元件:Eureka Server(提供註冊服務)、 Eureka Client(JAVA客戶端,負責傳送心跳)
- 系統中的其他微服務使用Eureka客戶端連線到Eureka服務端維持心跳連線(即註冊)。SpringCloud的其他模組可以透過Eureka Server 來發現系統中的微服務並加以呼叫
Eureka服務註冊中心構建
加入服務端依賴
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
配置yml
理解:物業公司肯定不向自己註冊自己,並肯定知道自己在哪,不用參加檢索
```yml
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #false表示不向註冊中心註冊自己
fetch-registry: false #false表示自己就是註冊中心,職責是維護例項,不參加檢索
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #設定eureka server的互動地址,即對外暴露的地址
```
新增啟動類
注意:要在類前加@EnableEurekaServer標註
```java
package com.XXX;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class Eureka7001_APP {
public static void main(String[] args) {
SpringApplication.run(Eureka7001_APP.class,args);
}
}
```
驗證是否構建成功
啟動主程式,訪問該服務地址即可
向Eureka註冊中心註冊微服務
增加依賴
在要註冊的微服務的pom.xml檔案中增加依賴
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
```
修改yml
- 在application.yml中增加以內容,將客戶端註冊到服務列表內
- ==理解:小區使用者要找到物業管理處的地址進行註冊==
```yml
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
```
主啟動類增加註解
- 增加@EnableEurekaClient註解
```java
@SpringBootApplication
@EnableEurekaClient
public class Provider8001_APP {
public static void main(String[] args) {
SpringApplication.run(Provider8001_APP.class,args);
}
}
```
actuator與微服務註冊完善
主機名稱與服務名稱的修改
- 修改服務名稱,在yml中eureka節點下新增如下內容
```yml
eureka:
instance:
instance-id: dept8001 #修改別名
prefer-ip-address: true #顯示IP地址
```
info內容的詳細資訊修改
作用
修改方法
1. 當前工程新增依賴
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
```
2. 總的父工程的build節點下新增如下內容
```xml
<build>
<finalName>microservicecloud</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
```
3. 在當前工程的application.yml檔案添加回顯資訊
```yml
info:
author: XXX
build-version: $project.version$
```
Eureka的自我保護
介紹
Eureka的自我保護機制主要是為了網路異常時保持高可用設計的,當在Eureka中註冊的微服務超過設定是時間內(預設90秒)沒有向Eureka服務端傳送心跳,該微服務會進入自我保護模式。在自我保護模式中,Eureka會保護服務登錄檔中的資訊,不會登出任何服務例項,直至收到的心跳數恢復至閾值以上,該微服務退出自我保護模式。
理解
好死不如賴活:Eureka的設計哲學是寧可保留錯誤的服務資訊,也不盲目登出可能健康的服務。所以異常的服務不會被登出,而是進入了自我保護模式。
自我保護模式的開關
在Eureka Server模組下的yml檔案中新增配置資訊即可,true表示開啟自我保護模式;false表示關閉自我保護模式(不推薦)
```java
server:
enable-self-preservation: false
```
### Eureka的服務發現
#### 介紹
系統中的微服務可以透過Eureka的服務發現去獲得在Eureka中註冊的服務的資訊,這是一個對外暴露的介面。
#### 使用方法(provider中)
1. 注入DiscoveryClient 物件(spring包下的),在controller方法中獲取
```java
@Autowired
private DiscoveryClient discoveryClient;
@ResponseBody
@GetMapping("/provider/discovery")
public Object discovery(){
List<String> list = discoveryClient.getServices();
System.out.println(list);
List<ServiceInstance> insList = discoveryClient.getInstances("MICROSERVICECLOUD-DEPT");
for (ServiceInstance si:insList) {
System.out.println(si.getHost() +"," + si.getServiceId() +"," +si.getPort() +"," +si.getUri() +"," +si.getMetadata());
}
return this.discoveryClient;
}
```
2. 在主啟動類中加入@EnableDiscoveryClient註解
```java
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class Provider8001_APP {
public static void main(String[] args) {
SpringApplication.run(Provider8001_APP.class,args);
}
}
```
#### 使用方法(consumer中)
在controller方法中使用restTemplate物件呼叫provider中暴露的URL 並獲得返回物件即可
```java
@GetMapping("/discovery")
public Object discovery() {
return restTemplate.getForObject(URL_PREFIX+"/provider/discovery",Object.class);
}
```
### Eureka的叢集配置
#### 叢集
叢集就是在不同的機器上配置相同的服務來構建要一個大的運算整體
#### 實現叢集
1. 新建N個Eureka Server模組
2. 每個模組的pom.xml中加入與單個Eureka Server相同的依賴
3. 每個模組加入主程式(記得加@EnableEurekaServer註解)
4. 修改hosts檔案(Win7的路徑是C:\Windows\System32\drivers\etc)
```shell
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
```
5. 修改Eureka Server模組的application.yml檔案,加入叢集,主要修改兩個地方:
-hostname:修改為hosts檔案中對映的地址
service-url下的defaultZone節點:填入叢集中另外的server服務端的地址
```yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #hostname為hosts檔案中對映的地址
client:
register-with-eureka: false #false表示不向註冊中心註冊自己
fetch-registry: false #false表示自己就是註冊中心,職責是維護例項,不參加檢索
service-url:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #設定eureka server的互動地址
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #其他兩個服務端的地址
```
6. 修改Eureka Client模組的application.yml檔案,使其向叢集註冊服務
- service-url下的defaultZone節點:填入叢集中需要向其註冊server服務端的地址
```yml
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
```
7. 訪問地址
``` shell
http://eureka7001.com:7001
http://eureka7002.com:7002
http://eureka7003.com:7003
```
Eureka與Zookeeper對比
CAP設計原則不同
Eureka遵守AP,Zookeeper遵守CP(C:強一致性,A:高可用,P:分割槽容錯性,三者只能選其二,高併發下P必選)
網路波動下兩者的處理對比
| Zookeeper | Eureka |
| :--------------------------------------- | ---------------------------------------- |
| 當網路出現故障時,剩餘zk叢集會發起投票選舉新的leader,但是此過程會持續30~120s,此過程對於高併發來說十分漫長,會導致整個註冊服務的癱瘓,這是不可容忍的 | 在15分鐘內85%的節點都沒有心跳,則註冊中心 會認為客戶端與之出現了網路故障,則會進入自動保護模式。1.Eureka不會移除沒有收到心跳的服務;2.新的服務仍能在服務端註冊,但是暫時不會被同步到其他節點上直到網路穩定 |
結論
Eureka可以很好的應對網路故障導致部分節點失去連線的情況,而不會像zookeeper那樣導致整個註冊服務系統的癱瘓。
Ribbon負載均衡
Spring Cloud Ribbon是基於Netflix Ribbon實現的一套==客戶端==負載均衡工具。Ribbon會自動幫助你基於某種規則(簡單輪詢、隨機連線等),也可以實現自定義的負載均衡演算法。
[Ribbon原始碼]: https://github.com/Netflix/Ribbon
負載均衡
- 英文名稱:Load Balance,微服務或分散式叢集中常用的一種應用
- 簡單來說負載均衡就是將使用者的請求ping平攤的分配到多個任務上,從而是系統達到HA(高可用)
- 兩種負載均衡:
2. 程序內LB:騙軟體, 將LB邏輯整合到消費方,消費方從服務註冊中心指導哪些地址可用,再自己選擇一個合適的伺服器。
#### Ribbon初步配置
- ==Ribbon是客戶端負載均衡工具!!!Ribbon是客戶端負載均衡工具!!!Ribbon是客戶端負載均衡工具!!!所以應該配置在客戶端
1. 加入依賴,因為Riboon需要依賴Eureka執行,所以要同時加入Eureka依賴
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
```
2. 對實現類加入@LoadBalanced註解
```java
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
```
3. 在application.yml檔案中配置向註冊中心註冊,如果是作為消費者模組不提供服務,不應該註冊自己
```yml
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
register-with-eureka: false #作為消費者不提供服務,不應該註冊自己
```
4. 主啟動類中加入@EnableEurekaClient註解
```java
@SpringBootApplication
@EnableEurekaClient
public class Consumer80_APP {
public static void main(String[] args) {
SpringApplication.run(Consumer80_APP.class,args);
}
}
```
5. 以上步驟1~4完成後即可在controller中直接透過服務名訪問系統中的微服務,服務名作為URI
```java
private static final String URL_PREFIX = "http://MICROSERVICECLOUD-DEPT/";
```
#### Ribbon負載均衡實現
架構示意圖:
![Ribbon負載均衡架構](E:\筆記\images\Ribbon負載均衡架構.png)
##### 實現方法
目標:構建provider集群后consumer透過負載均衡輪詢呼叫在Eureka中註冊的服務
1. 構建叢集,新開兩個provider模組,將原provider的==程式碼部分和pom.xml中依賴照搬==到新的provider中
2. 將原provider中application.yml檔案照搬到新provider,並修改埠號,若新的provider使用自己的資料庫,則修改資料庫資訊(其他配置也一樣,如修改別名)
3. 叢集中服務名稱必須一致!!!
```yml
spring:
application:
name: microservicecloud-dept #同一叢集下必須使用同一服務名!!!!!
```
4. 啟動服務,進行測試
##### 總結
Ribbon其實就是一個軟負載均衡的客戶端元件,可以和其他需要請求的客戶端結合使用。
### Ribbon核心元件IRule
IRule:根據特定演算法從服務列表中選取一個需要訪問的服務
#### 七大方法
==IRule是一個介面,七大方法是其自帶的落地實現類==
- RoundRobinRule:輪詢(預設方法)
- RandomRule:隨機
- AvailabilityFilteringRule:先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,還有併發的連線數量超過閾值的服務,然後對剩餘的服務進行輪詢
- WeightedResponseTimeRule:根據平均響應時間計算服務的權重。統計資訊不足時會按照輪詢,統計資訊足夠會按照響應的時間選擇服務
- RetryRule:正常時按照輪詢選擇服務,若過程中有服務出現故障,在輪詢一定次數後依然故障,則會跳過故障的服務繼續輪詢。
- BestAvailableRule:先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,然後選擇一個併發量最小的服務
- ZoneAvoidanceRule:預設規則,符合判斷server所在的區域的效能和server的可用性選擇服務
#### 切換規則方法
只需在==配置類==中配置一個返回具體方法的bean即可
```java
@Bean
public IRule MyRule(){
return new RandomRule();
}
```
### 自定義Ribbon負載均衡演算法
#### 配置及包位置
1. 自定義的Ribbon演算法類不能放在主啟動類所在的包及子報下(確切來說是不能放在@ComponentScan註解的包及子包下),否則會被全域性應用到Ribbon服務中。應該把自定義演算法類放在另外新建的包下,且這個類應該是為==配置類==。(其實與普通切換負載均衡規則類似,只不過是位置不同而已,普通的可以放在主啟動類所在的包,自定義的要放在外面的包下)
2. 主啟動類新增@RibbonClient(name = "微服務名",configuration = XXX.class)註解指定需要用到負載均衡的微服務名及自定義演算法的class物件。
```java
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MyRule.class)
public class Consumer80_APP {
public static void main(String[] args) {
SpringApplication.run(Consumer80_APP.class,args);
}
}
```
####透過修改原始碼獲得自定義演算法
目標:每個服務呼叫5次後再進行輪詢(呼叫次數不是很對,懶得改了)
```java
package com.Rules;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.RoundRobinRule;
import com.netflix.loadbalancer.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class MyRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private int total = 0;
private int currentIndex = 0;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public MyRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
public MyRule(ILoadBalancer lb) {
this();
setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (total > 5) {
total = 0;
int nextServerIndex = incrementAndGetModulo(serverCount);
currentIndex = nextServerIndex;
server = allServers.get(nextServerIndex);
}else {
if (currentIndex>=serverCount) {
currentIndex = 0;
}
server = allServers.get(currentIndex);
total++;
}
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
/**
* Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
*
* @param modulo The modulo to bound the value of the counter.
* @return The next value.
*/
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
```
## Feign負載均衡
Feign是一個宣告式WebService客戶端,使用方法時定義一個介面並在上面添加註解即可。Feign支援可拔插式的編碼器和解碼器。Spring Cloud對Feign進行了封裝,使其支援SpringMVC和HttpMessageConverters。Feign可以與Eureka和Ribbon組合使用以支援負載均衡。
[Feign原始碼]: https://github.com/OpenFeign/Feign
### 使用案例
1. 新建Feign模組,加入依賴(其實跟80消費者差不多,主要是多了Feign依賴)
```xml
<dependencies>
<dependency>
<groupId>com.XXX</groupId>
<artifactId>microservice-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
```
2. 因為Feign開發其實是面向介面程式設計,所以Feign介面可以放在api模組中供各模組使用,所以要在api模組中新增Feign依賴
3. 在api中編寫介面,介面上新增@FeignClient註解,並透過value指定作用的微服務名
```java
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService {
@PostMapping("/dept")
public boolean addDept(Dept dept);
@GetMapping("/dept")
public List<Dept> findAll();
@GetMapping("/dept/{id}")
public Dept findById(@PathVariable("id")Integer id);
}
```
4. 在Feign模組中編寫Controller,並注入FeignClient介面,直接呼叫service介面中的方法即可(因為宣告Feign介面時已經指定過微服務,所以訪問時會正確地找到微服務)
```java
@RestController
@RequestMapping("/consumer")
public class ConsumerDeptController {
@Autowired
private DeptClientService service;
@PostMapping("/dept")
public boolean addDept(Dept dept){
return service.addDept(dept);
}
@GetMapping("/dept")
public List<Dept> findAll(){
return service.findAll();
}
@GetMapping("/dept/{id}")
public Dept findById(@PathVariable("id")Integer id){
return service.findById(id);
}
}
```
5. 修改Feign模組的主啟動類,加入@EnableFeignClients註解和@ComponentScan註解(主要是掃描api中宣告的介面)
```java
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.XXX"})
@ComponentScan("com.XXX")
public class Consumer80Feign_APP {
public static void main(String[] args) {
SpringApplication.run(Consumer80Feign_APP.class,args);
}
}
```
6. 啟動後訪問,即會按照輪詢的方式呼叫provider叢集
### 總結
- Feign透過介面方法呼叫REST服務,在Eureka中查詢對應的服務
- Feign集成了Ribbon技術,所以也支援負載均衡(輪詢)
## Hystrix斷路器
### 分散式系統面臨的問題
#### 扇出
多個微服務互相呼叫的時候,如果A呼叫B、C,而B、C又繼續呼叫其他微服務,這就是扇出(像一把扇子一樣慢慢開啟。
#### 服務雪崩
- 對於高流量的應用來說,單一的後端依賴會導致伺服器所有的資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多的級聯故障。這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程式或系統。
### Hystrix介紹
Hystrix是一個用於處理分散式系統延遲和容錯的開源庫。分散式系統中,依賴避免不了呼叫失敗,比如超時,異常等。Hystrix能保證在出現問題的時候,不會導致整體服務失敗,避免級聯故障,以提高分散式系統的彈性。
Hystrix類似一個“斷路器”,當系統中異常發生時,斷路器給呼叫返回一個符合預期的,可處理的FallBack,這樣就可以避免長時間無響應或丟擲異常,使故障不能再系統中蔓延,造成雪崩。
#### 服務熔斷
熔斷機制的註解是@HystrixCommand
熔斷機制是應對雪崩效應的一種鏈路保護機制,一般存在於服務端
-當扇出鏈路的某個服務出現故障或響應超時,會進行服務降級,進而熔斷該節點的服務呼叫,快速返回“錯誤”的相應資訊。、
Hystrix的熔斷存在閾值,預設是5秒內20次呼叫失敗就會觸發
[Hystrix原始碼]: https://github.com/Netflix/Hystrix
##### 熔斷案例
1. 構建一個新的provider module(如複製8001module)
2. pom.xml加入hystrix依賴(一定要配合Eureka)
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
```
3. application.xml中配置埠和Eureka資訊(必配)和其他框架的配置資訊(可選,如mybatis)
4. 編寫具體業務邏輯
5. controller類中,在需要配置Fallback的方法上加入@@HystrixCommand(fallbackMethod = "XXX")註解,XXX為FallBack方法名本例中作為測試所以丟擲了異常
```java
@ResponseBody
@GetMapping("/dept/{id}")
@HystrixCommand(fallbackMethod = "nullDeptFallBack")
public Dept findById(@PathVariable("id")Integer id) {
Dept dept = deptService.findById(id);
if (null == dept){
throw new RuntimeException("返回值為空!");
}
return dept;
}
```
6. 根據需要配置FallBack的方法返回值編寫程式碼
```java
public Dept nullDeptFallBack(@PathVariable("id")Integer id) {
System.out.println(111);
return new Dept().setId(id).setDeptName("nullName").setDbSource("nullDB");
}
```
7. 主啟動類中加入@EnableCircuitBreaker註解
8. 開啟服務,測試
#### 解耦與降級處理
##### 降級
- 當系統整體資源快不夠的時候,忍痛將部分服務暫時關閉,帶渡過難關後,再重新開啟。
- 降級處理時在客戶端完成的,與服務端沒有關係
- 理解:所謂降級,一般是從整體負荷考慮,當某個服務熔斷之後,伺服器將不再被呼叫,此時客戶端可以自己準備一個本地的FallBack回撥,返回一個預設值。這樣做雖然服務水平下降,但好歹可用,比直接掛掉好。
##### 為什麼要解耦
如果按照上面的熔斷案例來做的話,Controller下的每個方法,都要給其編寫一個FallBack方法,當方法慢慢變多,就會造成程式碼膨脹,一個是增加編寫的工作量,另外一個也會增大維護的難度,程式碼的耦合度也會高,是十分不合理的,所以要將其解耦。
##### 解耦思路
因為服務端的是透過實現介面訪問服務端的,如果在父介面上實現了FallBack方法,透過這樣一種方式去維護起來就能實現解耦,也順便完成了降級的機制。
##### 解耦&降級案例
1. 在api模組中新建實現了FallbackFactory<T>介面的類,其中泛型T就是我們需要維護其FallBack的介面方法,並實現其create方法,在create方法中返回實現了T的物件,使用匿名內部類實現T。==注意:這個類一定要加@Component註解!!這個類一定要加@Component註解!!這個類一定要加@Component註解!!
```java
import com.XXX.entity.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DeptClientServiceFallBackFactory implements FallbackFactory<DeptClientService> {
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
public boolean addDept(Dept dept) {
return false;
}
public List<Dept> findAll() {
return null;
}
public Dept findById(Integer id) {
return new Dept().setId(id).setDeptName("伺服器跪了,").setDbSource("遲點來吧");
}
};
}
}
```
2. 修改步驟1中傳入的泛型T介面,新增@FeignClient(fallbackFactory = T.class)註解
```java
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)
public interface DeptClientService {
@PostMapping("/dept")
public boolean addDept(Dept dept);
@GetMapping("/dept")
public List<Dept> findAll();
@GetMapping("/dept/{id}")
public Dept findById(@PathVariable("id")Integer id);
}
```
3. 修改consumer feign模組的application.xml檔案,開啟hystrix(注:在IDEA中可能沒有程式碼提示,開啟的true也沒有正常高亮,但好像不需要做額外操作也不影響結果)
```yml
feign:
hystrix:
enabled: true
```
4. 開啟服務並測試
#### HystrixDashboard服務監控
介紹:SpringCloud對Hystrix Dashboard進行了整合,可以對透過Hystrix發起的請求進行準實時統計,並以報表和圖形的形式展示給使用者(包括每秒執行多少次請求成功和失敗等)。
##### 配置案例
1. 新建HystrixDashboard模組,pom.xml檔案加入HystrixDashboard依賴,其他依賴包括Feign,Ribbon,Eureka(可參考80模組的依賴)
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
```
2. application.yml檔案中配置埠(如9001)
3. provider類中確認要加入actuator依賴(此為監控依賴)
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
```
4. 編寫主啟動類,上標@EnableHystrixDashboard標註
```java
@SpringBootApplication
@EnableHystrixDashboard
public class DashBoard9001_APP {
public static void main(String[] args) {
SpringApplication.run(DashBoard9001_APP.class,args);
}
}
```
5. 啟動服務進行測試,訪問地址:http://localhost:9001/hystrix,(根據配置埠號),看到刺蝟表示已經配置好了
##### 如何監控
- 在dashboard介面中,填入需要監控的服務地址和埠號加上\hystrix.stream和監測間隔即可進入監控。(如http://localhost:8001/hystrix.stream
##### 監控分析
- 七色:進入監控介面後會有其中顏色的數字,其含義可以對應右上角相同顏色的單詞表示的狀態,其值代表該狀態下觸發的次數
- 一圈:圈的大小代表該服務的流量,圈越大流量越大
- 一線:代表監控間隔中,服務被訪問的頻率的折線圖
- 透過觀察這些就可以在大量的例項中找出故障例項和高壓例項進行修復和維護。
![Dashboard監控說明圖](E:\筆記\images\HystrixDashboard監控說明圖.png)
## Zuul路由閘道器
### 概述
2. 路由:Zuul可以對外部訪問實現統一的入口
3. 過濾:Zuul可以對外部訪問進行干預,如請求校驗、服務聚合等
4. Zuul需要配合Eureka使用,需要在Eureka中註冊並獲得其他微服務的資訊
[Zuul的原始碼]: http://github.com/Netflix/zuul
### 基本配置
1. 構建新的Zuul模組並在pom.xml中加入依賴(Zuul和Eureka必須同時加入)
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
```
2. 新建application.yml檔案並配置(一定要向Eureka註冊,因為Zuul本身也是一個微服務)
```yml
server:
port: 9527
spring:
application:
name: microservicecloud-zuul #為這個服務取名,非常重要!!!!!
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul.com
prefer-ip-address: true
```
3. 修改hosts檔案(非必須,不過能更好看出效果)
```shell
127.0.0.0 zuul.com
```
4. 建立主啟動類,並加入@EnableZuulProxy註解
```java
@SpringBootApplication
@EnableZuulProxy
public class Zuul9527_APP {
public static void main(String[] args) {
SpringApplication.run(Zuul9527_APP.class,args);
}
}
```
5. 啟動測試,訪問規則:步驟3中指定對映+埠號+微服務名稱+訪問路徑。
例子:http://zuul.com:9527/microservicecloud-dept/dept
### 路由訪問對映規則
#### 服務名對映和統一公共字首
當不向暴露真實的服務名時,可以對服務名進行對映,只需在application.yml中配置即可,==具體作用看註釋==
```yml
zuul:
routes:
#dept0是可以自定義的只是作為區分,沒什麼具體意義
dept0.serviceId: microservicecloud-dept
#路徑也是自定義的,支援萬用字元
dept0.path: /dept10/**
#需要隱藏的服務名,可以使用萬用字元,配置之後透過這個微服務名訪問就失效了
ignored-services: microservicecloud-*
#設定統一公共字首,設定後訪問路徑:http://zuul.com:9527/nihao/dept10/dept/3
prefix: /nihao
```
注:因為Zuul是針對外部訪問管理的,所以配置了隱藏的服務,在系統中其他模組進行服務名訪問時依然可以正常執行的,這點可以透過開啟consumer模組進行驗證!
## SpringCloud Config 分散式配置中心
分散式系統面臨的配置問題:微服務意味著將單體應用拆分成一個個自服務,這些服務都是要相應的配置資訊才能執行,隨著系統內微服務數量越來越多,配置資訊也不斷地增多,所以一套集中式的、動態的配置管理設施是必不可少的。
### 概述
- SpringCloud Config是一個提供外部集中式配置管理的設施,配置伺服器為各種不同的額微服務應用提供了一箇中心化的外部配置
- SpringCloud Config分為客戶端和服務端兩部分
1. 服務端:分散式配置中心,是一個獨立的微服務,用來連線併為客戶端提供配置資訊,加密/解密資訊等訪問介面
2. 客戶端:透過指定的配置中心獲取配置資源,cloud推薦用git來儲存配置資訊
- SpringCloud Config解決的問題:
1. 集中管理配置檔案
2. 不同環境不同配置,動態化的配置更新
3. 執行期間動態調整配置,不再需要在每個服務部署的機器上編寫配置檔案,讓服務中心統一為服務拉取配置檔案
4. 當配置發生變動時,服務不需要重啟即可感知配置變化並應用
5. 將配置資訊以REST介面形式暴露
![SpringCloud Config架構圖](E:\筆記\images\SpringCloud Config架構圖.png)
### SpringCloud Config服務端與Github通訊
目標:將配置檔案部署在github,Config服務端從github獲取配置
#### 案例
1. 新建ConfigServer模組並配置pom.xml
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>4.10.0.201712302008-r</version>
</dependency>
```
2. 建立遠端倉庫,並上傳配置檔案。如下例
```yml
spring:
profiles:
active:
- dev
---
spring:
profiles: dev
application:
name: microservicecloud-config-XXX-dev
---
spring:
profiles: test
application:
name: microservicecloud-config-XXX-test
```
3. 在application.xml檔案中配置github地址
```yml
server:
port: 3344
spring:
application:
#為這個服務取名,非常重要!!!!!
name: microservicecloud-config
cloud:
config:
server:
git:
# uri填github上倉庫地址
uri: https://github.com/XXXX/SpringCloud_Configuration.git
```
4. 編寫主啟動類,加入@EnableConfigServer註解
```java
@SpringBootApplication
@EnableConfigServer
public class ConfigServer3344_APP {
public static void main(String[] args) {
SpringApplication.run(ConfigServer3344_APP.class,args);
}
}
```
5. 啟動服務並嘗試訪問配置檔案,有以下五種訪問配置規則
- {application}:配置檔案的檔名
- {profile}:讀取的環境
- {lable}:分支
```SHELL
/{application}/{profile}[/{lable}]
/{application}-{profile}.yml
/{lable}/{application}-{profile}.yml
/{application}-{profile}.properties
/{lable}/{application}-{profile}.properties
```
可用例子(返回格式可能不大相同,但返回值相同):
- http://config3344.com:3344/application-test.yml
- http://config3344.com:3344/master/application-dev.yml
- http://config3344.com:3344/application-test.yml/master
不可用例子:
- 沒有該環境,返回空值:http://config3344.com:3344/application-test11.yml/master
- 沒有配置檔案,犯回錯誤頁面:http://config3344.com:3344/lkjliiusdfsddsfl.yml
### bootstrap.yml介紹
- bootstrap.yml比application.yml具有更高的優先順序。
- bootstrap.yml是系統級的資源配置項,application.yml是使用者級的資源配置項。
- SpringCloud會建立"BootStrap Context"作為"ApplicationContext"的==父上下文==。初始化的時候BootStrap Context負責從外部源載入配置屬性並解析。這兩個上下文共享一個"Environment",BootStrap 具有更高優先順序,他們不會被本地配置覆蓋。
### 客戶端的配置與測試
介紹:客戶端主要是在==載入時==透過config server服務端獲得github配置倉庫的地址,進而透過目標配置檔案的檔名獲取相應的配置,最後將取得的配置對自身資源進行賦值並提供訪問
#### 實現過程
1.建立遠端配置yml檔案並上傳到github上。如下測試案例因為需要進行測試,所以配置了兩個profiles方便切換並觀察
```yml
spring:
profiles:
active:
- dev
---
server:
port: 8201
spring:
profiles: dev
application:
name: microservicecloud-config-client-dev
eureka:
client:
service-url:
defaultZone: http://eureka-dev.com:7001/eureka/
---
server:
port: 8202
spring:
profiles: test
application:
name: microservicecloud-config-client-test
eureka:
client:
service-url:
defaultZone: http://eureka-dev.com:7001/eureka/
```
2. 本地建立config client模組,並配置好pom.xml,以下本元件是必選依賴
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
```
3. 編寫bootstrap.yml配置檔案,這個步驟比較關鍵,主要是根據此處的配置資訊去尋找config server以獲得github倉庫地址和配置中的目標配置檔案檔名
```yml
spring:
cloud:
config:
name: application_config #需要從github上讀取的資源名稱,注意沒有yml字尾名
profile: test #本次訪問的配置項
label: master
uri: http://config3344.com:3344 #本微服務啟動後先去找3344號服務,透過SpringCloudConfig獲取GitHub的服務地址
```
4. application.yml檔案在本module中其實是可寫可不寫的,為了習慣需要,還是給他寫了個名字
```YML
spring:
application:
name: microservicecloud_config
```
5. 修改host檔案增加對映,和3344一樣
6. 編寫主啟動類,沒什麼特別的,最基本的主啟動類
7. 編寫controller,此步驟也比較關鍵,主要是利用@Value註解賦值,若寫錯了bootstrap.yml中的配置檔名稱而沒有獲取到配置,啟動時這裡會丟擲異常。@Value中註解的引數即是目標配置檔案中的引數值,使用El表示式獲取
```java
@org.springframework.web.bind.annotation.RestController
public class RestController {
@Value("${server.port}")
private String port;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaZone;
@Value("${spring.application.name}")
private String name;
@GetMapping("/config")
@Override
public String toString() {
return "RestController{" +
"port='" + port + '\'' +
", eurekaZone='" + eurekaZone + '\'' +
", name='" + name + '\'' +
'}';
}
}
```
8. 先啟動config server服務,然後再啟用本client服務,根據profiles的值訪問對應的埠即可。如本例選擇的是test,則訪問埠為:http://config3355.com:8202/config。(config3355.com為hosts檔案中配置了的對映)
### SpringCloud的配置實戰
介紹:其實前面client的配置案例都是幫助理解這個元件為主,並沒有很大的實際意義。。。。。。這節的案例中是配置一個Provider,一個eureka,他們的配置統一在github上獲取,實現統一配置分散式管理和多環境變更,這個才比較有實戰意義。
#### 實現過程
1. 先寫好provider和Eureka的配置yml檔案,這兩個檔案和平常配置沒什麼不同,因為這裡主要是說config,所以就沒有配置叢集,上傳yml到github
Eureka配置檔案示例:
```yml
spring:
profiles:
active:
- dev
---
spring:
profiles: dev
application:
name: microservicecloud-eureka-client-dev
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #hostname為hosts檔案中對映的地址
client:
register-with-eureka: false #false表示不向註冊中心註冊自己
fetch-registry: false #false表示自己就是註冊中心,職責是維護例項,不參加檢索
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #設定eureka server的互動地址
---
spring:
profiles: test
application:
name: microservicecloud-eureka-client-dev
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #hostname為hosts檔案中對映的地址
client:
register-with-eureka: false #false表示不向註冊中心註冊自己
fetch-registry: false #false表示自己就是註冊中心,職責是維護例項,不參加檢索
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #設定eureka server的互動地址
```
Provider配置檔案示例:
```yml
spring:
profiles:
active:
- dev
---
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.XXX.entity
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
profiles: dev
application:
name: microservicecloud-dept #為這個服務取名,非常重要!!!!!
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://192.168.88.246:3306/cloudDB01
username: root
password: 123456
dbcp2:
min-idle: 5 #最小連線數
initial-size: 5 #初始化連線數
max-total: 10 #最大連線數
max-wait-millis: 200 #等待連線最長的超時時間
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: dept8001
prefer-ip-address: true
---
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.XXX.entity
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
profiles: test
application:
name: microservicecloud-dept #為這個服務取名,非常重要!!!!!
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://192.168.88.246:3306/cloudDB02
username: root
password: 123456
dbcp2:
min-idle: 5 #最小連線數
initial-size: 5 #初始化連線數
max-total: 10 #最大連線數
max-wait-millis: 200 #等待連線最長的超時時間
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: dept8001
prefer-ip-address: true
```
2. 新開eureka和provide的模組並在pom.xml中新增依賴,其他必要依賴和之前的案例一樣,但是config的依賴一定要新增上
```XML
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
```
3. 兩個模組都要編寫bootstrap.yml檔案,和上面的案例一樣
```yml
spring:
cloud:
config:
name: application_config #需要從github上讀取的資源名稱,注意沒有yml字尾名
profile: test #本次訪問的配置項
label: master
uri: http://config3344.com:3344 #本微服務啟動後先去找3344號服務,透過SpringCloudConfig獲取GitHub的服務地址
```
4. (可選)兩個模組中編寫application.yml檔案,可以配置一下服務名
```yml
spring:
application:
name: microservicecloud_config
```
5. 兩個模組的主啟動類,Eureka的正常加EurekaServer註解,Provider加EurekaClient註解,不詳述
6. 編寫Provider模組的業務程式碼
7. 啟動測試,因為這兩個模組都要透過3344ConfigServer為其在github上獲取配置,所以要先啟動3344模組,然後再一次啟動eureka和provider模組,進行測試即可。