Hystrix介紹
Hystrix是一個用於處理分布式系統的延遲和容錯的開源庫,在分布式系統里,許多依賴不可避免的會調用失敗,比如超時、異常等,Hystrix能保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分布式系統的彈性。
“斷路器”本身是一種開關裝置,當某個服務單元發生故障之后,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回一個符合預期的、可處理的備選響應(FallBack),而不長時間的等待或者拋出調用方法無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地占用,從而避免了故障在分布式系統中的蔓延,乃至雪崩。
github地址:https://github.com/Netflix/Hystrix
服務降級
所謂降級,就是當某個服務出現異常之后,服務器將不再被調用,此時服務端可以自己准備一個本地的fallback回調,返回一個缺省值。 這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強,當然這也要看適合的業務場景。
可能出現服務降級的情況:
- 程序運行異常
- 服務超時
- 服務熔斷出發服務降級
- 線程池/信號量打滿也會導致服務降級
Hystrix使用
項目准備
搭建項目,本章采用的項目框架如下:
服務降級Fallback
1、在服務提供者模塊(test-springcloud-provider-payment8008)中,引入Hystrix的依賴:
1 <!-- hystrix --> 2 <dependency> 3 <groupId>org.springframework.cloud</groupId> 4 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> 5 </dependency>
完整pom如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>test-springcloud</artifactId> 7 <groupId>com.test</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>test-springcloud-provider-payment8008</artifactId> 13 14 <dependencies> 15 16 <!-- hystrix --> 17 <dependency> 18 <groupId>org.springframework.cloud</groupId> 19 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> 20 </dependency> 21 22 <!-- eureka client --> 23 <dependency> 24 <groupId>org.springframework.cloud</groupId> 25 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 26 </dependency> 27 28 <!-- spring boot --> 29 <dependency> 30 <groupId>org.springframework.boot</groupId> 31 <artifactId>spring-boot-starter-web</artifactId> 32 </dependency> 33 <dependency> 34 <groupId>org.springframework.boot</groupId> 35 <artifactId>spring-boot-starter-actuator</artifactId> 36 </dependency> 37 38 <dependency> 39 <groupId>org.springframework.boot</groupId> 40 <artifactId>spring-boot-devtools</artifactId> 41 <scope>runtime</scope> 42 <optional>true</optional> 43 </dependency> 44 45 <dependency> 46 <groupId>org.projectlombok</groupId> 47 <artifactId>lombok</artifactId> 48 <optional>true</optional> 49 </dependency> 50 <dependency> 51 <groupId>org.springframework.boot</groupId> 52 <artifactId>spring-boot-starter-test</artifactId> 53 <scope>test</scope> 54 </dependency> 55 56 </dependencies> 57 58 <build> 59 <finalName>test-springcloud-provider-payment8008</finalName> 60 </build> 61 </project>
2、配置文件如下:
1 # 端口 2 server: 3 port: 8008 4 5 spring: 6 application: 7 name: cloud-payment-service 8 9 eureka: 10 client: 11 service-url: 12 defaultZone: http://localhost:8761/eureka 13 instance: 14 # instance: 15 instance-id: ${spring.cloud.client.ip-address}:${server.port} 16 # 訪問路徑可以顯示IP地址 17 prefer-ip-address: true
3、編輯啟動類,使用注解@EnableCircuitBreaker,允許斷路器
1 @SpringBootApplication 2 @EnableEurekaClient 3 //允許斷路器 4 @EnableCircuitBreaker 5 public class PaymentMain8008 { 6 public static void main(String[] args) { 7 SpringApplication.run(PaymentMain8008.class, args); 8 } 9 }
4、編輯業務類,並在方法上使用@HystrixCommand注解,表明方法支持服務降級,且設置了超時的降級策略
1 @Service 2 public class PaymentService { 3 4 public String paymentInfo_OK(Integer id) { 5 return "線程池:" + Thread.currentThread().getName() 6 + ",paymentInfo_OK,ID == " + id; 7 } 8 9 10 // fallbackMethod: 設置HystrixCommand服務降級所使用的方法名稱,注意該方法需要與原方法定義在同一個類中,並且方法簽名也要一致 11 // commandProperties: 設置HystrixCommand屬性,如:斷路器失敗百分比、斷路器時間容器大小等 12 // 設置斷路器超時降級策略,時間3000毫秒超時 13 @HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler", commandProperties = { 14 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") 15 }) 16 public String paymentInfo_Timeout(Integer id) { 17 int second = 5000; 18 try { 19 // 休眠5000毫秒 20 TimeUnit.MILLISECONDS.sleep(second); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 // 異常 25 // int n = 10/0; 26 return "線程池:" + Thread.currentThread().getName() 27 + ",paymentInfo_Timeout,ID == " + id 28 + ",耗時" + second + "毫秒"; 29 } 30 31 public String paymentInfo_TimeoutHandler(Integer id) { 32 String result = "線程池:" + Thread.currentThread().getName() 33 + ",paymentInfo_TimeoutHandler,ID == " + id; 34 return result; 35 } 36 }
5、編輯controller
1 @RestController 2 @Slf4j 3 public class PaymentController { 4 5 @Autowired 6 private PaymentService paymentService; 7 8 @Value("${server.port}") 9 private String serverPort; 10 11 @GetMapping(value = "/payment/hystrix/ok/{id}") 12 public String paymentInfo_OK(@PathVariable("id") Integer id) { 13 String result = paymentService.paymentInfo_OK(id); 14 log.info("result===" + result); 15 return result; 16 } 17 18 @GetMapping(value = "/payment/hystrix/timeout/{id}") 19 public String paymentInfo_Timeout(@PathVariable("id") Integer id) { 20 String result = paymentService.paymentInfo_Timeout(id); 21 log.info("result===" + result); 22 return result; 23 } 24 25 }
6、測試,啟動注冊中心,以及服務提供者項目
訪問地址:http://localhost:8008/payment/hystrix/ok/1,正常響應
訪問地址:http://localhost:8008/payment/hystrix/timeout/1,服務降級
同時,可以修改業務類中paymentInfo_Timeout方法,讓此方法報異常,然后進行訪問,發現一樣會服務降級
全局服務降級DefaultProperties
1、在服務消費者模塊(test-springcloud-order7996)中,引入Hystrix的依賴:
完整pom如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>test-springcloud</artifactId> 7 <groupId>com.test</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>test-springcloud-order7996</artifactId> 13 14 <dependencies> 15 16 <!-- hystrix --> 17 <dependency> 18 <groupId>org.springframework.cloud</groupId> 19 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> 20 </dependency> 21 22 <!-- openfeign --> 23 <dependency> 24 <groupId>org.springframework.cloud</groupId> 25 <artifactId>spring-cloud-starter-openfeign</artifactId> 26 </dependency> 27 28 <!-- eureka client --> 29 <dependency> 30 <groupId>org.springframework.cloud</groupId> 31 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 32 </dependency> 33 34 <!-- spring boot --> 35 <dependency> 36 <groupId>org.springframework.boot</groupId> 37 <artifactId>spring-boot-starter-web</artifactId> 38 </dependency> 39 <dependency> 40 <groupId>org.springframework.boot</groupId> 41 <artifactId>spring-boot-starter-actuator</artifactId> 42 </dependency> 43 44 <dependency> 45 <groupId>org.springframework.boot</groupId> 46 <artifactId>spring-boot-devtools</artifactId> 47 <scope>runtime</scope> 48 <optional>true</optional> 49 </dependency> 50 51 <dependency> 52 <groupId>org.projectlombok</groupId> 53 <artifactId>lombok</artifactId> 54 <optional>true</optional> 55 </dependency> 56 <dependency> 57 <groupId>org.springframework.boot</groupId> 58 <artifactId>spring-boot-starter-test</artifactId> 59 <scope>test</scope> 60 </dependency> 61 62 </dependencies> 63 64 <build> 65 <finalName>test-springcloud-order7996</finalName> 66 </build> 67 </project>
2、編輯配置文件如下:
1 # 端口 2 server: 3 port: 7996 4 5 spring: 6 application: 7 name: cloud-order 8 9 eureka: 10 client: 11 service-url: 12 defaultZone: http://localhost:8761/eureka 13 instance: 14 # instance: 15 instance-id: ${spring.cloud.client.ip-address}:${server.port} 16 # 訪問路徑可以顯示IP地址 17 prefer-ip-address: true
3、編輯啟動類
使用注解@EnableFeignClients,啟動openfeign
使用注解@EnableHystrix,啟用Hystrix,查看注解@EnableHystrix,里面也包含了注解@EnableCircuitBreaker
1 @SpringBootApplication 2 @EnableEurekaClient 3 @EnableFeignClients 4 // 啟動Hystrix 5 @EnableHystrix 6 public class OrderMain7996 { 7 public static void main(String[] args) { 8 SpringApplication.run(OrderMain7996.class, args); 9 } 10 }
4、編輯一個接口,並使用@FeignClient注解,表明一個是openfeign客戶端
1 @Component 2 // openfeign客戶端 3 @FeignClient(value = "CLOUD-PAYMENT-SERVICE") 4 public interface PaymentHystrixService { 5 6 @GetMapping(value = "/payment/hystrix/ok/{id}") 7 public String paymentInfo_OK(@PathVariable("id") Integer id); 8 9 @GetMapping(value = "/payment/hystrix/timeout/{id}") 10 public String paymentInfo_Timeout(@PathVariable("id") Integer id); 11 }
5、編寫一個controller,內容如下
1)類上需要使用@DefaultProperties(defaultFallback = "paymentClobalFallbackMethod"),定義一個默認的回調方法
2)paymentTimeout方法上需要使用@HystrixCommand 支持服務降級
1 @RestController 2 @Slf4j 3 @DefaultProperties(defaultFallback = "paymentClobalFallbackMethod") 4 public class OrderHystrixController { 5 @Autowired 6 private PaymentHystrixService paymentHystrixService; 7 8 @GetMapping(value = "/consumer/payment/hystrix/ok/{id}") 9 public String paymentInfo_OK(@PathVariable("id") Integer id) { 10 String result = paymentHystrixService.paymentInfo_OK(id); 11 log.info("result===" + result); 12 return result; 13 } 14 // @HystrixCommand(fallbackMethod = "paymentTimeoutFallbackMethod", commandProperties = { 15 // @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500") 16 // }) 17 @GetMapping(value = "/consumer/payment/hystrix/timeout/{id}") 18 // @HystrixCommand 支持服務降級 19 @HystrixCommand 20 public String paymentTimeout(@PathVariable("id") Integer id) { 21 int n = 10/0; 22 String result = paymentHystrixService.paymentInfo_Timeout(id); 23 log.info("result===" + result); 24 return result; 25 } 26 27 public String paymentTimeoutFallbackMethod(@PathVariable("id") Integer id) { 28 String result = "消費者:對方支付系統繁忙,請稍后再試,ID == " + id; 29 log.info("result===" + result); 30 return result; 31 } 32 33 }
6、測試
1)啟動Eureka注冊中心,關閉服務提供者項目,啟動服務消費者模塊(test-springcloud-order7996)
2)訪問地址:http://localhost:7996/consumer/payment/hystrix/ok/1,不支持服務降級
3)訪問地址:http://localhost:7996/consumer/payment/hystrix/timeout/1,支持服務降級
通配服務降級
1、在以上項目的基礎上,新增接口實現類PaymentFallbackService,實現接口PaymentHystrixService
1 @Component 2 public class PaymentFallbackService implements PaymentHystrixService { 3 public String paymentInfo_OK(Integer id) { 4 return "PaymentFallbackService——》paymentInfo_OK——》統一處理:" + id; 5 } 6 7 public String paymentInfo_Timeout(Integer id) { 8 return "PaymentFallbackService——》paymentInfo_Timeout——》統一處理:" + id; 9 } 10 }
2、修改接口PaymentHystrixService的配置,如下:
1 @Component 2 // openfeign客戶端 3 // fallback: 定義容錯的處理類,當調用遠程接口失敗或超時時,會調用對應接口的容錯邏輯, 4 // fallback指定的類必須實現@FeignClient標記的接口 5 @FeignClient(value = "CLOUD-PAYMENT-SERVICE", fallback = PaymentFallbackService.class) 6 public interface PaymentHystrixService {
3、測試
1)啟動Eureka注冊中心,關閉服務提供者項目,啟動服務消費者模塊(test-springcloud-order7996)
2)訪問地址:http://localhost:7996/consumer/payment/hystrix/ok/1,支持服務降級,且是通配服務降級的返回內容
3)訪問地址:http://localhost:7996/consumer/payment/hystrix/timeout/1,支持服務降級,返回的是默認全局的服務降級內容