一、Hystrix介绍
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
github地址:https://github.com/Netflix/Hystrix
服务降级
所谓降级,就是当某个服务出现异常之后,服务器将不再被调用,此时服务端可以自己准备一个本地的fallback回调,返回一个缺省值。 这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。
可能出现服务降级的情况:
- 程序运行异常
- 服务超时
- 服务熔断出发服务降级
- 线程池/信号量打满也会导致服务降级
二、在提供者单独使用Hystrix
-
zookeeper-provider-payment8003
pom.xml
<!--hystrix熔断器--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
PaymentService
1 package com.sdkj.service; 2 3 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 4 import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; 5 import org.springframework.stereotype.Service; 6 import org.springframework.web.bind.annotation.PathVariable; 7 8 import java.util.UUID; 9 import java.util.concurrent.TimeUnit; 10 11 /** 12 * @Author wangshuo 13 * @Date 2022/5/23, 22:02 14 * Please add a comment 15 */ 16 @Service 17 public class PaymentService { 18 19 public String paymentInfo_OK(Integer id) { 20 return "线程池:" + Thread.currentThread().getName() 21 + ",paymentInfo_OK,ID == " + id; 22 } 23 24 25 // fallbackMethod: 设置HystrixCommand服务降级所使用的方法名称,注意该方法需要与原方法定义在同一个类中,并且方法签名也要一致 26 // commandProperties: 设置HystrixCommand属性,如:断路器失败百分比、断路器时间容器大小等 27 // 设置断路器超时降级策略,时间3000毫秒超时 28 @HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler", commandProperties = { 29 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") 30 }) 31 public String paymentInfo_Timeout(Integer id) { 32 int second = 5000; 33 try { 34 // 休眠5000毫秒 35 TimeUnit.MILLISECONDS.sleep(second); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 // 异常 40 // int n = 10/0;//测试异常降级 41 return "线程池:" + Thread.currentThread().getName() 42 + ",paymentInfo_Timeout,ID == " + id 43 + ",耗时" + second + "毫秒"; 44 } 45 46 public String paymentInfo_TimeoutHandler(Integer id) { 47 String result = "线程池:" + Thread.currentThread().getName() 48 + ",paymentInfo_TimeoutHandler,ID == " + id; 49 return result; 50 } 51 52 // 服务熔断 53 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", 54 // 属性设置参考:HystrixCommandProperties 55 commandProperties = { 56 // 是否开启断路器,默认true 57 @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), 58 // 请求次数,默认20 59 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), 60 // 时间窗口期,默认5000 61 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), 62 // 失败率到达多少后跳闸,默认50 63 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") 64 }) 65 public String paymentCircuitBreaker(@PathVariable("id") Integer id){ 66 if(id < 0) { 67 throw new RuntimeException("======== id 不能为负数 ========="); 68 } 69 String serialNumber = UUID.randomUUID().toString(); 70 return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber; 71 } 72 73 public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ 74 return " id 不能为负数,请稍后再试, id == " + id; 75 } 76 77 }
PaymentController
1 package com.sdkj.controller; 2 3 import com.sdkj.service.PaymentService; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.annotation.Value; 6 import org.springframework.stereotype.Controller; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.ResponseBody; 9 10 import java.util.UUID; 11 12 /** 13 * @Author wangshuo 14 * @Date 2022/5/21, 19:14 15 * Please add a comment 16 */ 17 @Controller 18 @RequestMapping(value = "/payment") 19 public class PaymentController { 20 21 @Value("${server.port}") 22 private String serverPort; 23 @Autowired 24 PaymentService paymentService; 25 26 @RequestMapping(value = "/getZk") 27 @ResponseBody 28 public String getPaymentZk(){ 29 30 return "spring cloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID(); 31 } 32 33 //测试线程不降级 34 @RequestMapping(value = "/hystrix/ok") 35 @ResponseBody 36 public String getHystrixOk(Integer id){ 37 38 return paymentService.paymentInfo_OK(id); 39 } 40 41 //测试超时降级 42 @RequestMapping(value = "/hystrix/timeout") 43 @ResponseBody 44 public String getHystrixTimeout(Integer id){ 45 46 return paymentService.paymentInfo_Timeout(id); 47 } 48 49 //测试超时降级 50 @RequestMapping(value = "/hystrix/runtime") 51 @ResponseBody 52 public String getHystrixRuntime(Integer id){ 53 54 return paymentService.paymentCircuitBreaker(id); 55 } 56 }
App
1 package com.sdkj; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 8 /** 9 * @Author wangshuo 10 * @Date 2022/5/21, 19:11 11 * Please add a comment 12 */ 13 //服务发现 14 @EnableDiscoveryClient 15 //启用熔断器 16 @EnableCircuitBreaker 17 @SpringBootApplication 18 public class App { 19 20 public static void main(String[] args) { 21 SpringApplication.run(App.class, args); 22 } 23 }
三、消费者调用生产者使用Hystrix
-
zookeeper-consumer-order8004
pom.xml
<!--hystrix熔断器--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
OrderController
1 package com.sdkj.controller; 2 3 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.GetMapping; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.ResponseBody; 9 import org.springframework.web.client.RestTemplate; 10 11 /** 12 * @Author wangshuo 13 * @Date 2022/5/21, 19:30 14 * Please add a comment 15 */ 16 @Controller 17 @RequestMapping(value = "/order") 18 public class OrderController { 19 20 private static final String url = "http://cloud-payment-service"; 21 @Autowired 22 private RestTemplate restTemplate; 23 24 @RequestMapping(value = "/getPaymentZk") 25 @ResponseBody 26 public String getPaymentZk() { 27 28 return restTemplate.getForObject(url + "/payment/getZk", String.class); 29 } 30 31 @GetMapping(value = "/hystrix/timeout") 32 // @HystrixCommand 支持服务降级 33 @HystrixCommand(fallbackMethod = "paymentDemoteFallback") 34 @ResponseBody 35 public String paymentTimeout(Integer id) { 36 //int n = 10/0; 37 return restTemplate.getForObject(url + "/payment/hystrix/timeout?id="+id, String.class); 38 } 39 40 //降级回调方法 41 public String paymentDemoteFallback(Integer id){ 42 43 return "消费者:对方支付系统繁忙,请稍后再试,ID == "+id; 44 } 45 }
App
1 package com.sdkj; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.netflix.hystrix.EnableHystrix; 6 7 /** 8 * @Author wangshuo 9 * @Date 2022/5/21, 19:30 10 * Please add a comment 11 */ 12 //开启熔断器(这个注解包含了@EnableCircuitBreaker) 13 @EnableHystrix 14 @SpringBootApplication 15 public class App { 16 17 public static void main(String[] args) { 18 SpringApplication.run(App.class, args); 19 } 20 }
四、Hystrix配合Feign进行通配服务降级
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的配置,如下:
@Component // openfeign客户端 // fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑, // fallback指定的类必须实现@FeignClient标记的接口 @FeignClient(value = "CLOUD-PAYMENT-SERVICE", fallback = PaymentFallbackService.class) public interface PaymentHystrixService {
本文来自博客园,作者:荣慕平,转载请注明原文链接:https://www.cnblogs.com/rongmuping/articles/16303911.html