SpringCloud-服务降级_服务熔断_服务限流(Hystrix)
Hystrix
https://github.com/Netflix/Hystrix/
概述
前言
分布式系统面临的问题
复杂的分布式体系结构的应用 可能有很多个依赖,每个依赖在某些时刻将不可避免的失败;
服务雪崩
what
1、Hystrix是一个 处理分布式系统的延迟/容错的 开源库;
2、在分布式系统里,许多依赖不可避免的会调用失败(超时、异常...),Hystrix能保证在一个依赖出现异常的情况下,不会导致服务整体失败,避免级联故障,保证分布式系统的弹性;
3、"断路器"本身是一种开关,当某个服务单元发生故障时,通过断路器的故障检测 向调用方 返回一个符合预期、备选的FallBack,而不是长时间的等待或抛出调用方无法处理的异常;
这样保证了服务调用方的线程 不会被长时间占用,从而避免故障在分布式系统中蔓延,乃至雪崩;
停更维护怎么办
解决
resilience4j、
Hystrix概念
服务降级
what
当服务不可用时,给调用方的兜底响应;
什么情况会发生服务降级?
程序异常、超时、服务熔断触发服务降级、线程池满
服务熔断
what
当服务达到峰值,直接拒绝访问,给调用方一个兜底响应;
服务限流
what
当服务突然接收到大量请求时,限制单位时间内可处理的数量;
主要的问题
超时导致服务变慢
解决
超时不再继续等待
出错(服务宕机/程序出错)
解决
出错有兜底
解决方案
1、服务提供方超时/运行报错/宕机 -> 调用方不能卡死等待,必须有服务降级;
2、服务提供方正常,调用方自己故障/有自己要求(自己等待时间<服务提供方时间) -> 调用方自己服务降级;
How
服务降级
一般服务降级用在 服务调用方;
服务提供方
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> @EnableCircuitBreaker // 开启Hystrix @EnableEurekaClient @SpringBootApplication public class HystrixPaymentStarter8001 { public static void main(String[] args) { SpringApplication.run(HystrixPaymentStarter8001.class, args); } } @RestController public class Controller { @Autowired PaymentService paymentService; @HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) @GetMapping(value = "/hystrix/timeout") public String timeout(){ int i = 1/0; // 运行报错 return paymentService.timeout(); // 服务超时 } /** * 服务降级 Fallback方法 * @return */ public String timeOutFallback(){ return Thread.currentThread().getName() + "payment系统繁忙,请稍后再试! o(╥﹏╥)o"; } }
服务调用方
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> #开启Feign的Hystrix feign: hystrix: enabled: true @EnableHystrix // 开启Hystrix @EnableFeignClients // 开启Feign支持 @SpringBootApplication public class OpenFeignHystrixOrderStarter80 { public static void main(String[] args) { SpringApplication.run(OpenFeignHystrixOrderStarter80.class, args); } } @RestController public class OrderController { @Autowired private PaymentService paymentService; @HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }) @GetMapping(value = "/order/timeout") public String timeOut(){ int a = 1/0; // 程序运行报错 return paymentService.timeOut(); } /** * 服务降级 Fallback方法 * @return */ public String timeOutFallback(){ return Thread.currentThread().getName() + "由于 payment系统繁忙,请稍后再试! o(╥﹏╥)o"; } }
全局Fallback
标记@HystrixCommand方法才会进行服务降级:
有自定义的fallbackMethod,按自定义处理;
无自定义的fallbackMethod,按全局处理;
@DefaultProperties(defaultFallback = "globalFallback") // 全局fallback定义 @RestController public class OrderController { @Autowired private PaymentService paymentService; @HystrixCommand // 全局服务降级 @GetMapping(value = "/order/ok") public String ok(){ int a = 1/0; // 程序运行报错 return paymentService.ok(); } @HystrixCommand(fallbackMethod = "timeOutFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }) @GetMapping(value = "/order/timeout") public String timeOut(){ int a = 1/0; // 程序运行报错 return paymentService.timeOut(); } /** * 服务降级 Fallback方法 * @return */ public String timeOutFallback(){ return Thread.currentThread().getName() + "由于 payment系统繁忙,请稍后再试! o(╥﹏╥)o"; } /** * 服务降级 globalFallback方法 * @return */ public String globalFallback(){ return Thread.currentThread().getName() + "全局Fallback payment系统繁忙,请稍后再试! o(╥﹏╥)o"; } }
fallback方法与业务代码解耦
#开启Feign的Hystrix feign: hystrix: enabled: true @Component public class PaymentFallbackService implements PaymentService{ @Override public String ok() { return "PaymentFallbackService.ok O(∩_∩)O"; } @Override public String timeOut() { return "PaymentFallbackService.timeOut O(∩_∩)O"; } } @Component @FeignClient(value = "eureka-hystrix-payment-service", fallback = PaymentFallbackService.class) public interface PaymentService { @GetMapping(value = "/hystrix/ok") String ok(); @GetMapping(value = "/hystrix/timeout") String timeOut(); } @RestController public class OrderController { @Autowired private PaymentService paymentService; @GetMapping(value = "/order/ok") public String ok(){ return paymentService.ok(); } } @EnableHystrix // 开启Hystrix @EnableFeignClients // 开启Feign支持 @SpringBootApplication public class OpenFeignHystrixOrderStarter80 { public static void main(String[] args) { SpringApplication.run(OpenFeignHystrixOrderStarter80.class, args); } }
服务熔断
https://martinfowler.com/bliki/CircuitBreaker.html
熔断机制是什么
应对雪崩效应的 一种微服务链路保护机制;
当扇出链路的某个微服务不可用或响应时间过长,进行服务降级,进而熔断该节点微服务的调用,快速返回错误的响应信息;
当检测到该节点微服务调用正常后,恢复调用链路;
实现
在SpringCloud中,使用Hystrix实现;
Hystrix会监控微服务之间的调用情况,当失败的调用达到一定的阈值,缺省是5秒内20次失败,就会启动熔断机制;
Hystrix服务熔断机制注解 @HystrixCommand;
How
服务降级 -> 服务熔断 -> 恢复服务
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> server: port: 8001 spring: application: name: eureka-hystrix-payment-service eureka: client: register-with-eureka: true #是否向注册中心注册自己 fetchRegistry: true #是否从注册中心抓取已有的注册信息 默认true,集群必须设置为true service-url: defaultZone: http://localhost:7001/eureka/ #单机版 @EnableCircuitBreaker // 开启Hystrix @EnableEurekaClient @SpringBootApplication public class HystrixPaymentStarter8001 { public static void main(String[] args) { SpringApplication.run(HystrixPaymentStarter8001.class, args); } } package com.an; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * @author apy * @description * @date 2022/8/5 10:57 */ @RestController public class Controller { // 服务熔断 @HystrixCommand(fallbackMethod = "circuitBreakerFallback", commandProperties = { // 在10s访问时间内,进行10次访问,失败率达到60%后,进行熔断 @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") // 失败率达到多少后跳闸 }) @GetMapping(value = "/hystrix/circuitBreaker/{id}") public String circuitBreaker(@PathVariable(value = "id") Long id){ if (id < 0){ throw new IllegalArgumentException("param error"); } return Thread.currentThread().getName() + "success"; } /** * 服务降级 Fallback方法 * @param id * @return */ public String circuitBreakerFallback(Long id){ return "circuitBreakerFallback...id:"+ id; } }
熔断类型
Open:
请求不再调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟进入HalfOpen状态;
不会调用主逻辑,直接调用降级fallback;
Half Open:
部分请求根据规则调用当前服务,如果请求成功且符合规则,任务当前服务恢复正常,关闭熔断;
Close:
不会对服务进行熔断;
服务限流
...
Hystrix工作流程
https://github.com/Netflix/Hystrix/wiki/How-it-Works
Hystrix图形化Dashboard
what
Hystrix还提供了 图形化Dashboard,会持续记录所有通过Hystrix发起的请求的执行信息,并以图形报表的形式展示;
Netflix通过hystrix-metrics-event-stream实现了以上监控;
SpringCloud也整合了Hystrix Dashboard,对监控内容转化为图形化界面;
How
Hystrix Dashboard
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> server: port: 9001 @EnableHystrixDashboard @SpringBootApplication public class HystrixDashboardStarter9001 { public static void main(String[] args) { SpringApplication.run(HystrixDashboardStarter9001.class, args); } } http://localhost:9001/hystrix
Hystrix Dashboard监控8001微服务
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> 被监控的服务必须的依赖 </dependency> @EnableCircuitBreaker // 开启Hystrix @EnableEurekaClient @SpringBootApplication public class HystrixPaymentStarter8001 { public static void main(String[] args) { SpringApplication.run(HystrixPaymentStarter8001.class, args); } /** * 为服务监控而配置,与容错本身无关; * @return */ @Bean public ServletRegistrationBean getServlet(){ ServletRegistrationBean bean = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); bean.setLoadOnStartup(1); bean.addUrlMappings("/hystrix.stream"); bean.setName("HystrixMetricsStreamServlet"); return bean; } }