學習思路
- 名詞解釋
- 代碼實踐-基於註解、基於Feign
- 文末有驚喜
一、名詞解釋
- 服務熔斷:在分佈式系統中不可避免的會出現服務之間調用異常,一個接口的異常可能導致整個鏈路異常,服務熔斷就是防止這種級聯故障的發生,是異常服務快速返回備用數據,順利完成調用
- 服務降級:分佈式系統中,面對突發流量,系統可能出現負荷的情況,最終導致服務不可用,這個時候我們需要將一些非核心的服務進行降級(置爲不可用),以便節省出更多資源保證核心服務正常運行
相同點:
- 熔斷和降級都是保證服務在異常情況下還能正常運行,防止系統整體崩潰
- 都會導致部分服務短時間不可用
不同點:
- 服務熔斷:主要用於調用外部接口異常時進行快速返回,防止異常接口成爲系統瓶頸,甚至拖垮整個系統
- 服務降級:主要是整個系統出現負荷時手動/或預先設置某些非核心服務不可用
- 熔斷是系統自動判斷開啓關閉,降級是人爲手動或設置開啓關閉
二、代碼實踐-基於註解、基於Feign
1、網關層做熔斷降級,具體實現在:微服務-gateway-Filter-熔斷、限流、統一鑑權
個人建議:不建議在網關實現熔斷降級
原因
- 網關作爲下游業務系統的統一入口,不關心業務,也並不知道哪些是核心/非核心
- 服務熔斷正常來說需要針對業務去做一些備用數據或快速返回,應該針對業務制定,不應該在網關關心
- 網關下調用鏈上只有其中一個小服務異常,只需要熔斷這個小接口即可,如果在網關做可能熔斷了整個鏈路開通默認爲下游所有服務不可用
2、單個接口基於註解實現
1、首先引入jar包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2、在啓動類加上註解:@EnableHystrix
3、在方法上加@HystrixCommand註解
@HystrixCommand(
groupKey = "usernameGroup",commandKey = "usernameCommand",threadPoolKey = "usernameThread",
fallbackMethod = "getUsernameFallback",/*ignoreExceptions = Exception.class,*/
commandProperties = {
@HystrixProperty(name = "execution.timeout.enabled",value = "true"),
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout",value = "3000")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "101"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
}
)
@Override
public String getUsername(@RequestBody OrderDTO orderDTO) {
log.info("---------------------------=={}", JSON.toJSONString(orderDTO));
int i=1/0;
UserDTO userDTO=new UserDTO();
userDTO.setUserId("userid3");
userDTO.setUsername("username3");
String username = productService.getUsername(userDTO);
log.info("feign2=={}====={}",this.getClass().getSimpleName(),username);
return username;
}
註解屬性詳細見:https://github.com/Netflix/Hystrix/wiki/Configuration#coreSize
這裏只介紹幾個常用的
- commandKey:配置全局唯一標識服務的名稱,比如,庫存系統有一個獲取庫存服務,那麼就可以爲這個服務起一個名字來唯一識別該服務,如果不配置,則默認是@HystrixCommand註解修飾的函數的函數名。
- groupKey:一個比較重要的註解,配置全局唯一標識服務分組的名稱,比如,庫存系統就是一個服務分組。通過設置分組,Hystrix會根據組來組織和統計命令的告、儀表盤等信息。Hystrix命令默認的線程劃分也是根據命令組來實現。默認情況下,Hystrix會讓相同組名的命令使用同一個線程池,所以我們需要在創建Hystrix命令時爲其指定命令組來實現默認的線程池劃分。此外,Hystrix還提供了通過設置threadPoolKey來對線程池進行設置。建議最好設置該參數,使用threadPoolKey來控制線程池組。
- threadPoolKey:對線程池進行設定,細粒度的配置,相當於對單個服務的線程池信息進行設置,也可多個服務設置同一個threadPoolKey構成線程組。
- fallbackMethod:@HystrixCommand註解修飾的函數的回調函數,@HystrixCommand修飾的函數必須和這個回調函數定義在同一個類中,因爲定義在了同一個類中,所以fackback method可以是public/private均可。
- commandProperties:配置該命令的一些參數,如executionIsolationStrategy配置執行隔離策略,默認是使用線程隔離,此處我們配置爲THREAD,即線程池隔離。參見:com.netflix.hystrix.HystrixCommandProperties中各個參數的定義。
- threadPoolProperties:線程池相關參數設置,具體可以設置哪些參數請見:com.netflix.hystrix.HystrixThreadPoolProperties
- ignoreExceptions:調用服務時,除了HystrixBadRequestException之外,其他@HystrixCommand修飾的函數拋出的異常均會被Hystrix認爲命令執行失敗而觸發服務降級的處理邏輯(調用fallbackMethod指定的回調函數),所以當需要在命令執行中拋出不觸發降級的異常時來使用它,通過這個參數指定,哪些異常拋出時不觸發降級(不去調用fallbackMethod),而是將異常向上拋出。
- observableExecutionMode:定義hystrix observable command的模式;
- raiseHystrixExceptions:任何不可忽略的異常都包含在HystrixRuntimeException中;
- defaultFallback:默認的回調函數,該函數的函數體不能有入參,返回值類型與@HystrixCommand修飾的函數體的返回值一致。如果指定了fallbackMethod,則fallbackMethod優先級更高。
設置完HystrixCommand註解後,需要編寫程序運行異常的fallbackMethod
private String getUsernameFallback(OrderDTO orderDTO,Throwable throwable){
log.info("fallback====={}==={}",JSON.toJSONString(orderDTO),throwable.getMessage());
UserDTO userDTO=new UserDTO();
userDTO.setUserId("userid4");
userDTO.setUsername("username4");
return userDTO.getUsername();
}
這裏可以打印異常,返回兜底數據等,當然也可以直接返回空對象,只要調用發有針對性的處理即可
整體思路:
- 引入jar
- 啓動類加註解,啓動Hystrixy
- 在需要熔斷的方法上配置註解
- 編寫熔斷方法的fallbackMethod
3、單個接口基於Feign實現
這裏默認認爲FeignClient調用環境正常
1、在FeignClient接口添加fallbackFactory配置
@FeignClient(name = "hystrix-feign2",primary = false,fallbackFactory = HystrixClientFactory.class)
public interface UserService {
@PostMapping("/feign2/user/get")
UserDTO getUser(UserDTO userDTO);
}
2、編寫HystrixClientFactory:主要處理服務異常的fallback方法
@Component
@Log4j2
public class HystrixClientFactory implements FallbackFactory<UserService> {
@Override
public UserService create(Throwable throwable) {
log.error("{}{}",throwable.getMessage(),"==============");
return (userDTO)-> {
log.info("系統異常=={}",userDTO==null?"userDTO is null":userDTO.toString());
UserDTO dto=new UserDTO();
dto.setUsername("error-username");
dto.setUserId("error-userid");
return dto;
};
}
}
這裏需要注意的是要實現FallbackFactory接口,實現create方法,在方法裏返回我們要熔斷的接口即可,這裏只有一個可以直接用lambda表達式即可,多個方法可new接口實現逐個實現方法即可
3、開啓feign.hystrix.enabled=true:這個屬性默認是false必須在配置文件顯示開啓,當然還可以設置超時熔斷
hystrix:
command:
hystrix-feign2: #default全局有效,service id指定應用有效
execution:
timeout:
#是否開啓超時熔斷
enabled: true
isolation:
thread:
timeoutInMilliseconds: 5000 #斷路器超時時間,默認1000ms
feign.hystrix.enabled: true
題外話:至於你需要什麼樣的熔斷策略可以根據系統情況自己配置
比如10秒內錯誤率達到50%等
最後給個圖自己體會
三、服務降級
降級基本都是人工控制,比如系統監控到流量過大觸發我們之前的配置,系統某些非核心功能不可用,還可以利用配置中心動態配置開關,我們手動去修改使某些接口進入快速響應
文內代碼地址:https://gitee.com/carpentor/spring-cloud-example
公衆號主要記錄各種源碼、面試題、微服務技術棧,幫忙關注一波,非常感謝
參考文章;
Spring Cloud @HystrixCommand和@CacheResult註解使用,參數配置
https://github.com/Netflix/Hystrix/wiki/Configuration#coreSize