分布式系统面临的问题:
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败
多个微服务之间的调用,结社微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的“扇出”如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所以的 “雪崩效应”
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败糟糕的是,这些应用程序还可能导致服务之间延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理以便单个依赖关系的失败,不能取消整个应用程序或系统
所以,通常当发现一个模块下的某个实例失败后,这时候这个模块依然会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等。
Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器” 本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控,向调用方放回一个符合预期的、可处理的备选响应,而不是长时间的等待或抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
使用hystrix已经可以代替原有的provider和order了
所以两个都可以新建一个模块
在原有基础上添加上Hystrix的jar包
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
由于Hystrix已经停更,2.2.10是最后的一个版本
主启动类上需要添加@EnableHystrix注解
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableEurekaClient
@EnableHystrix // 必须开启
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class,args);
}
}
这里可以以service服务实现类来做 服务降级
但结构简单了点,直接用了Impl类
@Service
public class PaymentService {
public String paymentInfo_OK(Integer id){
return "线程池:"+Thread.currentThread().getName()+"——id:"+id;
}
/**
* @HystrixCommand 若是出错、超时等异常情况,返回一个兜底方法
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler",commandKey = "commandKey01")
public String paymentInfo_ERROR(Integer id){
// int i = 10/0;// 直接异常
// 超时异常
try {
TimeUnit.SECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "ERROR - 线程池:"+Thread.currentThread().getName()+"——id:"+id;
}
/**
异常回调函数
*/
public String peymentInfo_ERROR_Handler(Integer id){
return "ERROR - 兜底监听方法 - 线程池:"+Thread.currentThread().getName()+"——id:"+id;
}
}
@HystrixCommand(fallbackMethod = “peymentInfo_ERROR_Handler”,commandKey = “commandKey01”) fallbackMethod 参数值直接是兜底方法的方法名
在需要使用异常回调方法的方法上添加上@HystixCommand注解,即可开启服务降级
@HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler",commandKey = "commandKey01")
实际上,服务降级光光在provider上使用注解也可以达到服务降级的操作。 而我们也可以在添加order80后,有了转发,也可以在order80中添加服务降级,比provider要更先一步获得异常并捕获
当要设置超时时间时,需要在yaml配置文件中配置时间。老版本中在注解中设置已经无用
## hystrix 设置兜底请求兜底方法的最多超时时间
hystrix:
command:
HystrixCommandKey:
execution:
isolation:
thread:
timeoutInMilliseconds: 1500
在主启动类上,一样要添加@EnableHystrix注解
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class,args);
}
}
一样的转发接口
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String peymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/error/{id}")
public String peymentInfo_ERROR(@PathVariable("id") Integer id);
}
在控制器内,若是想要开启该控制器内的全部函数都有一个异常回调方法,
那么需要在开启的方法上添加没有参数的@hystrixCommand注解,其二就是在控制器上添加@DefaultProperties(defaultFallback = “paymentDefaultFallBackMethod”)注解。
@DefaultProperties注解的参数就是默认的回调函数
@Slf4j
@RestController
@DefaultProperties(defaultFallback = "paymentDefaultFallBackMethod")
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@HystrixCommand
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String peymentInfo_OK(@PathVariable("id") Integer id){
String result = paymentHystrixService.peymentInfo_OK(id);
return result;
}
// @HystrixCommand(fallbackMethod = "peymentInfo_ERROR_Handler_80",commandKey = "commandKey_80")
@HystrixCommand
@GetMapping("/consumer/payment/hystrix/error/{id}")
public String peymentInfo_ERROR(@PathVariable("id") Integer id){
String s = paymentHystrixService.peymentInfo_ERROR(id);
return s;
}
public String peymentInfo_ERROR_Handler_80(@PathVariable("id") Integer id){
return "消费者80的监听兜底方法出现了!!!";
}
/**
* 全局fallback方法
* @return
*/
public String paymentDefaultFallBackMethod(){
return "控制器内存在方法或运行异常,执行了默认fallback方法!!";
}
}
若是还不够,那么可以在转发接口上做点文章。可以在接口类的@FeignClient注解上设置第二个参数:fallback;
@Component
/**
* fallback = PaymentHystrixFallbackService.class
* ———————— 设定该接口只要调用的方法中存在错误异常,都会使用该实现类中的兜底方法
*/
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentHystrixFallbackService.class)
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String peymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/error/{id}")
public String peymentInfo_ERROR(@PathVariable("id") Integer id);
}
这个参数我们需要一个实现该接口类的service类,来作为我们的异常调用方法
@Component
public class PaymentHystrixFallbackService implements PaymentHystrixService{
@Override
public String peymentInfo_OK(Integer id) {
return "peymentInfo_OK ______ 执行fallback";
}
@Override
public String peymentInfo_ERROR(Integer id) {
return "peymentInfo_ERROR _______ 执行fallback";
}
}
这样在接口转发回调时就会被触发
我们在provider的控制器中,再次添加一个方法
// ============= 服务熔断
@HystrixCommand(fallbackMethod = "paymentCirecuitBreakerFallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
})
public String paymentCirecuitBreaker(@PathVariable("id") Integer id){
if (id<0){
throw new RuntimeException("###########id,不能是负数");
}
return Thread.currentThread().getName()+"\t"+"调用成功,流水号"+System.currentTimeMillis();
}
public String paymentCirecuitBreakerFallback(@PathVariable("id") Integer id){
return "id不能是负数————————触发fallback"+id;
}
具体看注解。注解中的commandProperties参数就是配置和熔断的各类内容
@HystrixCommand(fallbackMethod = "paymentCirecuitBreakerFallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
})
public String paymentCirecuitBreaker(@PathVariable("id") Integer id){}
设计到断路器的三个重要参数:快照时间窗、请求总数阈值、错误百分比阈值
Hystrix(图形化)已过时,对应的jar包也已经找不到了。
<!-- 未找到依赖,去maven的jar包仓库中也未找到 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>