SpringCloud(6)---熔斷降級理解、Hystrix實戰
SpringCloud(6)---熔斷降級理解、Hystrix實戰
一、概念
1、為什麽需要熔斷降級
(1)需求背景
它是系統負載過高,突發流量或者網絡等各種異常情況介紹,常用的解決方案。
在一個分布式系統裏,一個服務依賴多個服務,可能存在某個服務調用失敗,比如超時、異常等,如何能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗。
比如:某微服務業務邏輯復雜,在高負載情況下出現超時情況。
內部條件:程序bug導致死循環、存在慢查詢、程序邏輯不對導致耗盡內存
外部條件:黑客攻擊、促銷、第三方系統響應緩慢。
(2)解決思路
解決接口級故障的核心思想是優先保障核心業務和優先保障絕大部分用戶。比如登錄功能很重要,當訪問量過高時,停掉註冊功能,為登錄騰出資源。
(3)解決策略
熔斷,降級,限流,排隊。
2、什麽是熔斷
一般是某個服務故障或者是異常引起的,類似現實世界中的‘保險絲’,當某個異常條件被觸發,直接熔斷整個服務,而不是一直等到此服務超時,為了防止防止整個系統的故障,
而采用了一些保護措施。過載保護。比如A服務的X功能依賴B服務的某個接口,當B服務接口響應很慢時,A服務X功能的響應也會被拖慢,進一步導致了A服務的線程都卡在了X功能
上,A服務的其它功能也會卡主或拖慢。此時就需要熔斷機制,即A服務不在請求B這個接口,而可以直接進行降級處理。
3、什麽是降級
服務器當壓力劇增的時候,根據當前業務情況及流量,對一些服務和頁面進行有策略的降級
大部分客戶的得到正確的相應。
自動降級:超時、失敗次數、故障、限流
(1)配置好超時時間(異步機制探測回復情況);
(2)不穩的的api調用次數達到一定數量進行降級(異步機制探測回復情況);
(3)調用的遠程服務出現故障(dns、http服務錯誤狀態碼、網絡故障、Rpc服務異常),直接進行降級。
人工降級:秒殺、雙十一大促降級非重要的服務。
4、熔斷和降級異同
相同點:
1)從可用性和可靠性觸發,為了防止系統崩潰
2)最終讓用戶體驗到的是某些功能暫時不能用
不同點:
1)服務熔斷一般是下遊服務故障導致的,而服務降級一般是從整體系統負荷考慮,由調用方控制
2)觸發原因不同,上面顏色字體已解釋
5、熔斷到降級的流程講解
Hystrix提供了如下的幾個關鍵參數,來對一個熔斷器進行配置:
circuitBreaker.requestVolumeThreshold //滑動窗口的大小,默認為20 circuitBreaker.sleepWindowInMilliseconds //過多長時間,熔斷器再次檢測是否開啟,默認為5000,即5s鐘 circuitBreaker.errorThresholdPercentage //錯誤率,默認50%
3個參數放在一起,所表達的意思就是:
每當20個請求中,有50%失敗時,熔斷器就會打開,此時再調用此服務,將會直接返回失敗,不再調遠程服務。直到5s鐘之後,重新檢測該觸發條件,判斷是否把熔斷器關閉,或者繼續打開。
這裏面有個很關鍵點,達到熔斷之後,那麽後面它就直接不去調該微服務。那麽既然不去調該微服務或者調的時候出現異常,出現這種情況首先不可能直接把錯誤信息傳給用戶,所以針對熔斷
我們可以考慮采取降級策略。所謂降級,就是當某個服務熔斷之後,服務器將不再被調用,此時客戶端可以自己準備一個本地的fallback回調,返回一個缺省值。
這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強,當然這也要看適合的業務場景。
二、Hystrix實戰
通過訂單服務去掉商品微服務,註冊中心和商品微服務這裏就不寫了,具體可以看上篇博客:SpringCloud(5)---Feign服務調用
1、pom.xml
<!--hystrix依賴,主要是用 @HystrixCommand --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
2、application.yml
server: port: 9001 #指定註冊中心地址 eureka: client: serviceUrl: defaultZone: http://localhost:7001/eureka/ #服務的名稱 spring: application: name: order-service #開啟feign支持hystrix (註意,一定要開啟,舊版本默認支持,新版本默認關閉) # #修改調用超時時間(默認是1秒就算超時) feign: hystrix: enabled: true client: config: default: connectTimeout: 2000 readTimeout: 2000
3、SpringBoot啟動類
@SpringBootApplication @EnableFeignClients //添加熔斷降級註解 @EnableCircuitBreaker public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
4、ProductClient
/** * 商品服務客戶端 * name = "product-service"是你調用服務端名稱 * fallback = ProductClientFallback.class,後面是你自定義的降級處理類,降級類一定要實現ProductClient */ @FeignClient(name = "product-service",fallback = ProductClientFallback.class) public interface ProductClient { //這樣組合就相當於http://product-service/api/v1/product/find @GetMapping("/api/v1/product/find") String findById(@RequestParam(value = "id") int id); }
5、ProductClientFallback降級處理類
/** * 針對商品服務,錯降級處理 */ @Component public class ProductClientFallback implements ProductClient { @Override public String findById(int id) { System.out.println("ProductClientFallback中的降級方法"); //這對gai該接口進行一些邏輯降級處理........ return null; } }
6、OrderController類
@RestController @RequestMapping("api/v1/order") public class OrderController { @Autowired private ProductOrderService productOrderService; @RequestMapping("save") //當調用微服務出現異常會降級到saveOrderFail方法中 @HystrixCommand(fallbackMethod = "saveOrderFail") public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){ return productOrderService.save(userId, productId); } //註意,方法簽名一定要要和api方法一致 private Object saveOrderFail(int userId, int productId){ System.out.println("controller中的降級方法"); Map<String, Object> msg = new HashMap<>(); msg.put("code", -1); msg.put("msg", "搶購人數太多,您被擠出來了,稍等重試"); return msg; } }
7、測試
(1)正常情況
先將訂單服務(order)和商品服務(product)同時啟動,如圖:
訂單服務調用商品服務正常
(2)異常情況
此刻我將商品微服務停掉:只啟動訂單微服務,這時去調用商品服務當然會出現超時異常情況。
在調接口,發現已經成功到降級方法裏
在看controller中的降級方法和ProductClientFallback降級方法的實現先後順序,出乎我自己的預料,controller中降級方法會在ProductClientFallback降級方法之前執行。
官方文檔:https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.strategy
我只是偶爾安靜下來,對過去的種種思忖一番。那些曾經的舊時光裏即便有過天真愚鈍,也不值得譴責。畢竟,往後的日子,還很長。不斷鼓勵自己,
天一亮,又是嶄新的起點,又是未知的征程(上校8)
SpringCloud(6)---熔斷降級理解、Hystrix實戰