在微服務架構中,一般存在多個服務調用層。微服務之間經過網絡進行通訊,從而支撐起整個應用,爲了保證高可用,單個服務一般也會集羣部署。但因爲網絡緣由或者自身緣由,服務並不能保證100% 可用。而服務間的依賴關係,會致使故障傳播,即服務提供者的不可用會致使消費者不可用,並把不可用逐漸放大,這就是雪崩效應。java
這裏就引入了請求超時機制和斷路器模式git
Hystrix 是 Netflix 的開源組件,是一個用於實現超時機制和斷路器模式的工具類庫。在微服務架構中,一般存在多個服務調用層。較低級別的服務中的服務故障可能致使級聯故障,一直到達用戶。當對特定服務的調用超過一個閾值(默認是 10秒/20個請求/故障百分比 > 50%),斷路器將打開而且不會進行調用。在出現錯誤和開路的狀況下,開發人員能夠提供一個回退github
斷路打開後能夠防止級聯故障。回退能夠是另外一個受 Hystrix 保護的調用、靜態數據或合理的空值。web
咱們在 Spring Cloud 服務消費(Ribbon) 中的例子基礎上添加 Hystrixspring
準備工做express
代碼參考:https://github.com/morgan412/spring-cloud-demo/tree/master/netflix網絡
添加 Hystrix 依賴架構
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
主類上添加註解 @EnableCircuitBreaker
,開啓斷路器功能app
@SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker public class OrderServiceRibbonHystrixApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceRibbonHystrixApplication.class, args); } @LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
在須要容錯的方法上添加註解 @HystrixCommand
,並指定回調(回退)方法ide
@Service public class ProductService { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "getProductFallBack") public Product getProduct(Long id) { return restTemplate.getForObject("http://product-service/product/" + id, Product.class); } public Product getProductFallBack(Long id) { Product product = new Product(); product.setId(-1L); product.setName("默認商品"); return product; } }
@HystrixCommand
的配置能夠比較靈活,可使用commandProperties
屬性列出@HystrixProperty
註釋,例如@HystrixCommand(fallbackMethod = "getProductFallBack", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"), @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000")}, threadPoolProperties = { @HystrixProperty(name = "coreSize", value = "1"), @HystrixProperty(name = "maxQueueSize", value = "10") })
@RestController @Log4j2 public class ProductController { @Autowired private ProductService productService; @GetMapping("/product/{id}") public Product getProduct(@PathVariable Long id) { return productService.getProduct(id); } }
驗證結果
{"id":-1,"name":"默認商品","description":null,"price":null,"count":null}
。說明當調用的服務不可用時,執行了回退方法Feign 使用聲明式的接口,沒有方法體,因此經過註解的方式顯然不適合 Feign。Spring Cloud 已經默認爲 Feign 整合了 Hystrix。咱們在 Spring Cloud 服務消費(Feign) 中的例子基礎上使用 Hystrix
準備工做
Spring Cloud 已經默認爲 Feign 整合了 Hystrix,因此咱們不須要添加依賴。配置文件中須要把 feign.hystrix.enabled
屬性設置爲 true
feign: hystrix: enabled: true
改寫 Feign 客戶端接口,在 @FeignClient
註解中經過 fallback 屬性指定回調類
@FeignClient(value = "product-service", fallback = ProductFeignClientFallback.class) public interface ProductFeignClient { @GetMapping("/product/{id}") Product getProduct(@PathVariable Long id); }
建立回調類,這個類須要實現 @FeignClient
的接口,其中實現的方法就是對應接口的回退方法
@Component public class ProductFeignClientFallback implements ProductFeignClient { @Override public Product getProduct(Long id) { Product product = new Product(); product.setId(-1L); product.setName("默認商品"); return product; } }
@RestController @Log4j2 public class ProductController { @Autowired private ProductFeignClient productFeignClient; @GetMapping("/product/{id}") public Product getProduct(@PathVariable Long id) { return productFeignClient.getProduct(id); } }
驗證結果
{"id":-1,"name":"默認商品","description":null,"price":null,"count":null}
。說明當調用的服務不可用時,執行了回退方法若是須要查看回退緣由,可使用註解 @FeignClient
中的 fallbackFactory 屬性
@FeignClient(value = "product-service", fallbackFactory = ProductClientFallbackFactoty.class) public interface ProductFeignClient { @GetMapping("/product/{id}") Product getProduct(@PathVariable Long id); }
同時建立 ProductClientFallbackFactoty 類,實現 FallbackFactory 接口,create 方法有個 Throwable 參數記錄回退緣由
@Component @Log4j2 public class ProductClientFallbackFactoty implements FallbackFactory<ProductFeignClient> { @Override public ProductFeignClient create(Throwable throwable) { return new ProductFeignClient() { @Override public Product getProduct(Long id) { // 日誌最好放在各個 fallback 方法中,而不要直接放在 create 方法中 // 不然在引用啓動時會打印該日誌 log.info("fallback, caused by:", throwable); Product product = new Product(); product.setId(-1L); product.setName("默認商品"); return product; } }; } }
測試一下結果,當調用的服務不可用時,會進入回調方法中,並打印以下日誌
2019-05-06 14:21:20.384 INFO 8056 --- [ HystrixTimer-1] c.t.o.c.ProductClientFallbackFactoty : fallback, caused by: com.netflix.hystrix.exception.HystrixTimeoutException: null
Hystrix 還提供了一些監控,當 HystrixCommand 和 HystrixObservableCommand 在執行時會產生會產生執行的結果和運行指標。能夠配合 spring-boot-starter-actuator
模塊同時設置 management.endpoints.web.exposure.include: hystrix.stream
,經過 /actuator/hystrix.stream
端點來獲取指標信息
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
management: endpoints: web: exposure: include: hystrix.stream
當有 HystrixCommand 方法被執行,訪問 /actuator/hystrix.stream
能夠重複看到一些信息
Feign 項目須要添加依賴
spring-cloud-starter-netflix-hystrix
,並在主類上加上註解@EnableCircuitBreaker
,才能使用/actuator/hystrix.stream
端點
使用 Hystrix Dashboard 可讓上面的監控數據可視化,新建一個 Spring Boot 工程 hystrix-dashboard
,添加依賴 spring-cloud-starter-netflix-hystrix-dashboard
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
而後在主類上添加註解 @EnableHystrixDashboard
@SpringBootApplication @EnableHystrixDashboard public class HystrixDashboardApplication { public static void main(String[] args) { SpringApplication.run(HystrixDashboardApplication.class, args); } }
設置服務端口 server.port=8000
,啓動 hystrix-dashboard
,訪問 http://localhost:8000/hystrix 能夠看到如下界面
從上面的界面咱們能夠看到,Hystrix Dashboard 面板監控支持三種方式:默認的集羣監控、自定義的集羣監控、單個應用的監控。其中前兩個集羣的方式是須要結合 Turbine 實現,後面去用到。另外 Delay
是輪詢監控信息的延遲時間,Title
是監控界面標題,默認是監控實例的 URL
http://turbine-hostname:port/turbine.stream
http://turbine-hostname:port/turbine.stream?cluster=[clusterName]
http://hystrix-app:port/actuator/hystrix.stream
那咱們把上面例子的 order-service-ribbon-hystrix
服務添加 hystrix 監控相關的端點,pom.xml 添加依賴 spring-boot-starter-actuator
,設置配置屬性 management.endpoints.web.exposure.include=hystrix.stream
,同時確保在主類上已經使用註解@EnableCircuitBreaker
或 @EnableHystrix
完成配置後,啓動項目,把地址 http://localhost:8081/actuator/hystrix.stream 添加到面板頁面,能夠看到如下界面
上面展現了 getProduct 這個 HystrixCommand 的各項指標,各指標含義能夠看下圖
Turbine 是聚合 Hystrix 監控數據的工具,上面的 Dashboard 面板能夠可視化一個 /actuator/hystrix.stream
端點的數據,可是對於多個服務和而且每一個服務有多個實例,來回的切換想要監控實例的地址就會很不方便。咱們須要一個把全部服務的 /actuator/hystrix.stream
端點數據整合起來的工具,這個工具就是 Turbine
建立一個 Spring Boot 項目命名爲 hystrix-turbine
,部分的依賴入以下,該依賴默認包含了 Eureka Client
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-turbine</artifactId> </dependency>
主類上添加註解 @EnableTurbine
,該註解的配置中已經配置了服務註冊的功能,即至關於包含了 @EnableDiscoveryClient
的功能
@SpringBootApplication @EnableTurbine public class HystrixTurbineApplication { public static void main(String[] args) { SpringApplication.run(HystrixTurbineApplication.class, args); } }
配置信息以下
server: port: 8001 spring: application: name: hystrix-turbine eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ turbine: app-config: order-service-ribbon-hystrix,order-service-feign-hystrix cluster-name-expression: "'default'" combine-host-port: true
turbine.app-config
配置用於查找實例的服務名
turbine.cluster-name-expression
指定集羣名稱,服務數量很的多時候,能夠啓動多個 Turbine 服務聚合不一樣的集羣數據,而該參數能夠用來區分不一樣的聚合
turbine.combine-host-port
經過主機名與端口號的組合來進行區分服務
咱們分別啓動項目 eureka-server:876一、product-service:807一、order-service-ribbon-hystrix:808九、order-service-feign-hystrix:8081
咱們能夠先測試下 http://localhost:8081/actuator/hystrix.stream 和 http://localhost:8089/actuator/hystrix.stream 的端口有無問題,沒有問題咱們啓動 hystrix-dashboard
,在頁面輸入 http://localhost:8001/turbine.stream 獲得的界面以下