hystrix是如何实现熔断降级的

本文介绍了如何利用feign和hystrix进行服务调用的熔断降级,详细解析了从@FeignClient注解配置,到HystrixInvocationHandler动态代理,再到HystrixCommand的run()和getFallback()方法,以及熔断器的工作机制,包括线程池和信号量的隔离策略,最后展示了整个执行流程图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章将介绍feign与hystrix结合来实现调用的同时进行熔断降级防止服务雪崩

使用feign的话自然少不了@FeignClient注解,而@FeignClient注解中除了最基本的name等属性之外,如果要整合hystrix一起使用的话,我们可能会用到fallbackFactory或者是fallback属性,所以一个@FeignClient注解看起来可能会是这样的

@FeignClient(name = "ServiceName",fallbackFactory = MyFallbackFactory.class)

fallbackFactory属性中可以填自己定义的fallbackFactory的类,你需要实现FallbackFactory接口,然后将熔断降级的逻辑自己来实现一下,看起来可能是这个样子的

public class MyFallbackFactory implements FallbackFactory<InterfaceName> {
    @Override
    public InterfaceName create(Throwable throwable) {
        return new InterfaceName() {
            @Override
            public String sayHello(Long id, String name, Integer age) {
                return null;
            }
        };
    }
}

feign实现声明式调用的关键就是通过了动态代理,请求会交给动态代理去处理,让我们使用起来就像使用接口调用一样简单

既然feign与hystrix整合的话,那么请求处理的逻辑肯定会有所变化,具体就体现在了feign的动态代理中,整合后的动态代理变为了另外一个,也就是hystrix相关的动态代理,我们来分析一下这里面做了哪些事情

已知的条件就是@FeignClient中提供的信息,包括了需要调用的服务名称,和fallbackFactory的实现,fallbackFactory中包含了接口中方法执行fallback降级的方法名称、参数、逻辑等信息,这些信息组合起来就会生成一个动态代理,叫做HystrixInvocationHandler

现在我们得到了hystrix的动态代理HystrixInvocationHandler,那么之后的接口调用就会通过HystrixInvocationHandler的invoke()方法了,在这里会通过一个setterMethodMap来构建一个HystrixCommand,这个那么这个setterMethodMap里面是些什么东西呢?

setterMethodMap一看就是一个map,在这里面key是method,也就是方法,里面包含了方法名称,参数,返回值类型等,value的话就要复杂一点,里面主要包含了groupKey和commandKey,groupKey可以认为是hystrix进行熔断降级的那个线程池,hystrix最多只会消耗完这个线程池的资源,而不会导致整个服务线程资源耗尽,默认的话groupKey其实就是服务名称,也就是@FeignClient注解中的name属性,而commandKey可以认为是服务对应的接口,默认值是接口名称 + 接口中的方法(参数类),举个例子,假如接口是greetingService,方法是hello(String name),那么commandKey就是greetingService#hello(String)

上面罗里吧嗦了一大堆,其实简单来说就是HystrixInvocationHandler中已经知道要调用的接口里面的方法信息,对于已知的流程我们来画个图
HystrixCommand
ok,现在我们已经得到了HystrixCommand,HystrixCommand里面有两个方法,一个是run(),一个是getFallback(),run()方法自然就是接口正常执行的逻辑,我们已经有了方法的各种信息,再加上调用接口的参数,接下来的事情就交给feign吧,feign会替我们完成后面一系列的工作,通过和ribbon整合完成负载均衡获取要发送的机器的信息,向那台机器构造http请求,发送请求并处理结果,这里就不再展开了

我们来看看getFallback()方法,这个方法会在HystrixCommand正常逻辑执行失败的时候触发,稍微分析一下里面的流程

首先会判断fallbackFactory是不是为null,如果为null的话就说明没有配置fallback的方法,那么执行失败的话就直接给你报错了,之后会调用fallbackFactory的create()方法,这个方法的具体实现其实就是我们上面说的@FeignClient注解中的fallbackFactory配置的类的create()方法,方法中传入一个参数就是抛出的异常,你可以根据不同的异常类型来做不同的处理

create()方法会返回一个fallback,这里面就包含了降级之后的具体处理逻辑了,接着就会根据具体的方法,配合里面的参数调用fallback中的降级逻辑来完成降级

看到这里你可能发现讲来讲去还是没有讲到hystrix的核心逻辑,别急,马上来了,HystrixInvocationHandler的invoke()方法的最后,会调用HystrixCommand的execute()方法,核心逻辑就在这个里面,我们来看看这里都做了些啥

public R execute() {
    try {
        return queue().get();
    } catch (Exception e) {
        throw Exceptions.sneakyThrow(decomposeException(e));
    }
}

核心就是queue().get()方法,这里的queue()返回的是一个Future

public Future<R> queue() {
    /*
    * The Future returned by Observable.toBlocking().toFuture() does not implement the
    * interruption of the execution thread when the "mayInterrupt" flag of Future.cancel(boolean) is set to true;
    * thus, to comply with the contract of Future, we must wrap around it.
    */
    final Future<R> delegate = toObservable().toBlocking().toFuture();
    
    // 省略代码,通过上面的注释,可以了解到这里的delegate其实不具备处理中断等异常原因的能力,所以对delegate进行了进一步封装
}

之后就不再贴源码了,因为hystrix的源码中大量使用了rxjava,里面各种Observable对象,调用来调用去,逻辑比较乱,我就直接说哪一步干了些什么

这里首先会去检查一下requestCacheEnabled,默认是不开启的,如果开启了request cache的话,那么就会去request cache中找一下是否存在我们需要的结果,存在的话则直接返回

之后有一个判断是circuitBreaker.attemptExecution(),circuitBreaker是什么?circuitBreaker就是熔断器,说白了就是一个开关,如果circuitBreaker打开了,那么就不会去执行正常的逻辑了,直接走fallback进行降级。所以这一步的意思就是尝试执行circuitBreaker,如果被熔断了的话,那么就直接去走降级的逻辑

熔断器放行的话,我们知道hystrix有两种隔离的策略,一种是基于线程池,还有一种是基于信号量,绝大多数情况下使用线程池就可以了,所以我们这里分析一下线程池的执行逻辑
线程池的话,可以创建线程执行任务,如果核心工作线程满了的话,就会将任务加入到队列中等待线程执行完成其他任务后再执行,hystrix的线程池默认情况下,队列是没有排队效果的,假如你有一个10个线程的线程池,那么当10个线程同时都在工作的话,新来的任务会直接走拒绝策略,当然你可以根据自己的需要自己通过参数自定义线程池,这里通过线程池和队列的大小来限制了资源,保证了资源不会被耗尽

接着会执行HystrixCommand中的run()方法来完成我们自己编写的逻辑

如果在运行上面步骤的时候出现了异常,比如说线程池满了、队列满了、请求超时了、请求报错了,都会由circuitBreaker监听到,那么如果在一个时间窗口内(默认10秒),请求总量大于20次,且异常比例大于50%的话,那么熔断器就会打开,之后的逻辑都会直接走fallback降级了

有一个参数,circuitBreakerSleepWindowInMilliseconds(默认5秒),在circuitBreaker打开之后经过5秒之后状态会由打开变为半开状态(OPEN -> HALF_OPEN),此时再次去尝试执行Command,执行成功的话就将circuitBreaker关闭,否则再次打开

来一个整个执行流程的图
hystrix运行流程
在我之前的文章有总结hystrix的运行流程,感兴趣的可以看这篇文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值