1 Spring Cloud OpenFeign
1.1 遠程調用需求出現的原因
在使用微服務時,服務器之間要想互相調用,需要通過注冊中心,但是注冊中心最重要的作用是注冊和管理服務器,雖然提供了方法實現服務器互相調用,也自動實現了負載均衡,但是實現過程要寫的代碼太繁瑣了
如圖通過注冊中心提供的方法實現服務器之間互相調用,在實際開發中不希望手寫那么多調用代碼,所以就出現了遠程調用需求

假如order模塊需要調用user模塊,只需要通過openFeign就能找到,而openFeign通過連接注冊中心實現查找服務器,需要調用的模塊存在,再去調用服務

1.2 Spring Cloud OpenFeign 是什么
Spring Cloud OpenFeign 基於Netflix Feign 實現的,並且實現了聲明式的Web服務客戶端定義方式,它使得web服務客戶端更容易編寫。
為了更方便的與Spring 組件集成,Spring Cloud還為OpenFeign提供了SpringMVC的支持,所以client接口可以直接把被調用模塊的controller方法拿過來。
OpenFeign配合Eureka和Ribbon可以很方便的實現客戶端負載均衡。所謂客戶端負載均衡,就是OpenFeign在拉取某個業務模塊目前可用的tomcat服務器后,會通過隨機、輪詢、均衡請求數量等機制對請求進行分流。(不過新版springboot中的OpenFeign似乎修改了負載均衡實現方式,已經沒有ribbon了,而負載均衡策略只有“輪詢”這一種方式)

1.3 環境要求
作為遠程調用的分布式組件,由於Spring Cloud OpenFeign是基於Netflix Feign實現的,所以它也與Spring Cloud Eureka一樣都屬於Netflix套件,所以
版本要求與Spring Cloud Eureka一樣
1.4 使用方法
1.4.1 官方說明
根據官方文檔,只需要為springboot啟動類和調用別的模塊的方法的接口添加注解即可使用,相較於注冊中心使用HttpClient(現在是RestTemplate)的調用方式,OpenFeign更簡單明了,無論是配置還是使用起來都很方便。

1.4.2 引入pom依賴
首先引入pom依賴


1.4.3 啟動類上使用注解
然后在springboot啟動類上添加注解

1.4.4 接口上使用注解
根據需求在order模塊下創建XXXClient接口,例如order模塊要調用user模塊,此時就要創建一個UserClient接口,並把User模塊的controller接口放入,最后使用@FeignClient注解

User模塊中,需要放入UserClient接口的方法名和請求路徑

最終UserClient接口代碼如下,Client接口中的方法除了請求路徑和請求方式需要與被調用的接口一致以外,方法名和參數名並不是必須得一致。

@FeignClient注解中的屬性值不寫屬性名時默認為name屬性,這個name屬性就是需要調用的系統(user模塊)的spring.application.name 屬性的值(user模塊注冊到Eureka注冊中心的名字)

1.5 公共模塊
1.5.1 存在的問題
在上面的使用案例中,UserClient放置在order模塊中,這就存在一個問題,如果UserClient中的方法返回的是一個user模塊中的entity而不是現在這種object,由於order模塊中不存在user里的entity,就會報錯
假如把user模塊中的entity復制到order模塊中,那么當User模塊的負責人修改entity,還得通知其他調用這個UserClient的人注意修改
所以最佳做法是把UserClient提取到一個公共模塊commons中
1.5.2 創建公共模塊
創建一個commons模塊,pom依賴中只需要聲明一個打包方式以及父模塊,其他依賴都不需要,當然,如果真的有需求,比如junit,那就選擇性留一些依賴

1.5.3 解決方法
現在可以把所有Client類以及需要的eneity都復制到公共模塊中

接着讓所有子模塊在pom文件中引用這個公共模塊,依賴要給出公共模塊的組名、模塊名、版本號

1.5.4 父模塊不能引用這個公共模塊
千萬不要在父模塊的pom文件中引用公共模塊,因為公共模塊已經掛在了父模塊下,如果父模塊又引用公共模塊,就會導致整個項目在打包時陷入死循環
1.5.5 公共模塊可以放置其他東西
公共模塊除了放置遠程調用組件需要用到的client接口、client接口依賴的entity,也可以放一些公共配置,比如攔截器
保證每個業務模塊盡量只放自己模塊的controller、service、mapper、entity、VO
1.6 解決項目打包報錯
報錯

說明
控制台提示打包錯誤,其實是因為剛才創建的公共模塊commons不屬於一個springboot項目,它只是起到一個工具類的作用

而父模塊的pom中設定了打包方式,那么一旦項目打包,父模塊就會基於pom設定的打包方式為所有子模塊打包,這就會導致打包commons出錯,只需要把父模塊中的這段打包依賴刪掉即可

