SpringCloud hystrix服務降級概念介紹
Hystrix
初識Hystrix
Hystrix是什么?
Java應用程序講求“高內(nèi)聚低耦合”,而spring cloud是一種微服務架構理念,將原來的一個應用程序拆分成許多微服務來調(diào)用,這樣的話就可以滿足“低耦合”的要求,但是隨之而來的就是“服務雪崩”問題。
所謂的服務雪崩就是指,由于服務提供者不可用導致服務調(diào)用者不可用,并且在生產(chǎn)過程中,這種不可用逐漸擴大的現(xiàn)象。想要解決“服務雪崩”問題就需要用到Hystrix(豪豬)
Hystrix是一個用于處理分布式系統(tǒng)的延遲和容錯的開源庫,在分布式系統(tǒng)里,許多依賴不可避免的會調(diào)用失敗,比如超時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯(lián)故障,以提高分布式系統(tǒng)的彈性。
"斷路器”本身是一種開關裝置,當某個服務單元發(fā)生故障之后,通過斷路器的故障監(jiān)控(類似熔斷保險絲),向調(diào)用方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調(diào)用方無法處理的異常,這樣就保證了服務調(diào)用方的線程不會被長時間、不必要地占用,從而避免了故障在分布式系統(tǒng)中的蔓延,乃至雪崩。
Hystrix三大概念
服務降級(fallback)
fallback是什么
所謂的服務降級就是當服務出現(xiàn)程序運行異常、超時、服務熔斷觸發(fā)服務降級、線程池/信號量打滿等情況,此時應該返回一個符合預期的、可處理的備選響應(fallback),以提高用戶的使用體驗而不是長時間的等待請求或者返回一個超時異常頁面。總而言之,當出現(xiàn)以上問題時,要有一個兜底方案來提高用戶的使用體驗
服務降級的解決方案可以分為服務提供方和服務調(diào)用方,兩面都可以實現(xiàn)服務降級
服務提供方實現(xiàn)服務降級
第一步: 對服務提供方的service接口方法進行加強,主要就是針對可能出現(xiàn)超時等異常情況的接口,新建方法對其進行兜底,如果原接口出現(xiàn)問題則使用兜底方案進行反饋
使用@HystrixCommand注解的fallbackMethod屬性指定兜底方法名,使用commandProperties屬性的@HystrixProperty注解指定異常類型(超時異常和超時時間)
/** * 超時訪問,設置自身調(diào)用超時的峰值,峰值內(nèi)正常運行,超過了峰值需要服務降級 自動調(diào)用fallbackMethod 指定的方法 * 超時異?;蛘哌\行異常 都會進行服務降級 * @param id * @return */ @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public String paymentInfoTimeOut(Integer id) { int second = 5; try { TimeUnit.SECONDS.sleep(second); } catch (InterruptedException e) { e.printStackTrace(); } return "線程池: " + Thread.currentThread().getName() + " paymentInfoTimeOut,id: " + id + "\t" + "O(∩_∩)O哈哈~" + " 耗時(秒): " + second; } public String paymentInfo_TimeOutHandler(Integer id) { return "超時異常兜底方案!線程池: " + Thread.currentThread().getName() + " paymentInfo_TimeOutHandler,id: " + id + "\t"; }
第二步: 服務提供方的主啟動類上使用@EnableCircuitBreaker注解開啟“熔斷器”,這樣的話前面的配置才能生效
@SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class HystrixPaymentMain8001 { public static void main(String[] args) { SpringApplication.run(HystrixPaymentMain8001.class, args); } }
除了上述可以自定義超時時間的異常,出現(xiàn)其他運行時異常也會調(diào)用兜底方案返回
服務調(diào)用方實現(xiàn)服務降級
第一步: 使用配置文件開啟hystrix
feign:
hystrix:
enabled: true
第二步: 服務調(diào)用方的controller加強,新建方法對其進行兜底,使用方式與服務提供方一樣,主要就是服務調(diào)用方和服務提供方兩套方案,可以實現(xiàn)兩邊定制化。
@GetMapping("/payment/hystrix/timeout/{id}") @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500") }) public String paymentInfoTimeOut(@PathVariable("id") Integer id) { String result = paymentHystrixService.paymentInfoTimeOut(id); return result; } public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) { return "服務調(diào)用方兜底方案!我是消費者80,對方支付系統(tǒng)繁忙請10秒鐘后再試或者自己運行出錯請檢查自己,o(╥﹏╥)o"; }
第三步: 服務調(diào)用方的主程序類上使用@EnableHystrix注解開啟hystrix
服務降級優(yōu)化
- 解決冗余問題
前面的每一個方法都對應一個兜底方案,這樣的話會顯得代碼十分臃腫,實際上很多的接口都可以使用一個兜底方案,于是我們就可以配置默認的兜底方案,在沒有使用@HystrixCommand注解指定的時候,類中的所有接口都會走默認兜底方案
@DefaultProperties注解的defaultFallback屬性指定默認兜底方法,如果類中存在@HystrixCommand注解中不使用屬性指定特定兜底方案的情況,就說明這個接口使用是默認兜底方案
@RestController @RequestMapping("consumer") @Slf4j @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod") public class OrderHystrixController { @Resource private PaymentHystrixService paymentHystrixService; @HystrixCommand @GetMapping("/payment/hystrix/ex/{id}") public String paymentInfoException(@PathVariable("id") Integer id) { int age = 10/0; String result = paymentHystrixService.paymentInfoException(id); return result; } /** * hystrix 全局fallback方法 * @return */ public String payment_Global_FallbackMethod() { return "Global異常處理信息,請稍后再試,/(ㄒoㄒ)/~~"; } }
- 解決耦合問題
上述操作中,原方案和兜底方案都在controller中定義,想要解決這個耦合問題可以使用一個類實現(xiàn)service接口,然后重寫所有的接口方法,然后使用service接口上@FeignClient注解的fallback屬性指定接口的實現(xiàn)類為兜底類
@Component @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class) public interface PaymentHystrixService { @GetMapping("/payment/hystrix/ok/{id}") String paymentInfoOK(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/timeout/{id}") String paymentInfoTimeOut(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/ex/{id}") String paymentInfoException(Integer id); }
@Component public class PaymentFallbackService implements PaymentHystrixService { @Override public String paymentInfoOK(Integer id) { return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o"; } @Override public String paymentInfoTimeOut(Integer id) { return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o"; } @Override public String paymentInfoException(Integer id) { return "-----PaymentFallbackService fall back-paymentInfoException ,o(╥﹏╥)o"; } }
服務熔斷(break)
break是什么
微服務鏈路中某個微服務的請求達到最大訪問之后,直接拒絕訪問,然后調(diào)用服務降級的方法返回友好的提示;當檢測到該節(jié)點微服務調(diào)用響應正常之后,還可以恢復鏈路的正常調(diào)用。hystrix會默認在服務5秒內(nèi)調(diào)用失敗20次后觸發(fā)熔斷機制,但是也可以使用配置對其進行修改。
服務提供方實現(xiàn)服務熔斷
首先service層使用注解配置服務熔斷的相關值和熔斷時的備選方案,就以下代碼為例:在10S的時間窗口期中,10次請求中失敗率達到60%就會觸發(fā)熔斷啟動備選方案。
如果在10S的時間窗口期中,請求次數(shù)不足10次,那么根本就不可能觸發(fā)熔斷器。當熔斷器開啟后所有的請求都不會被轉發(fā),一段時間窗口期之后(默認5秒,可以自定義配置)斷路器切換為半開狀態(tài),此時會讓其中一個請求進行轉發(fā),成功則關閉斷路器,反之繼續(xù)開啟
@HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback", commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),/* 是否開啟斷路器*/ @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 請求次數(shù) @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 時間窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),// 失敗率達到多少后跳閘 }) public String paymentCircuitBreaker(Integer id) { if (id < 0) { throw new RuntimeException("******id 不能負數(shù)"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName() + "\t" + "調(diào)用成功,流水號: " + serialNumber; } public String paymentCircuitBreakerFallback(Integer id) { return Thread.currentThread().getName() + "\t" + "id 不能負數(shù)或超時或自身錯誤,請稍后再試,/(ㄒoㄒ)/~~ id: " + id; }
controller中調(diào)用service方法
@GetMapping("/circuit/{id}") public String paymentCircuitBreaker(@PathVariable("id") Integer id) { String result = paymentService.paymentCircuitBreaker(id); log.info("****result: " + result); return result; }
服務限流(flowlimit)
flowlimit是什么
在秒殺等高并發(fā)的操作下,為了防止大量請求一塊發(fā)送過來,采用排隊的方式,把請求按照順序排隊發(fā)送過來。由于hystrix已經(jīng)停止更新,而且Alibaba的sentinel在進行服務限流的處理時比hystrix更加優(yōu)秀,所以說這一部分知識可以放在后面進行學習。
Hystrix圖形化監(jiān)控
第一步: 新建一個模塊用于監(jiān)控,導入相關依賴
<dependencies> <!--最主要的依賴,用于引入圖形化dashboard--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <!-- 引入自己定義的api通用包 --> <dependency> <groupId>com.xiaochen</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
第一步: 配置文件配置端口號
server:
port: 9001
第三步: 主啟動類開啟HystrixDashboard,
@SpringBootApplication @EnableHystrixDashboard public class HystrixDashboardMain9001 { public static void main(String[] args) { SpringApplication.run(HystrixDashboardMain9001.class, args); } }
此外,所有的服務提供方也就是被監(jiān)控的服務都要引入spring-boot-starter-actuator依賴,表示自己可以受監(jiān)控。然后就是在服務的主啟動類上要使用以下代碼中的addUrlMappings配置受監(jiān)控的路徑
/** * 注意:新版本Hystrix需要在主啟動類中指定監(jiān)控路徑 * 此配置是為了服務監(jiān)控而配置,與服務容錯本身無關,spring cloud升級后的坑 * ServletRegistrationBean因為springboot的默認路徑不是"/hystrix.stream", * 只要在自己的項目里配置上下面的servlet就可以了 * * @return ServletRegistrationBean */ @Bean public ServletRegistrationBean getServlet() { HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); // 一啟動就加載 registrationBean.setLoadOnStartup(1); // 添加url registrationBean.addUrlMappings("/hystrix.stream"); // 設置名稱 registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; }
啟動監(jiān)控模塊、eureka模塊、受監(jiān)控模塊之后,訪問以下路徑可以通過路徑監(jiān)控指定的服務,設置后點擊下面的Monitor Stream按鈕即可進入圖形化監(jiān)控界面
圖形化界面各處代表的含義如下:
到此這篇關于SpringCloud hystrix服務降級概念介紹的文章就介紹到這了,更多相關SpringCloud hystrix內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java servlet結合Oracle搭建java的web開發(fā)環(huán)境
今天我將與大家分享一下我學JAVA WEB寫的一些小實例 ,我個人是不太喜歡書本上的晦澀的概念的,所以我花了更多的時間在一些應用實例上,我覺得這樣的學習方式很適合我,由簡到繁,由淺入深2015-12-12Mybatis-Plus動態(tài)表名的實現(xiàn)示例
面對復雜多變的業(yè)務需求,動態(tài)表名的處理變得愈發(fā)重要,本文主要介紹了Mybatis-Plus動態(tài)表名的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下2024-07-07spring,mybatis事務管理配置與@Transactional注解使用詳解
這篇文章主要介紹了spring,mybatis事務管理配置與@Transactional注解使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Java(SpringBoot)項目打包(構建)成Docker鏡像的幾種常見方式
在對Spring Boot應用程序進行Docker化時,為應用程序選擇正確的基礎鏡像非常重要,下面這篇文章主要給大家介紹了關于Java(SpringBoot)項目打包(構建)成Docker鏡像的幾種常見方式,需要的朋友可以參考下2023-12-12Java(TM) Platform SE binary 打開jar文件的操作
這篇文章主要介紹了Java(TM) Platform SE binary 打開jar文件的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02