category
学习思考
date
Jul 24, 2022
icon
Origin
password
slug
hystrixFrame
status
Published
summary
关于hystrix框架的一些理解
tags
Tags
type
Post

概述:

分布式面临的问题:

复杂分布式体系结构中的应用有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败。

服务雪崩:

多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用相应时间过长或者不可用,对微服务A的调用就会占越来越多的系统资源,今儿引起系统崩溃,所谓“雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便的单个依赖关系的失败,不能取消整个应用程序或系统。
所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。

Hystrix :

是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等、Hystrix能够保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
 
“断路器” 本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(蕾丝熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延、乃至雪崩。

Hystrix能做什么:

服务降级、服务熔断、接近实时的监控
官网:https://github.com/Netflix/Hystrix/wiki/How-To-Use

服务降级:

服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback
降级的原因:程序异常、超时、服务熔断出发服务降级、线程池/信号量打满也会导致服务降级。

服务熔断:

类比保险丝,达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

服务限流:

秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟 N 个,有序进行。

解决的要求:

超时导致服务器变慢(转圈):

超时不在等待

出错(宕机或者程序运行出错):

出错要有兜底

解决:

对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级
对方服务(8001)宕机了,调用者(80)不能一直卡死等待,必须有服务降级
对方服务(8001)OK,调用者(80)自己出故障或者有自我要求

服务降级:

降级配置:

用注解的方法替代编码,也可以用继承类的方式。

服务端提供端(8001):

设置自身调用时间的峰值,峰值内可以正常运行。超过了,需要有兜底方法处理,作为服务降级fallback
业务类启用:
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000") })
主启动类激活:@EnableCircuitBreaker
程序报错或者超时兜底方案都是:
public String paymentInfo_TimeoutHandler(Integer id){ return "线程池:" + Thread.currentThread().getName() + "系统繁忙或运行报错,id:" + id + "\t" + "😣"; }
paymentInfo_TimeoutHandler对应注解中fallbackMethod

客户端(80):

一般降级写在客户端
客户端yml文件增加配置:
feign: hystrix: enabled: true
启动类增加:@EnableHystrix
业务层:
@HystrixCommand(fallbackMethod = "paymentInfoTimeoutFallbackMethod",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500") })
public String paymentInfoTimeoutFallbackMethod(){ return "我是消费者80,对方支付系统繁忙请10秒后再试或自己运行错误检查自己,💔"; }
 

目前问题:

每个业务方法对应一个兜底方法,代码膨胀
统一和定义的分开,代码耦合度高

解决方法:

1 :1 每个方法对应一个服务降级方法,技术上可行,但是很傻
1:n 除了个别重要核心业务有专属,其他普通的可以通过统一跳转到统一处理结果页面
代码层面:
controller层增加@DefaultProperties(defaultFallback = "payment_Global_fallbackMethod") 注解
新增全局fallback方法:
public String payment_Global_fallbackMethod(){ return "Global信息处理请稍后再试😁"; }
关于解耦:
只需要在feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦。
我们要面对的常见异常:运行、超时、宕机
新建类去实现feign的调用接口,代码如下:
@Component public class PaymentFallbackService implements PaymentHystrixService{ @Override public String paymentInfo_OK(Integer id) { return "--------PaymentFallbackService fall back ---paymentInfo_OK 😂"; } @Override public String paymentInfo_Timeout(Integer id) { return "--------PaymentFallbackService fall back ---paymentInfo_Timeout 😭"; } }
在原有接口新增属性:@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
fallback属性对应新增类

服务熔断:

熔断是什么:

熔断机制时应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长是,回进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,恢复调用链路。
在Springcloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是
@HystrixCommand
服务降级→ 进而熔断→ 恢复调用链路
按着这个思路,我们可以在controller层做如下测试:
@GetMapping("/payment/circuit/{id}") public String paymentCircuitBreaker(@PathVariable("id") Integer id ){ String result = paymentService.paymentCircuitBreaker(id); log.info("*******result" + result); return result; }
在service层做如下更改:
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",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 paymentCircuitBreaker(@PathVariable("id") Integer id){ if(id < 0){ throw new RuntimeException("********id不能负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName() + "\t"+"调用成功,流水号:" + serialNumber; } public String paymentCircuitBreaker_fallback(@PathVariable("id")Integer id){ return "id 不能负数,请稍后再试,id" + id; }
我们通过浏览器访问接口:
notion image
上面这是正常访问的情况
notion image
接下来测试错误情况,随后我们多次连续输入错误的id值
然后在输入正确的id,我们会发现:
notion image
正确的也无法访问,需要过一段时间才可以访问。
测试成功。

总结:

断路器在什么情况下会起作用:

涉及到断路器的三个重要参数:快照时间窗请求总数阀值错误百分比阀值
快照时间窗:断路器是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认最近的10s
请求总数阀值:在快照时间窗内,必须满足总数阀值才有资格熔断。默认20,意味着在10s内,如果Hystrix的调用命令不足20次,即使所有请求都超时或者因其他原因失败,断路器都不会打开。
错误百分比阀值:当总请求数在快照时间内超过了阈值,比如发生30次调用,如果在这30次调用中,有15次发生了异常,也就是50%的错误概率。在设置默认50%的情况下,这时候会将断路器打开。

过程:

总请求满足一定的阈值,错误请求满足一定的阈值,满足以上条件后断路器将会开启,这个时候,所有的请求都不会被转发,一段时间后(默认是5s),断路器改为半开状态,会让其中一个请求进行转发,如果成功,断路器关闭,若失败,继续开启,重复上述步骤。
再有请求调用的时候,将不会调用主逻辑,会直接调用降级fallback方法。通过断路器,实现自发的发现错误,并将降级逻辑切换为主逻辑,减少响应延迟的效果。
Hystrix提供了链路恢复功能。
 
 
服务网关-GATEWAY负载均衡算法

  • Twikoo
  • Giscus