此時雖然父模塊中的打包方式被刪除了,但是各個子模塊的pom文件中依然存在打包方式,運行整個項目時,這些子模塊就會打包,而公共模塊Commons不受影響,這就解決了打包報錯的問題
1.7 解決子模塊的啟動類掃描不到公共模塊的問題
1.7.1 @SpringBootApplication問題
報錯

說明
如圖是springboot啟動類的默認寫法,該寫法會把當前啟動類的package作為路徑,此時@SpringBootApplication只能掃描自身所在層級以及子級的文件,自然沒辦法掃描到另一個模塊下的UserClient接口

再舉一個例子
假如現在有一個類在啟動類上層,如圖

此時TestController如圖

前端訪問時就會報錯,因為user模塊的springboot啟動類掃不到這個TestController

所以需要通過設置scanBasePackages告訴springboot啟動類,要從哪開始掃描,通過屬性名可以知道,這是一個數組,可以寫入多個包路徑

1.7.2 @EnableFeignClients問題
報錯

說明
@EnableFeignClients和@springbootapplication一樣,默認寫法下只能掃描自己所在層級和所有子級的@FeignClient注解,無法掃描到其他模塊中的@FeignClient注解,因此提示UserClient沒有找到

解決辦法
在需要使用遠程調用的order模塊的springboot啟動類上,給@EnableFeignClients設置要掃描的路徑

2 spring Cloud Ribbon
2.1 介紹
Ribbon是一個客戶端負載均衡器,在Feign中實際上也默認使用了Ribbon來做負載,且該功能是默認啟用的。
客戶端負載實際上跟Nginx類似,都是將訪問請求轉發到其他服務器。它通過Eureka注冊中心的Application名稱來獲取服務器列表,然后在調用時通過負載策略來訪問具體的服務器地址。
2.2 環境配置說明
OpenFeign默認集成Ribbon,如果使用的是舊版springboot,那么無需做什么配置,可以直接使用
在新版springboot中,集成的OpenFeign已經沒有Ribbon了,估計是修改了實現負載均衡的方法
下面的知識點都依照舊版springboot中OpenFeign繼承了ribbon來說明
2.3 修改ribbon的負載策略
ribbon默認開啟輪詢策略,也可以手動設置為其他負載策略
| 策略類名 | 策略描述 |
|---|---|
| AvailabilityFilteringRule | 過濾掉那些因為一直連接失敗的被標記為circuit tripped的后端Server,並過濾掉那些高並發的后端Server(active connections 超過配置的閾值) 一句話:把請求轉到ribbon認為比較空閑的服務器上 |
| BestAvailableRule | 選擇一個最小的並發請求的Server |
| RandomRule | 隨機選擇一個Server |
| RetryRule | 重試查找選擇一個可用的Server |
| RoundRobinRule | 輪詢選擇Server(默認策略) |
| WeightedResponseTimeRule | 根據響應時間分配一個weight,響應時間越長,weight越小,被選中的可能性越低。(也就是根據服務器性能分配請求) |
| ZoneAvoidanceRule | 復合判斷。判斷區域是否可用,並過濾掉區域中的連接過多的Server |
配置負載策略也比較簡單,只需要在調用方(order模塊)的yml中聲明被調用方在注冊中心的名字以及負載策略的全類名,負載策略是按照服務名單獨來進行配置的
user-system:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3 spring Cloud Hystrix
3.1 介紹
Netflix提供了一個叫Hystrix的類庫,它實現了斷路器模式,也就是提供了服務熔斷機制。
在微服務架構中,通常一個微服務會調用多個其他的微服務。當某一個環節的微服務調用失敗后,它將會導致上一層服務失敗,服務訪問越大則失敗率越高,而這一連串的失敗就是雪崩效益,下層失敗導致上層所有服務崩潰,因此需要一個服務熔斷機制,避免越錯越多。
Hystrix的作用就是,當發現某一服務調用失敗后,告知調用者該接口失敗,從而避免調用者服務資源消耗。
而這樣的處理就是我們經常會在微博以及淘寶上經常看到的繁忙頁面或相關提示,這實際上就是發生了服務熔斷,過幾分鍾后就好了。
實際可見:



3.2 原理圖
當訪問量超過設定的閾值時,斷路器起作用,Hystrix將執行fallback方法來返回給api調用,也就是讓接口對所有請求返回失敗,不再處理這些請求,給后端運維時間處理宕機的服務器。

3.3 環境要求
與其他netflix組件版本一致
3.4 單獨使用Hystrix
3.4.1 引入pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
3.4.2 啟動類使用注解
在各個子模塊的springboot啟動類上使用@EnableCircuitBreaker

如果本來就要使用@EnableEurekaClient @EnableFeignClients 和@EnableCircuitBreaker 那么可以使用一個注解替代這三個注解——@SpringCloudApplication

進入這個注解,可以看到它是哪些注解的延伸注解,但是可以看到,它並不能直接配置這三個延伸注解的scanBasePackages和basePackages,所以我們需要自定義一個類似@SpringCloudApplication的注解,實現合並注解+配置注解

