如何使用Hystrix实现服务降级?

标签: Java

保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/128/ )。

概述

降级就是说在调用某个方法发生超时、异常等错误时,改为调用备用方法,并使用备用方法的结果来替代原方法的操作。例如原方法是请求Redis中的数据,但因为Redis宕机,导致请求发生异常,则此时可以调用备用方法通过查询数据库给出结果。

环境配置

通过Hystrix就可以方便地实现这一操作。接下来,我们给出简单的示例。

首先,准备SpringBoot项目,然后在其中引入适用于SpringBoot的hystrix包:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

注意,如果这时候启动提示如下的错误,则基本是SpringBoot版本与hystrix版本不匹配导致的。因为hystrix是基于SpringCloud的,而SpringCloud和SpringBoot存在版本对应关系。如果对应不一致,则可能导致出现下面的错误。

java.lang.NoSuchMethodError: 'void org.springframework.boot.builder.SpringApplicationBuilder.<init>(java.lang.Object[])'

这里我们给出一个可用的对应版本,即SpringBoot的2.3.5.RELEASE和spring-cloud-starter-netflix-hystrix的2.2.7.RELEASE。它们这一对是肯定没有问题的。

然后,我们需要在SpringBoot的主类上增加@EnableHystrix注解,以启用Hystrix。如下所示。

@SpringBootApplication
@EnableHystrix
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

环境配置就是这么简单,接下来我们就可以写业务代码了。

功能实现

例如我们编写如下的方法,也就是原方法。在原方法中,我们故意让它一定概率抛出异常、一定概率发生延迟、一定概率成功。

@HystrixCommand(
        commandKey = "FallBackService_queryUserNameById",
        fallbackMethod = "queryDefaultUserName",
        commandProperties = {
                // 超时判定时间设置为30ms
                @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "30"),
        }
)
String queryUserNameById(int i) throws InterruptedException {
    System.out.print("正在查询用户名,用户编号为" + i);
    int randomValue = new Random().nextInt(100);
    if (randomValue <= 30) {
        // 约30%概率会触发异常
        System.out.println(" : 查询发生异常 ");
        throw new RuntimeException();
    } else if (randomValue <= 60) {
        // 约30%概率会触发超时
        System.out.println(" : 查询发生延迟 ");
        Thread.sleep(50);
        return "编号" + i +"的用户名查询超时";
    } else {
        // 约40%概率会正常执行
        System.out.println(" : 查询成功 ");
        return "易哥" + i;
    }
}

我们在原方法上增加@HystrixCommand注解。其中比较关键的是fallbackMethod参数,我们指向了该原方法对应的备用方法,即当原方法发生错误时要调用的方法。然后我们编写备用方法。

String queryDefaultUserName(int i) {
    System.out.println("生成默认用户名,用户编号为" + i);
    return "平台用户" + i;
}

注意,这里的备用方法要和原方法有相同的入参、返回值。这一点也好理解,毕竟备用方法是要在某些时候替换原方法的,入参、返回值不一样那就没法替换了。

然后,我们调用10次原方法,则在控制台看到如下的输出(因异常和延迟为随机发生,故每次调用的结果不一定完全一致):

正在查询用户名,用户编号为1 : 查询发生延迟 
生成默认用户名,用户编号为1
正在查询用户名,用户编号为2 : 查询发生延迟 
生成默认用户名,用户编号为2
正在查询用户名,用户编号为3 : 查询发生异常 
生成默认用户名,用户编号为3
正在查询用户名,用户编号为4 : 查询发生延迟 
生成默认用户名,用户编号为4
正在查询用户名,用户编号为5 : 查询发生延迟 
生成默认用户名,用户编号为5
正在查询用户名,用户编号为6 : 查询发生延迟 
生成默认用户名,用户编号为6
正在查询用户名,用户编号为7 : 查询发生异常 
生成默认用户名,用户编号为7
正在查询用户名,用户编号为8 : 查询成功 
正在查询用户名,用户编号为9 : 查询发生异常 
生成默认用户名,用户编号为9
正在查询用户名,用户编号为10 : 查询成功 

这表明只要原方法发生延迟或者异常,备用方法都会被触发。在最终的返回值中,我们可以看到如下的结果。

平台用户1
平台用户2
平台用户3
平台用户4
平台用户5
平台用户6
平台用户7
易哥8
平台用户9
易哥10

可见,当原方法发生延迟或者异常时,备用方法的结果会被返回给调用方。

通过该示例,我们就演示了Hystrix的降级功能。

参数详解

以上实现的是最简单的降级示例,也仅仅使用了最简单的参数,而其他参数都是用的默认值。但是这个作为示例是可以的,真正使用时,大家还是要对Hystrix的各个参数有详细的了解,至少也要知道大体的含义和默认值。否则,后续使用中,可能会遇到不少百思不得其解的地方。例如,Hystrix的熔断器就是默认开启的,要是不知道这点,估计到时候出现一些调用结果会很疑惑。

总之,Hystrix要比这个强大的多。大家还是要好好学一下。

下面是我对@HystrixCommand参数的介绍,主要是摘抄参考了《高性能架构之道(第二版)》这本书。上面的示例也是参考的书里的。下面的参数我这里列的不是很全,如果要细致学习的话,十分建议大家去看下这本书。

好了,以上就是Hystrix实现降级的简单示例。

可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。

作者书籍推荐