SpringCloud?hystrix斷路器與局部降級全面介紹
服務(wù)降級
服務(wù)壓力劇增的時候,根據(jù)當(dāng)前的業(yè)務(wù)情況及流量對一些服務(wù)和頁面有策略的降級,以此緩解服務(wù)器的壓力,以保證核心任務(wù)的進行。同時保證部分甚至大分客戶能得到正確的響應(yīng)。也就是當(dāng)前的請求處理不了或者出錯了,給一個默認的返回。例如:雙11降級產(chǎn)品評價等非核心功能,保證支持和訂單的核心任務(wù)進行。
服務(wù)熔斷
就是防止服務(wù)雪崩現(xiàn)象出現(xiàn),是服務(wù)降級的一種特殊情況。
一、Hystrix的服務(wù)使用前的問題
1、ProductController 中方法異常和超時
在商品服務(wù) ProductController 中的方法中增加異常和超時,ProductController 中方法修改如下:
package com.hwadee.springcloud.controller; import com.hwadee.springcloud.entity.Product; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; @RestController @RequestMapping("/product") public class ProductController { //方便后面講負載均衡,查看ip,此處獲取配置中的端口號和ip @Value("${server.port}") private String port; @Value("${spring.cloud.client.ip-address}") private String ip; @RequestMapping("/buy/{id}") public Product findById(@PathVariable Long id) { Product product = new Product(); product.setId(id); // 后面需要測試負載均衡,所以返回 ip 地址及端口號 product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port+" "+"查詢商品訂單,訂單號:"+id); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); //測試超時熔斷 try { Thread.sleep(5000); //測試并發(fā)熔斷 //Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } return product; } @RequestMapping(value = "/delete/{id}") public Product deleteOrderById(@PathVariable Long id){ Product product = new Product(); product.setId(id); // 后面需要測試負載均衡,所以返回 ip 地址及端口號 product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port+" "+"從購物車刪除訂單,訂單號:"+id); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); //測試異常熔斷 System.out.println(10/0); return product; } }
2、訪問查看效果
訪問http://localhost:9000/order/buy/1
訪問http://localhost:9000/order/delete/1
訂單服務(wù)中OrderController 中 調(diào)用商品服務(wù) ProductController 中方法時,ProductController 中方法出現(xiàn)異常和超時,訪問瀏覽器的異常結(jié)果和訂單服務(wù)中的內(nèi)部異常如下:
?
?
?
?
3、問題分析
在微服務(wù)架構(gòu)中,我們將系統(tǒng)拆分成了一個個的服務(wù)單元,各單元應(yīng)用間通過服務(wù)注冊與訂閱的方式互相依賴。由于每個單元都在不同的進程中運行,依賴通過遠程調(diào)用的方式執(zhí)行,這樣就有可能因為網(wǎng)絡(luò)原因或是依賴服務(wù)自身問題出現(xiàn)調(diào)用故障或延遲,而這些問題會直接導(dǎo)致調(diào)用方的對外服務(wù)也出現(xiàn)延遲,若此時調(diào)用方的請求不斷增加,最后就會出現(xiàn)因等待出現(xiàn)故障的依賴方響應(yīng)而形成任務(wù)積壓,線程資源無法釋放,最終導(dǎo)致自身服務(wù)的癱瘓,進一步甚至出現(xiàn)故障的蔓延最終導(dǎo)致整個系統(tǒng)的癱瘓。如果這樣的架構(gòu)存在如此嚴重的隱患,那么相較傳統(tǒng)架構(gòu)就更加的不穩(wěn)定,如下圖。
?
二、 商品服務(wù) Hystrix的 局部降級
1、降級配置
注解 @HistrixCommand
在商品服務(wù) ProductController 中的 findById( )和deleteOrderById( ) 方法上增加降級配置的注解 @HistrixCommand
—旦調(diào)用服務(wù)方法失敗并拋出了超時或錯誤信息后,會自動調(diào)用@HystrixCommand標注好的fallbackMethod調(diào)用類中的指定方法。
在@HistrixCommand 指定超時或異常要回調(diào)的方法,同時可以指定配置參數(shù),例如使用@HistrixCommand 中的屬性commandProperties 指定默認超時時間,如:
fallbackMethod:指定回調(diào)方法是findByIdTimeout
commandProperties: 指定@HystrixProperty??? ?的默認值是默認超時時間是3s@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
2、回調(diào)(兜底降級)方法
在商品服務(wù)ProductController 中增加回調(diào)方法findByIdTimeout( ) 和deleteOrderByIdException( ),當(dāng)訪問ProductController 中的 findById( )和deleteOrderById( ) 發(fā)生超時 或 異常時,會調(diào)用回調(diào)方法。
3、具體代碼
降級配置 和回調(diào)(兜底降級)方法的具體代碼如下:
import com.hwadee.springcloud.entity.Product; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; @RestController @RequestMapping("/product") public class ProductController { //方便后面講負載均衡,查看ip,此處獲取配置中的端口號和ip @Value("${server.port}") private String port; @Value("${spring.cloud.client.ip-address}") private String ip; @RequestMapping("/buy/{id}") @HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public Product findById(@PathVariable Long id) { Product product = new Product(); product.setId(id); // 后面需要測試負載均衡,所以返回 ip 地址及端口號 product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "查詢商品訂單,訂單號:" + id); product.setPrice(new BigDecimal(50000.0)); System.out.println(product); //測試超時熔斷 try { Thread.sleep(5000); //測試并發(fā)熔斷 //Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } return product; } @RequestMapping(value = "/delete/{id}") @HystrixCommand(fallbackMethod = "deleteOrderByIdException") public Product deleteOrderById(@PathVariable Long id) { Product product = new Product(); product.setId(id); // 后面需要測試負載均衡,所以返回 ip 地址及端口號 product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "從購物車刪除訂單,訂單號:" + id); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); //測試異常熔斷 System.out.println(10 / 0); return product; } public Product findByIdTimeout(Long id) { Product product = new Product(); product.setId(id); product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "訪問 超時 進行降級服務(wù)"); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); return product; } public Product deleteOrderByIdException(Long id) { Product product = new Product(); product.setId(id); product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "訪問 異常 進行降級服務(wù)"); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); return product; } }
4、主啟動類激活Hstrix
在商品服務(wù)的主啟動類 ProductServerApplication 中使用注解@EnableCircuitBreaker 進行激活Hystrix,代碼如下
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient// 啟動 eureka 客戶端 @EnableCircuitBreaker // 主啟動類激活 Hystrix public class ProductServerApplication { public static void main(String[] args) { SpringApplication.run(ProductServerApplication.class, args); } }
5、進行測試
將商品服務(wù)中ProductController 和 ProductServerApplication復(fù)制到 其他所有 商品服務(wù)中,進行更新代碼。
分別訪問:http://localhost:9001/product/buy/1 和 http://localhost:9001/product/delete/1 查看超時和異常服務(wù)降級。看瀏覽器和內(nèi)部結(jié)果。
?
?
三、 訂單服務(wù) Hystrix的 局部降級
1、降級配置
注解 @HistrixCommand
在訂單服務(wù) OrderController 中的方法上增加降級配置的注解 @HistrixCommand
2、回調(diào)(兜底降級)方法
在訂單服務(wù) OrderController 定義 回調(diào)方法 buyTimeout( Long id) 、deleteOrderException( Long id),并設(shè)置超時服務(wù),超時服務(wù)要比將商品服務(wù)ProductController 中的 findById( ) 超時時間短。例如:ProductController 中的 findById( ) 超時時間是 3s ,則訂單服務(wù) OrderController 定義 回調(diào)方法 buyTimeout( ) 設(shè)定的超時時間應(yīng)是 <3s 。
3、具體代碼
降級配置 和回調(diào)(兜底降級)方法的具體代碼如下:
import com.hwadee.springcloud.entity.Product; import com.hwadee.springcloud.service.IOrderFeignService; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/order") public class OrderController { @Autowired IOrderFeignService orderFeignService; @RequestMapping("/buy/{id}") @HystrixCommand(fallbackMethod = "buyTimeout", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500") }) public Product buy(@PathVariable Long id) { System.out.println("進入OrderController的buy方法, orderFeignService 準備調(diào)用遠端接口 findById"); Product product = orderFeignService.findOrderById(id); return product; } @RequestMapping(value = "/delete/{id}") @HystrixCommand(fallbackMethod = "deleteOrderException") public Product deleteOrderById(@PathVariable Long id) { System.out.println("進入OrderController的deleteOrderById方法, orderFeignService 準備調(diào)用遠端接口deleteOrderById"); Product product = orderFeignService.deleteOrderById(id); int i =10/0; return product; } public Product buyTimeout( Long id) { Product product = new Product(); product.setId(id); product.setName("當(dāng)前訂單服務(wù)訪問/order/buy/1 超時:"+id); return product; } public Product deleteOrderException( Long id) { Product product = orderFeignService.deleteOrderById(id); product.setName("當(dāng)前訂單服務(wù)訪問/order/delete/1 10/0異常:"+id); return product; } }
4、將商品服務(wù)中的超時時間為正常
將商品服務(wù)ProductController 中的 findById( ) 超時時間為正常,即程序超時時間是2s,熔斷等待時間是3s,并且要比 訂單服務(wù) OrderController 定義 回調(diào)方法 buyTimeout( ) 中的熔斷時間大,代碼如下:
@HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = {
// 正常超時時間是 3s 比OrderController 中定義的超時時間長。
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public Product findById(@PathVariable Long id) { 。。。。。
// 超時時間 2s
Thread.sleep(2000); 。。。。。
return product;
}
完整代碼如下:
import com.hwadee.springcloud.entity.Product; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; @RestController @RequestMapping("/product") public class ProductController { //方便后面講負載均衡,查看ip,此處獲取配置中的端口號和ip @Value("${server.port}") private String port; @Value("${spring.cloud.client.ip-address}") private String ip; @RequestMapping("/buy/{id}") @HystrixCommand(fallbackMethod = "findByIdTimeout", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public Product findById(@PathVariable Long id) { Product product = new Product(); product.setId(id); // 后面需要測試負載均衡,所以返回 ip 地址及端口號 product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "查詢商品訂單,訂單號:" + id); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); //測試超時熔斷 try { Thread.sleep(5000); //測試并發(fā)熔斷 //Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } return product; } @RequestMapping(value = "/delete/{id}") @HystrixCommand(fallbackMethod = "deleteOrderByIdException") public Product deleteOrderById(@PathVariable Long id) { Product product = new Product(); product.setId(id); // 后面需要測試負載均衡,所以返回 ip 地址及端口號 product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "從購物車刪除訂單,訂單號:" + id); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); //測試異常熔斷 System.out.println(10 / 0); return product; } public Product findByIdTimeout(Long id) { Product product = new Product(); product.setId(id); product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "訪問 超時 進行降級服務(wù)"); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); return product; } public Product deleteOrderByIdException(Long id) { Product product = new Product(); product.setId(id); product.setName("當(dāng)前訪問商品服務(wù)地址:" + ip + ":" + port + " " + "訪問 異常 進行降級服務(wù)"); product.setPrice(new BigDecimal(10000.0)); System.out.println(product); return product; } }
5、主啟動類激活Hstrix
在訂單服務(wù)的主啟動類 OrderServerApplication 中使用注解@EnableCircuitBreaker 或 注解@EnableHystrix進行激活Hystrix,注意:@EnableHystrix包括了注解@EnableCircuitBreaker ,代碼如下
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient// 啟動 eureka 客戶端 @EnableFeignClients // 啟動 feign @EnableCircuitBreaker // 或 @EnableHystrix 啟動 Hystrix public class OrderServerApplication { public static void main(String[] args) { SpringApplication.run(OrderServerApplication.class, args); } }
6、進行測試
分別訪問:http://localhost:9000/order/buy/1 和 http://localhost:9000/order/delete/1 查看超時和異常服務(wù)降級。
?
?
到此這篇關(guān)于SpringCloud hystrix斷路器與服務(wù)降級全面介紹的文章就介紹到這了,更多相關(guān)SpringCloud hystrix斷路器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot Redis實現(xiàn)接口冪等性校驗方法詳細講解
這篇文章主要介紹了SpringBoot Redis實現(xiàn)接口冪等性校驗方法,近期一個老項目出現(xiàn)了接口冪等性校驗問題,前端加了按鈕置灰,依然被人拉著接口參數(shù)一頓輸出,還是重復(fù)調(diào)用了接口,通過復(fù)制粘貼,完成了后端接口冪等性調(diào)用校驗2022-11-11spring aop實現(xiàn)用戶權(quán)限管理的示例
本篇文章主要介紹了spring aop實現(xiàn)用戶權(quán)限管理的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12SpringBoot?自定義starter?yaml提示失效問題及解決方法
在自定義starter后,必不可少會有properties配置參數(shù)需要指定,而在有時又不知道為什么出現(xiàn)這個問題,這篇文章主要介紹了SpringBoot?自定義starter?yaml提示失效問題,需要的朋友可以參考下2022-12-12Spring源碼如何修改Bean的屬性用到的相關(guān)類
這篇文章主要介紹了Spring源碼如何修改Bean的屬性用到的相關(guān)類,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05