3.4.3 使用Hystrix
在服務調用方的controller層的接口上使用@HystrixCommand注解標記在需要熔斷的方法上,使用fallbackMethod聲明當接口熔斷時需要調用的方法A。
@HystrixCommand(fallbackMethod="發生熔斷時執行的controller方法")
方法A可以返回一個默認提示文案或者默認對象,且方法A的入參參數列表必須與使用了@HystrixCommand的接口方法的參數列表保持一致。

3.4.4 局部配置
3.4.4.1 說明
通過設置配置項,可以修改發生服務熔斷時熔斷多久自動恢復
3.4.4.2 常用參數說明
Hystrinx的熔斷由三個參數的設置共同完成
| 屬性 | 說明 |
|---|---|
| circuitBreaker.requestVolumeThreshold | 默認值20,表示10秒內20個請求為一個輪回 |
| circuitBreaker.errorThresholdPercentage | 默認值是50,表示50%的錯誤率 |
| circuitBreaker.sleepWindowInMilliseconds | 默認值是5000,表示熔斷后,拒絕所有請求5秒 |
3.4.4.3 配置方式
-
Hystrix的配置信息可以通過@HystrixCommand的commandProperties屬性來進行配置。
-
commandProperties是配置Hystrix配置的屬性,該屬性的值為@HystrixProperty類型的數組。
-
在@HystrixProperty中配置屬性名和屬性值即可完成屬性配置
-
Hystrix在熔斷期間會對服務進行一次請求測試,如果服務能夠正常訪問,則會重新關閉熔斷
下圖的配置代表10秒內20個請求中錯誤率達到百分之60以上,就會觸發服務熔斷,熔斷后拒絕請求50秒

3.4.4.4 其他可配置屬性一覽
更多可配屬性在HystrixCommandProperties類中查看。
超時配置
Hystrix默認超時時間是1秒鍾,當遠程服務調用超過1秒則會判定該遠程服務調用失敗。

execution.isolation.thread.timeoutInMilliseconds:連接超時時間,單位毫秒,默認為1秒。
3.4.5 類全局配置
按照上面的配置方式,若一個類中存在多個接口需要進行熔斷配置,則需要在每一個方法上加入注解和屬性配置,這樣非常麻煩。
Hystrix也提供了類全局配置來方便開發者進行參數設置,使用@DefaultProperties即可完成全局聲明,可以配置全局服務熔斷的參數以及觸發服務熔斷時被調用的方法
方法

發生服務熔斷時被調用的方法

注意點:
1. @DefaultProperties 和 @HystrixCommand可以共存,后者的優先級大於前者。
2. defaultFallback屬性指定的發生服務熔斷時被調用的方法的參數列表必須為空
3.5 Openfeign集成Hystrix
3.5.1 開啟Openfeign集成的Hystrix
Openfeign組件中默認集成了Hystrix,只需要在配置文件中開啟即可使用Hystrix的功能。
feign:
#開啟feign的hystrix
hystrix:
enabled: true
3.5.2 創建fallback類
在公共模塊Commons中創建一個fallback類,用於設置發生服務熔斷時被調用的方法,這個類放置位置如圖

具體代碼如下

說明:
fallback類通過實現Client接口,完成與client接口的綁定,這樣一旦client接口中的方法出現問題,就調用fallback類中的方法,由於接口中的方法返回的是對象,因此這里只能返回null
3.5.3 使用Hystrix
隨后直接在@FeignClient上使用fallback屬性指定fallback類

3.5.4 yml配置
直接在yml中對Hystrix進行屬性配置,實現全局配置,在yml中的配置實際上與@HystrixCommand相差無幾,只是在配置屬性前面多了hystrix.command.default
其中default代表默認配置,可以更改為具體某個@FeignClient的name,為每一個feign單獨配置
//配置超時配置
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 4000
//配置錯誤百分比
hystrix:
command:
default:
circuitBreaker:
errorThresholdPercentage: 60
3.6 公共返回類
3.6.1 微服務中返回給前端的數據
在上面創建的fallback類中,發生服務熔斷時不應該直接返回一個null,而是返回一個公共返回類,包含狀態碼、信息、數據
3.6.2 創建公共返回類
這個公共返回類寫在commons模塊中,代碼如下,實際開發時會封裝得更為精細,把狀態碼和信息用枚舉類進一步封裝

3.6.3 各個返回類型的改變
下面舉例部分方法的返回類型的變化
client接口的方法的返回類型變化

fallback類的方法的返回類型變化

controller類的方法的返回類型變化

3.7 fallbackFactory
基於一個工廠類創建Client接口的fallback類

對比之前直接創建Client接口的fallback類

無非是@FeignClient注解上,屬性名的區別,以及fallbackFactory會獲取client端的報錯信息

4 整體流程一圖流

