Hystrix_服务降级
Hystrix三大特性并没有说明那个服务不能用,那个服务不能加,需要根据自己的业务场景添加。
服务降级
服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示。这就是fallback的作用。
那些情况会发生服务降级
- 服务程序运行异常
- 服务运行超时
- 服务熔断机制触发服务降级
- 线程池/信号量打满也会导致服务降级
从服务消费者代码理解服务降级
之前官方都是继承HystrixCommand实现自己的command,在command的构造方法中需要配置请求被执行需要的参数。但是现在大部分都是通过注解配置的形式去实现了,注解是@HystrixCommand
maven配置文件
1.主要是eureka,hystrix,openfeign三大组件
<dependencies>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--hystrix-->
<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>
<dependency>
<groupId>com.yu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yml文件配置
1.重点:配置feign:hystrix:enabled开启,在代码最末端
server:
port: 80
spring:
application:
name: cloud-consumer-feign-hystrix-order
eureka:
client:
register-with-eureka: true #向注册中心注册自己服务
service-url: #eureka注册中心地址
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群配置,往多个注册中心都注册
fetchRegistry: true #是否从Eureka注册中心抓取已有的服务,默认是true,
#但是集群必须是true才可以配合ribbon做负载均衡
ribbon:
ReadTimeout: 5000 #数据读取等待时间
ConnectTimeout: 5000 #请求连接等待时间
logging:
level:
#feign日志以什么级别监控那个接口
com.yu.springcloud.service.PaymentFeignService: debug
feign:
hystrix:
enabled: true #开启hystrix功能
主启动类配置
1.需要开启Hystrix功能添加@EnableHystrix注解
/**
1. @author 小鱼
2. @version 1.0
3. @date 2021/7/26 9:31 下午
4. @EnableHystrix:开启hystrix功能
*/
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderFeignHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignHystrixMain80.class);
}
}
Feign远程接口
1.了解Feign可以明白这是消费者客户端通过Feign远程调用了生产者服务端具体的服务
2.配置@FeignClient中的value属性:生产者微服务yml配置的服务名称,fallback属性:填写实现PaymentHystrixService接口的实现类。因为当生产者服务发生了上述中的问题的之后,会调用具体的实现类中的方法,返回一个符合预期结果给具体调用放。
总结
这是消费者对生产者远程调用进行一个预防,达到一个服务降级的概念
/**
5. @author 小鱼
6. @version 1.0
7. @date 2021/7/26 9:33 下午
8. @FeignClient:
9. 1.配置了远程调用生产者的微服务名称。
10. 2.fallback配置了生产者微服务的默认服务降级
*/
@FeignClient(value = "cloud-payment-hystrix-service",fallback = PaymentHystrixFallbackService.class)
@Component
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/paymentInfoOk/{id}")
public String paymentInfoOk(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/paymentInfoTimeout/{id}")
public String paymentInfoTimeout(@PathVariable("id")Integer id);
}
服务降级后处理方法
/**
11. @author 小鱼
12. @version 1.0
13. @date 2021/7/27 8:26 下午
*/
@Component
public class PaymentHystrixFallbackService implements PaymentHystrixService {
@Override
public String paymentInfoOk(Integer id) {
return "生产者服务出错或者服务繁忙!";
}
@Override
public String paymentInfoTimeout(Integer id) {
return "生产者服务出错或者服务繁忙!o(╥﹏╥)o";
}
}
消费者自身的统一服务降级配置
1.在类中添加@DefaultProperties(defaultFallback = “paymentGlobalFallback”),对于自身的类有一个统一的服务降级后处理的方法。
/**
14. @author 小鱼
15. @version 1.0
16. @date 2021/7/26 9:32 下午
17. @DefaultProperties:
18. 1.设置默认的通一的服务降级调用方法。
19. 2.需要设置默认的必须加上@HystrixCommand
20. 3.定制化的可以加上@HystrixCommand(fallbackMethod = "XXXXXXXXXXXX")对应的方法
*/
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "paymentGlobalFallback")
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@GetMapping("/consumer/payment/hystrix/paymentInfoOk/{id}")
@HystrixCommand()
public String paymentInfoOk(@PathVariable("id") Integer id){
int i= 1000/0;
return paymentHystrixService.paymentInfoOk(id);
}
@GetMapping("/consumer/payment/hystrix/paymentInfoTimeout/{id}")
@HystrixCommand
public String paymentInfoTimeout(@PathVariable("id")Integer id){
return paymentHystrixService.paymentInfoTimeout(id);
}
public String paymentGlobalFallback(){
return "消费者出错误或者系统繁忙";
}
}
Hystrix_服务熔断
熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,恢复调用链路。
在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,
当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand。
大神论文
Martin Fowler:https://martinfowler.com/bliki/CircuitBreaker.html
论文整体思想: 对于软件系统来说,对运行在不同进程中的软件进行远程调用是很常见的,可能是在一个网络上的不同机器上。内存调用和远程调用之间的一个重大区别是,远程调用可能会失败,或者在达到某个超时限制之前没有响应就挂起。更糟糕的是,如果在一个没有响应的供应商上有许多调用者,那么您可能会耗尽关键资源,导致跨多个系统的级联故障。迈克尔 · 尼加德在他的优秀著作《释放它》中,普及了断路器模式,以防止这种灾难性的级联。
断路器实现思想: 断路器背后的基本思想非常简单。在断路器对象中包装一个受保护的函数调用,断路器对象监视故障。一旦故障达到一定的阈值,断路器跳闸,所有进一步的呼叫断路器返回一个错误,没有保护呼叫正在所有。通常,如果断路器跳闸,你还需要某种监视器警报。
下图来源: Martin Fowle博客图,加上个人理解并且机器翻译(沙拉查词插件:好用 O(∩_∩)O)
大神论文个人理解
断路器三个状态:打开,关闭,半打开(半关闭)
断路器计数器:阈值
- 一个远程调用请求进入断路器整个流程,首先你第一次请求断路器是关闭的,并且阈值的计数是0,这时候断路器状态是关闭。
- 当多个请求进入断路器可能因为多种原因导致某些请求失败,每失败一次阈值就会加一。 如果阈值没有达到要求断路器还是关闭的。如果阈值达到要求那么就会打开断路器,并且下次的请求不进入正常业务代码流程,直接返回错误页面或者你设计好的服务降级的方法去告知其他服务暂时不可用,这时候断路器的状态是打开。
- 当断路器打开之后,一定的时间之内会进入到一个半关闭的状态,会尝试让一部分请求去执行正常的代码流程,这时候断路器处于半打开状态。
- 当断路器半打开状态,并且断路器放过去请求正常流程代码都是正常的,那么断路器会关闭。反之(请求失败了)断路器重新打开
代码
主启动类
@EnableCircuitBreaker//开启断路器功能
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker//开启断路器功能
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class);
}
}
业务类方法设置断路器
- circuitBreaker.enabled:是否开启断路器
- circuitBreaker.requestVolumeThreshold:默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。
- circuitBreaker.sleepWindowInMilliseconds:半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复
- circuitBreaker.errorThresholdPercentage:错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。
/**
*
* @param id
* @return
* circuitBreaker.enabled:是否开启断路器
* circuitBreaker.requestVolumeThreshold:默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。
* circuitBreaker.sleepWindowInMilliseconds:半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复
* circuitBreaker.errorThresholdPercentage:错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。
*/
@Override
@HystrixCommand(fallbackMethod = "paymentInfoTimeoutHandler" ,commandProperties = {
@HystrixProperty(name="circuitBreaker.enabled",value = "true"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
})
public String paymentInfoCircuitBreaker(Integer id) {
if(id<0){
throw new RuntimeException();
}
return "线程:"+Thread.currentThread().getName()+" 请求超过,id: "+id+" 哈哈哈";
}