原文地址:Spring Cloud 入門 之 Hystrix 篇(四)
博客地址:http://www.extlight.comhtml
在微服務應用中,服務存在必定的依賴關係,若是某個目標服務調用慢或者有大量超時形成服務不可用,間接致使其餘的依賴服務不可用,最嚴重的可能會阻塞整條依賴鏈,最終致使業務系統崩潰(又稱雪崩效應)。java
上述的問題將是本篇須要解決的問題。git
斷路器是一種開關設置,當某個服務單元發生故障以後,經過斷路器的故障監控,向調用方返回一個符合預期的服務降級處理(fallback),而不是長時間的等待或者拋出調用方沒法處理的異常,這樣保證了服務調用方的線程不會長時間被佔用,從而避免了故障在分佈式系統的蔓延乃至崩潰。github
fallback 至關因而降級操做。對於查詢操做, 咱們能夠實現一個 fallback 方法, 當請求後端服務出現異常的時候, 可使用 fallback 方法返回的值。 fallback 方法的返回值通常是設置的默認值或者來自緩存,告知後面的請求服務不可用了,不要再請求了。web
相同:spring
目標一致:爲了防止系統崩潰而實施的一種防護手段 表現形式一致:當請求目標在必定時間內無響應時,返回或執行默認響應內容
不一樣:後端
觸發條件不一樣:下游服務出現故障觸發請求熔斷。系統負荷超過閾值觸發服務降級。 管理目標層次不一樣:請求熔斷針對全部微服務。服務降級針對整個系統中的外圍服務。
Spring Cloud Hystrix 實現了斷路器、線程隔離等一系列服務保護功能。它是基於 Netflix 的開源框架 Hystrix 實現的,該框架的目的在於經過控制訪問遠程系統、服務和第三方庫節點,從而對延遲和故障提供更強大的容錯能力。api
Hystrix 具有服務熔斷、服務降級、線程和信號隔離、請求緩存、請求合併以及服務監控的能力。瀏覽器
本次測試案例基於以前發表的文章中介紹的案例進行演示,不清楚的讀者請先轉移至 《Spring Cloud 入門 之 Feign 篇(三)》 進行瀏覽。緩存
如今的項目列表以下:
服務實例 | 端口 | 描述 |
---|---|---|
common-api | - | 公用的 api,如:實體類 |
eureka-server | 9000 | 註冊中心(Eureka 服務端) |
goods-server | 8081 | 商品服務(Eureka 客戶端) |
goods-server-02 | 8082 | 商品服務(Eureka 客戶端) |
goods-server-03 | 8083 | 商品服務(Eureka 客戶端) |
order-server | 8100 | 訂單服務(Eureka 客戶端) |
在 order-server 項目中:
<!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
咱們來修改獲取下訂單的方法,在 placeOrder 方法上加 @HystrixCommand 註解:
@Service public class OrderServiceImpl implements OrderService{ @Autowired private RestTemplate restTemplate; // @Autowired // private GoodsServiceClient goodsServiceClient; @HystrixCommand(fallbackMethod = "defaultByPlaceOrder") @Override public void placeOrder(Order order) throws Exception{ Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class); // Result result = this.goodsServiceClient.goodsInfo(order.getGoodsId()); if (result != null && result.getCode() == 200) { System.out.println("=====下訂單===="); System.out.println(result.getData()); } else { System.out.println(result.getMsg()); } } public void defaultByPlaceOrder(Order order) { System.out.println("商品服務系統異常"); } }
當調用商品服務超時或出現異常時,Hystrix 會調用 @HystrixCommand 中指定的 fallbackMethod 方法獲取返回值或執行異常處理。
注意:fallbackMethod 方法要求與正常方法有相同的入參和回參。
在啓動類上添加 @EnableCircuitBreaker 註解:
@EnableCircuitBreaker @EnableEurekaClient @SpringBootApplication public class OrderServerApplication { public static void main(String[] args) { SpringApplication.run(OrderServerApplication.class, args); } }
啓動好全部項目,使用 Postman 請求 order-server 進行下單操做,運行結果以下:
當咱們請求發送的 goodsId 的商品不存在,服務提供方拋會異常,調用方沒法處理,所以只能展現圖中的異常信息。
從圖中可知,雖然請求了一個 goodsId 不存在的商品,可是調用方(order-server)開啓了熔斷機制,執行默認方法,從而使接口能正常通訊而不是拋出調用方不可處理的異常致使整個系統不能正常運行。
看到這裏,或許會有讀者產生一個疑問,若是類中定義 N 個方法,是否是意味着同時也要定義 N 個異常處理的方法呢,答案是否認的。
Hystrix 還提供了 @DefaultProperties 統一處理請求熔斷,在該註解上設置 defaultFallback 屬性值,即熔斷開啓後要執行的方法。
@Service @DefaultProperties(defaultFallback = "defaultByHystrix") public class OrderServiceImpl implements OrderService{ // @Autowired // private RestTemplate restTemplate; @Autowired private GoodsServiceClient goodsServiceClient; @HystrixCommand @Override public void placeOrder(Order order) throws Exception{ // Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class); Result result = this.goodsServiceClient.goodsInfo(order.getGoodsId()); if (result != null && result.getCode() == 200) { System.out.println("=====下訂單===="); System.out.println(result.getData()); } else { System.out.println(result.getMsg()); } } public void defaultByHystrix() { System.out.println("商品服務系統異常"); } }
注意:defaultFallback 定義的方法必須是無參的。
在 common-api 項目中:
@Component public class GoodsServiceClientFallbackFactory implements FallbackFactory<GoodsServiceClient> { @Override public GoodsServiceClient create(Throwable cause) { return new GoodsServiceClient() { @Override public Result goodsInfo(String goodsId) { return Result.fail(500, "商品服務系統出現異常,請聯繫管理員"); } }; } }
使用單獨的類處理異常邏輯,當與服務端沒法正常通訊時調用此類中的方法返回結果。
將上邊定義好的 FallbackFactory 設置到 @FeignClient 註解上:
@FeignClient(value="GOODS", fallbackFactory = GoodsServiceClientFallbackFactory.class) public interface GoodsServiceClient { @RequestMapping("/goods/goodsInfo/{goodsId}") public Result goodsInfo(@PathVariable("goodsId") String goodsId); }
在 order-server 項目中:
server: port: 8100 spring: application: name: ORDER eureka: instance: instance-id: order-api-8100 prefer-ip-address: true # 訪問路徑能夠顯示 IP client: service-url: defaultZone: http://localhost:9000/eureka/ # 註冊中心訪問地址 feign: hystrix: enabled: true
@Service //@DefaultProperties(defaultFallback = "defaultByHystrix") public class OrderServiceImpl implements OrderService{ // @Autowired // private RestTemplate restTemplate; @Autowired private GoodsServiceClient goodsServiceClient; // @HystrixCommand @Override public void placeOrder(Order order) throws Exception{ // Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class); Result result = this.goodsServiceClient.goodsInfo(order.getGoodsId()); if (result != null && result.getCode() == 200) { System.out.println("=====下訂單===="); System.out.println(result.getData()); } else { System.out.println(result.getMsg()); } } // public void defaultByHystrix() { // System.out.println("商品服務系統異常"); // } }
在啓動類上加 FallbackFactory 類的包掃描目錄:
@ComponentScan(basePackages = {"com.extlight.springcloud"}) // 爲了能掃描 common-api 項目中的 GoodsServiceClientFallbackFactory @EnableFeignClients(basePackages = {"com.extlight.springcloud"}) @EnableEurekaClient @SpringBootApplication public class OrderServerApplication { public static void main(String[] args) { SpringApplication.run(OrderServerApplication.class, args); } }
打開 Postman 請求下單接口,結果以下圖:
咱們手動關閉 2 個商品服務,保留一個商品服務並屢次請求商品服務接口,從而出模擬商品服務超過預約荷載情景,最終看到圖中服務降級功能。當有請求再次訪問商品服務時默認返回 GoodsServiceClientFallbackFactory 中定義的內容。
除了服務熔斷、降級的功能外,Hystrix 還提供了準及時的調用監控。 Hystrix 會持續地記錄全部經過 Hystrix 發起的請求的執行信息,並以統計報表和圖形方式展現給用戶。
order-server 項目中:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
修改 application.yml,開放端口:
management: endpoints: web: exposure: include: "*"
1.新建一個名爲 hystrix-dashboard 項目,添加以下依賴:
<!-- hystrix-dashboard --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
2.新建 application.yml
server: port: 9300 spring: application: name: Hystrix-Dashboard
3.開啓監控功能
在啓動類上添加 @EnableHystrixDashboard 註解。
@EnableHystrixDashboard @SpringBootApplication public class HystrixdashboardApplication { public static void main(String[] args) { SpringApplication.run(HystrixdashboardApplication.class, args); } }
啓動,瀏覽器訪問: http://localhost:9300/hystrix:
咱們以監控 order-server 爲例,在監控界面添加監控信息:
# 須要監控的服務地址 http://localhost:8100/actuator/hystrix.stream delay: 請求間隔時間 title: 監控名稱 點擊 monitor stream 批量訪問 order-server 服務的下單接口。
最終效果以下:
經過批量訪問下單接口,發現圖中實心圓和曲線發生了變化。那咱們如何根據這兩個圖形查看監控信息呢?
實心圓:經過顏色的變化表明實例的健康程度,健康度從綠色>黃色>橙色>紅色遞減。其大小也會根據實例的請求流量發生變化,流量越大實心圓越大。
曲線:用來記錄間隔時間內流量的相對變化,一般能夠觀察到流量的上升和降低趨勢。