javascript
spring cloud 熔断_Spring Cloud 熔断器/断路器 Hystrix
在微服務架構中,業務會被拆分成一個個服務,服務間可以彼此調用。為了保證服務的高可用性,單個服務通常會被集群部署,但是由于網絡等原因,服務并不能保證100%可用。如果某個服務出現了問題,那么調用這個服務就會出現線程阻塞,如果此時又有大量的請求涌入,Servlet容器的線程資源就會被迅速消耗殆盡,最終導致服務癱瘓。服務與服務之間的依賴,導致了故障會傳播,以致于會對整個微服務系統造成影響,導致整個服務癱瘓,這種現象叫做雪崩現象。
如何保證在一個服務出現問題的情況下,不會導致整個服務癱瘓,這就是Hystrix需要做的事情。
0. 開發環境
- IDE:IntelliJ IDEA 2017.1 x64
- jdk:1.8.0_91
- Spring Boot:2.0.9.RELEASE
- Spring Cloud:Finchley.RELEASE
1. Hystrix簡介
Hystrix是一個實現了斷路器模式的庫,提供了熔斷、隔離、Fallback、cache、監控等功能,能夠在一個或多個依賴出現問題時保證系統依然可用。
我們可以把Hystrix想象成一個保險絲。在我們家庭的電路系統中,外部電路入戶時通常都會加上一個保險絲,當家庭電路系統中某一處發生意外,外部電壓過高,達到保險絲熔點的時候,保險絲就會被熔斷,切斷家庭與外部電路的聯通,進而保障家庭用電系統不會受到損壞。
Hystrix提供的斷路器就有類似功能,當在一定時間段內,服務消費者調用服務提供者的服務,次數達到設定的閾值,并且出錯的次數也達到設置的出錯閾值時,就會進行服務降級,讓服務消費者直接執行本地設置的降級策略,不再調用服務消費者的服務。
Hystrix提供的斷路器具有自我反饋和自我恢復的功能,Hystrix會根據接口調用的情況,讓斷路器在closed,open,half-open三種狀態之間自動切換。
- open狀態表示打開熔斷,即服務消費者執行本地設置的降級策略,不再調用服務消費者。
- closed狀態表示關閉熔斷,此時服務消費者直接調用服務提供者。
- half-open狀態,這是一個中間狀態,當斷路器處于該狀態時,服務消費者直接調用服務提供者。
2. 新建服務消費者
2.1 新建服務消費者
2.2 引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-consumer-hystrix</artifactId><packaging>jar</packaging><parent><groupId>cn.wbnull</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0.0</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency></dependencies> </project>2.3 新建application.yml
server:port: 8085servlet:context-path: /springbootconsumerspring:application:name: spring-boot-consumer-hystrixeureka:client:register-with-eureka: falsefetch-registry: trueservice-url:defaultZone: http://localhost:8090/springcloudeureka/eureka/2.4 新建啟動類
新建Spring Boot啟動類SpringBootConsumerHystrixApplication,增加如下注解,其中@EnableHystrix注解表示開啟Hystrix
package cn.wbnull.springbootconsumer;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate;@SpringBootApplication @EnableEurekaClient @EnableHystrix public class SpringBootConsumerHystrixApplication {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}public static void main(String[] args) {SpringApplication.run(SpringBootConsumerHystrixApplication.class, args);} }2.5新建控制器類
這里我們在接口方法users()上增加了@HystrixCommand(fallbackMethod = "usersFallback"),@HystrixCommand注解表示對該方法開啟斷路器功能,指定了熔斷方法是usersFallback。
package cn.wbnull.springbootconsumer.controller;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;import java.util.Map;@RestController @Scope("prototype") public class GatewayController {@Autowiredprivate RestTemplate restTemplate;@PostMapping(value = "/users")@HystrixCommand(fallbackMethod = "usersFallback")public Map<String, String> users(@RequestBody Map<String, String> request) throws Exception {ResponseEntity<Map> responseEntity = restTemplate.postForEntity("http://spring-boot-provider/springbootprovider/users", request, Map.class);return responseEntity.getBody();}public Map<String, String> usersFallback(Map<String, String> request) throws Exception {request.put("fallback", "spring-boot-consumer-hystrix");return request;} }2.6 測試
依次啟動spring-cloud-eureka,spring-boot-provider,spring-boot-provider-v2,spring-boot-consumer-hystrix。然后打開Postman,配置如下,不斷點擊Send按鈕,可以看到返回信息正常,且兩組返回信息交替出現。
然后我們關閉spring-boot-provider,spring-boot-provider-v2服務,再在Postman中測試,可以看到返回正常,返回信息如下,正是我們剛才usersFallback()方法中的處理。
這里如果我們沒有使用Hystrix的話,正常應該是會等待超時,然后返回超時信息。現在啟用Hystrix,當spring-boot-provider和spring-boot-provider-v2服務不可用時,spring-boot-consumer-hystrix調用spring-boot-provider的接口不通,會執行快速失敗,直接返回usersFallback()方法的處理結果,而不是等待超時,防止了線程阻塞。
2.7 修改Hystrix默認超時時間
2.7.1 修改控制器類
修改GatewayController類中users()方法,增加上休眠2秒。
@PostMapping(value = "/users")@HystrixCommand(fallbackMethod = "usersFallback")public Map<String, String> users(@RequestBody Map<String, String> request) throws Exception {Thread.sleep(2000);ResponseEntity<Map> responseEntity = restTemplate.postForEntity("http://spring-boot-provider/springbootprovider/users", request, Map.class);return responseEntity.getBody();}然后我們再依次啟動spring-cloud-eureka,spring-boot-provider,spring-boot-provider-v2,spring-boot-consumer-hystrix。然后繼續使用Postman測試,發現依舊返回熔斷方法中參數。
這是因為Hystrix默認的超時時間是1秒,也就是服務消費者在等待服務提供者返回信息時,如果超過1秒沒有得到返回信息的話,就認為服務提供者故障,直接執行本地設置的降級策略,也就是usersFallback()方法。
我們可以通過配置文件修改Hystrix超時時間
2.7.2 修改Hystrix超時時間
application.yml文件增加如下配置
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000然后我們重啟spring-boot-consumer-hystrix,再次使用Postman測試,返回信息正常。
3. Feign中使用斷路器
Feign中已經默認集成了Hystrix,但是Spring Cloud在D版本之后沒有默認打開。需要在配置文件中配置打開它。
feign.hystrix.enabled=true3.1 新建Feign服務消費者
3.2 引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-consumer-feign-hystrix</artifactId><packaging>jar</packaging><parent><groupId>cn.wbnull</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0.0</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies> </project>3.3 新建application.yml
server:port: 8086servlet:context-path: /springbootconsumerspring:application:name: spring-boot-consumer-feign-hystrixeureka:client:register-with-eureka: falsefetch-registry: trueservice-url:defaultZone: http://localhost:8090/springcloudeureka/eureka/feign:hystrix:enabled: true3.4 新建啟動類
package cn.wbnull.springbootconsumer;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication @EnableEurekaClient @EnableFeignClients public class SpringBootConsumerFeignHystrixApplication {public static void main(String[] args) {SpringApplication.run(SpringBootConsumerFeignHystrixApplication.class, args);} }3.5 新建FeignClient類
這里熔斷之后的降級處理策略不是指定單個熔斷方法,而是指定一個類。@FeignClient(value = "spring-boot-provider", fallback = GatewayFallback.class)
package cn.wbnull.springbootconsumer.feign;import cn.wbnull.springbootconsumer.fallback.GatewayFallback; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.PostMapping;import java.util.Map;@Component @FeignClient(value = "spring-boot-provider", fallback = GatewayFallback.class) public interface GatewayFeignClient {@PostMapping(value = "/springbootprovider/users")Map<String, String> users(Map<String, String> request) throws Exception; }3.6 新建Fallback類
新建熔斷處理類GatewayFallback,GatewayFallback類需要實現上面的GatewayFeignClient接口,并注入到IoC容器中。
package cn.wbnull.springbootconsumer.fallback;import cn.wbnull.springbootconsumer.feign.GatewayFeignClient; import org.springframework.stereotype.Component;import java.util.Map;@Component public class GatewayFallback implements GatewayFeignClient {@Overridepublic Map<String, String> users(Map<String, String> request) throws Exception {request.put("fallback", "spring-boot-consumer-feign-hystrix");return request;} }3.7 新建控制器類
package cn.wbnull.springbootconsumer.controller;import cn.wbnull.springbootconsumer.feign.GatewayFeignClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController @Scope("prototype") public class GatewayController {@Autowiredprivate GatewayFeignClient gatewayFeignClient;@PostMapping(value = "/users")public Map<String, String> users(@RequestBody Map<String, String> request) throws Exception {return gatewayFeignClient.users(request);} }3.8 測試
依次啟動spring-cloud-eureka,spring-boot-provider,spring-boot-provider-v2,spring-boot-consumer-feign-hystrix。然后使用Postman測試,可以看到返回信息正常,且兩組返回信息交替出現。
然后我們關閉spring-boot-provider,spring-boot-provider-v2服務,再在Postman中測試,可以看到返回正常,返回信息如下,正是我們在GatewayFallback類users()方法中的處理。
3.9 修改Hystrix默認超時時間
3.9.1 修改控制器類
修改GatewayController類中users()方法,增加上休眠2秒。
@PostMapping(value = "/users")public Map<String, String> users(@RequestBody Map<String, String> request) throws Exception {Thread.sleep(2000);return gatewayFeignClient.users(request);}然后我們再依次啟動spring-cloud-eureka,spring-boot-provider,spring-boot-provider-v2,spring-boot-consumer-feign-hystrix。然后使用Postman測試,返回熔斷方法中參數。
3.9.2 修改Hystrix超時時間
Feign默認集成了Ribbon,Ribbon也有一個超時時間,超時時間為1秒,所以這里不僅要設置Hystrix的超時時間,還要設置Ribbon的超時時間。
ribbon:ReadTimeout: 5000ConnectTimeout: 5000hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000然后我們重啟spring-boot-consumer-feign-hystrix,再次使用Postman測試,返回信息正常。
4. 獲取服務異常信息
到現在,我們已經使用Hystrix解決了服務提供者故障的問題,但是我們還是無法確定故障原因,所以我們需要捕捉提供者拋出的異常。恰巧,Hystrix支持該操作。
4.1 新建FallbackFactory
新建GatewayFallbackFactory類,實現FallbackFactory接口,并注入到IoC容器中。
package cn.wbnull.springbootconsumer.fallback;import cn.wbnull.springbootconsumer.feign.GatewayFeignClient; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component;@Component public class GatewayFallbackFactory implements FallbackFactory<GatewayFeignClient> {@Overridepublic GatewayFeignClient create(Throwable throwable) {return (request) -> {request.put("fallback", "spring-boot-consumer-feign-hystrix by GatewayFallbackFactory");request.put("throwable", throwable.toString());return request;};} }4.2 修改GatewayFeignClient
修改GatewayFeignClient類注解 @FeignClient
@FeignClient(value = "spring-boot-provider", fallbackFactory = GatewayFallbackFactory.class)4.3 測試
依次啟動spring-cloud-eureka,spring-boot-consumer-feign-hystrix。然后使用Postman測試,可以看到返回信息如下。
{"name": "熔斷測試name","fallback": "spring-boot-consumer-feign-hystrix by GatewayFallbackFactory","throwable": "java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: spring-boot-provider" }異常信息也捕捉到了,完美。
GitHub:
dkbnull/SpringCloudDemo?github.comCSDN:
https://blog.csdn.net/dkbnull/article/details/89578323?blog.csdn.net微信:
Spring Cloud 熔斷器/斷路器 Hystrix?mp.weixin.qq.com微博:
Spring Cloud 熔斷器/斷路器 Hystrix?weibo.com總結
以上是生活随笔為你收集整理的spring cloud 熔断_Spring Cloud 熔断器/断路器 Hystrix的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python整商运算符_python中的
- 下一篇: gradle idea java ssm