通过Hystrix理解熔断和降级

刚开始参加工作的时候,看公司的SOA框架描述什么降级和熔断,当时我百脸懵逼,什么鬼。就写几个代码,还要熔断和降级,难道在代码中安装了保险丝,代码执行着突然不爽还要降一级吗,有病吧!笑哭了!

曾几何时欠下的技术债终于要还了,最近项目中使用到了Netflix公司的开源组件Hystrix,于是研究了一下,对降级和熔断有些理解了。

下面通过Hystrix的两个例子来理解降级和熔断,更多关于Hystrix的内容,大家Google去吧。

降级(fallback)
MorningService.java

public class MorningService {

    /**
     * 超时
     */
    public void timeout() {
        int j = 0;
        while (true) {
            j++;
        }
    }

}


HystrixFallbackTest.java

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import org.junit.Test;

import java.io.IOException;

public class HystrixFallbackTest extends HystrixCommand<String> {

    private final String name;

    private MorningService morningService;

    public HystrixFallbackTest(String name, MorningService morningService) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("FallbackGroup"))
        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(10000)));  // 10秒超时哦
        this.name = name;
        this.morningService = morningService;
    }

    @Override
    protected String run() throws Exception {
        /**
         * 超时触发fallback
         */
        morningService.timeout();
        return name;
    }

    /**
     * Hystrix的降级方法
     * @return
     */
    @Override
    protected String getFallback() {
        return "fallback: " + name;
    }

    public static class UnitTest {

        @Test
        public void testFallback() throws IOException {
            System.out.println(new HystrixFallbackTest("Morning", new MorningService()).execute());
        }
    }
}


执行上面的Test方法,在run方法里正常执行超过10秒就timeout了,走降级方法fallbck(),打印出的内容是:

fallback: Morning
1
降级就是在执行主流程时,主流程突然出现意外执行不下去了,那就执行另外一个方法让主流程看起来是正常的(这个方法通常就是降级方法,似乎有些牵强)。

熔断(circuit breaker)
保险丝:电路中正确安置保险丝,保险丝就会在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,保护了电路安全运行。(来自百度百科)

熔断就跟保险丝一样,当一个服务请求并发特别大,服务器已经招架不住了,调用错误率飙升,当错误率达到一定阈值后,就将这个服务熔断了。熔断之后,后续的请求就不会再请求服务器了,以减缓服务器的压力。

来一个栗子吧: 
HystrixCircuitBreakerTest.java

import com.netflix.hystrix.*;
import org.junit.Test;

import java.io.IOException;

public class HystrixCircuitBreakerTest extends HystrixCommand<String> {

    private final String name;

    private MorningService morningService;

    public HystrixCircuitBreakerTest(String name, MorningService morningService) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("CircuitBreakerTestGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("CircuitBreakerTestKey"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("CircuitBreakerTest"))
                .andThreadPoolPropertiesDefaults(   // 配置线程池
                        HystrixThreadPoolProperties.Setter()
                        .withCoreSize(200)  // 配置线程池里的线程数,设置足够多线程,以防未熔断却打满threadpool
                )
                .andCommandPropertiesDefaults(  // 配置熔断器
                        HystrixCommandProperties.Setter()
                        .withCircuitBreakerEnabled(true)  //  熔断器在整个统计时间内是否开启的阀值
                        .withCircuitBreakerRequestVolumeThreshold(3)    // 至少有3个请求才进行熔断错误比率计算
                        .withCircuitBreakerErrorThresholdPercentage(50)   //当出错率超过50%后熔断器启动
                                .withMetricsRollingStatisticalWindowInMilliseconds(5000)   // 统计滚动的时间窗口
                        .withCircuitBreakerSleepWindowInMilliseconds(2000)   // 熔断器工作时间,超过这个时间,先放一个请求进去,成功的话就关闭熔断,失败就再等一段时间
                )
        );
        this.name = name;
        this.morningService = morningService;
    }

    @Override
    protected String run() throws Exception {
        int num = Integer.valueOf(name);
        if(num % 2 == 0) {  // 直接返回
            return name;
        } else {
            morningService.timeout(); // 无限循环模拟超时
        }
        return name;
    }


    /**
     * Whether or not your command has a fallback,
     * all of the usual Hystrix state and circuit-breaker state/metrics are updated to indicate the command failure.
     */
    @Override
    protected String getFallback() {
        return "CircuitBreaker fallback: " + name;
    }

    public static class UnitTest {

        @Test
        public void testSynchronous() throws IOException {
            for(int i = 0; i < 50000; i++) {
                try {
                    System.out.println("===========" + new HystrixCircuitBreakerTest(String.valueOf(i), new MorningService()).execute());
                    // 查看熔断器是否打开
                    System.out.println("if circuit breaker open: " + HystrixCircuitBreaker.Factory.getInstance(HystrixCommandKey.Factory.asKey("CircuitBreakerTestKey")).isOpen());
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


来看执行结果: 
1. 降级 

image.png
 
超时的请求走fallback,熔断器还没有打开。 
2. 熔断 

image.pngimage.png
 
熔断器打开了,后续请求直接走降级方法fallback,不再调用主流程方法。 
3. 尝试恢复 

image.png
 
过了熔断器工作的时间窗以后,尝试放一个请求进去,执行成功就关闭熔断器,失败则继续打开,如此往复循环进行工作。

熔断器模式,参考CircuitBreaker, 
还有美团精华文章服务容错模式

最后,我想说熔断降级确实没毛病!哈哈! 
解决问题的模式是相通的,关键还是要多思考
--------------------- 
作者:jiaobuchong 
来源:CSDN 
原文:https://blog.csdn.net/jiaobuchong/article/details/78232920 
版权声明:本文为博主原创文章,转载请附上博文链接!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值