程序员社区

SpringCloud构建微服务之Hystrix熔断降级

前言

在前面呢我们有介绍什么是Hystrix,以及Hystrix的作用。那么本篇文章呢我们将结合代码,来演示如何利用Hystrix来现实服务的熔断降级

集成Hystrix

首先在spring-cloud-examples的基础上新建一个子module——spring-cloud-hystrix,然后在spring-cloud-hystrix的基础上再分别建立consumer-hystrixconsumer-feign-hystrix两个module
如图所示:
在这里插入图片描述
分别将spring-cloud-consumer-user-feignspring-cloud-consumer-user的代码、配置文件copy至刚刚新建的项目consumer-hystrixconsumer-feign-hystrix
修改consumer-hystrixpom文件,增加hystrix依赖:

<!--hystrix-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
 </dependency>

完整pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-hystrix</artifactId>
        <groupId>com.chaytech</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer-hystrix</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>com.chaytech</groupId>
            <artifactId>spring-cloud-model</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.chaytech</groupId>
            <artifactId>spring-cloud-api</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- ribbon相关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>

        <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>

        <!-- 修改后立即生效,热部署 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

    </dependencies>

</project>

修改consumer-hystrix中的UserController,增加一个方法上并在方法加上@HystrixCommand注解,标示此方法带容错机制。一旦调用服务方法失败,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法:

@GetMapping("/consumer/user/getUserHystrix/{id}")
    // 一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
    @HystrixCommand(fallbackMethod = "userHystrixFallback")
    public UserEntity getUserHystrix(@PathVariable("id") Integer id) {
        Logger.info("getUserHystrix thread name is {}", Thread.currentThread().getName());
        try{
            Thread.sleep(1500);
        }catch (Exception e){
        }
        return userApi.getUser(id);
    }

    /**
     * 熔断降级回退方法
     *
     * 注意此方法返回值和参数需与目标方式一致
     *
     * @param id
     * @return
     */
    private UserEntity userHystrixFallback(Integer id){
        UserEntity userEntity = new UserEntity("系统繁忙,请稍后再试!");
        return userEntity;
    }

完整UserController

@RestController
public class UserController {

    private Logger Logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserApi userApi;

    @PostMapping("/consumer/user/add")
    public boolean add(UserEntity user) {
        return userApi.createUser(user);
    }

    @GetMapping("/consumer/user/getUser/{id}")
    public UserEntity getUser(@PathVariable("id") Integer id) {
        Logger.info("getUser thread name is {}", Thread.currentThread().getName());
        try{
            Thread.sleep(1500);
        }catch (Exception e){
        }
        return userApi.getUser(id);
    }

    @GetMapping("/consumer/user/listUser")
    public List<UserEntity> list() {
        return userApi.listUser();
    }

    @GetMapping("/consumer/user/getUserHystrix/{id}")
    // 一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
    @HystrixCommand(fallbackMethod = "userHystrixFallback")
    public UserEntity getUserHystrix(@PathVariable("id") Integer id) {
        Logger.info("getUserHystrix thread name is {}", Thread.currentThread().getName());
        try{
            Thread.sleep(1500);
        }catch (Exception e){
        }
        return userApi.getUser(id);
    }

    /**
     * 熔断降级回退方法
     *
     * 注意此方法返回值和参数需与目标方式一致
     *
     * @param id
     * @return
     */
    private UserEntity userHystrixFallback(Integer id){
        UserEntity userEntity = new UserEntity("系统繁忙,请稍后再试!");
        return userEntity;
    }
}

修改consumer-hystrix启动类,增加@EnableHystrix注解来开启hysterix

@SpringBootApplication
// 本服务启动后会自动注册进eureka服务中
@EnableEurekaClient
@EnableFeignClients(basePackages ={"com.chaytech.**"} )
@ComponentScan(basePackages = {"com.chaytech.**"})
@EnableHystrix // 开启hysterix
public class UserConsumerHystrix80_Application {

    public static void main(String[] args) {
        SpringApplication.run(UserConsumerHystrix80_Application.class,args);
    }
}

下面我们来启动eureka集群、用户微服务spring-cloud-provider-user、消费者服务consumer-hystrix
在这里插入图片描述
进行测试:
请求:127.0.0.1:8080/consumer/user/getUser/1
在这里插入图片描述
可以看到正常返回数据了

请求:127.0.0.1:8080/consumer/user/getUserHystrix/1

在这里插入图片描述
返回了系统繁忙,请稍后再试!,这正是我们定义的服务出现故障后的userHystrixFallback方法返回的内容。
有些同学可能有些疑问,此时服务是正常的啊,为什么会返回这个呢?我们来看一下前面定义的getUserHystrix方法:

@GetMapping("/consumer/user/getUserHystrix/{id}")
    // 一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
    @HystrixCommand(fallbackMethod = "userHystrixFallback")
    public UserEntity getUserHystrix(@PathVariable("id") Integer id) {
        Logger.info("getUserHystrix thread name is {}", Thread.currentThread().getName());
        try{
            Thread.sleep(1500);
        }catch (Exception e){
        }
        return userApi.getUser(id);
    }

可以看到我在方法内部使当前线程休眠了1.5秒,Hystrix默认响应时间是1秒,超过1秒将会触发服务降级,这里我们让线程休眠了1.5秒,很显然超过了Hystrix默认的响应时间,因此Hystrix进行了降级返回。这里有一点需要注意,我们虽然进行了降级返回,但是方法还是会继续往下执行的,有兴趣的同学可自行测试
Hystrix支持禁用响应超时进行服务降级(不建议禁用,可以配置将超时时间配置长一点),配置如下:

hystrix:  
 command: 
   default: 
      execution: 
       timeout: 5000 # 超时时间设置
        enabled: false # 禁用服务超时进行服务降级

下面我们人为来模式服务故障,将spring-cloud-provider-user服务停掉后,再次访问:

请求:127.0.0.1:8080/consumer/user/getUser/1
在这里插入图片描述
可以看到getUser因为没有配置容错处理,直接返回了500,这种信息是不友好的。

请求:127.0.0.1:8080/consumer/user/getUserHystrix/1
在这里插入图片描述
getUserHystrix依旧返回了系统繁忙,请稍后再试!,进行了容错处理。

上面演示的是直接在目标方法上增加@HystrixCommand注解,进行容错处理。有些同学肯能会想到,那我如果有好多接口都需要进行容错处理,岂不是每个方法上都要加上这个注解,并且还要定义一个降级回掉方法,工作量太大了,有没有其它方法?
答案是:有的,下面我们来介绍另外一种服务容错处理方式。

修改spring-cloud-api项目,创建一个类UserFallBack去实现UserApi,注意UserFallBack要加上@Component注解,交给Spring容器管理,否则spring将识别不到:

@Component
public class UserFallBack implements UserApi {
    @Override
    public boolean createUser(UserEntity user) {
        return false;
    }

    @Override
    public UserEntity getUser(Integer id) {
        UserEntity userEntity = new UserEntity("系统繁忙,请稍后再试!");
        return userEntity;
    }

    @Override
    public List<UserEntity> listUser() {
        return null;
    }
}

UserFallBack类里的方法返回的内容,就是服务出现故障后,进行服务降级返回的内容,可以自行定义。

修改UserApi,将@FeignClient添加fallback属性,fallback指向的就是前面新建的UserFallBack

//@FeignClient(value = "USER-PROVIDER")
@FeignClient(value = "USER-PROVIDER", fallback = UserFallBack.class)
public interface UserApi {

    @PostMapping("/user/createUser")
    public boolean createUser(@RequestBody UserEntity user);

    @GetMapping("/user/getUser/{id}")
    public UserEntity getUser(@PathVariable("id") Integer id);

    @GetMapping("/user/listUser")
    public List<UserEntity> listUser();
}

因为feign已经集成了hystrix,默认是关闭的,我们只需修改consumer-feign-hystrixapplication.yml文件,开启hystrix即可:

# 开启hystrix
feign:
  hystrix:
    enabled: true

然后将spring-cloud-provider-userconsumer-feign-hystrix服务启动,如果consumer-feign-hystrix启动失败,则需要在启动类上加上@ComponentScan指定扫描的包:

@SpringBootApplication
// 本服务启动后会自动注册进eureka服务中
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.chaytech.**"})
@ComponentScan(basePackages = {"com.chaytech.**"})
public class UserConsumerFeignHystrix80_Application {

    public static void main(String[] args) {
        SpringApplication.run(UserConsumerFeignHystrix80_Application.class,args);
    }
}

请求:127.0.0.1:8080/consumer/user/getUser/1
在这里插入图片描述
可正常访问

spring-cloud-provider-user服务停掉,再次请求127.0.0.1:8080/consumer/user/getUser/1
在这里插入图片描述
此时因为我们将服务停掉无法通讯,从而进行了服务降级返回我们设置的指定信息。

@FeignClient除了可以使用fallback指定服务降级处理,还可以使用fallbackFactory来指定:

@Component
public class UserFallBackFactory implements FallbackFactory<UserApi> {
    @Override
    public UserApi create(Throwable throwable) {
        return new UserApi() {
            @Override
            public boolean createUser(UserEntity user) {
                return false;
            }

            @Override
            public UserEntity getUser(Integer id) {
                UserEntity userEntity = new UserEntity("系统繁忙,请稍后再试!");
                return userEntity;
            }

            @Override
            public List<UserEntity> listUser() {
                return null;
            }
        };
    }
}
//@FeignClient(value = "USER-PROVIDER")
//@FeignClient(value = "USER-PROVIDER", fallback = UserFallBack.class)
@FeignClient(value = "USER-PROVIDER", fallbackFactory = UserFallBackFactory.class)
public interface UserApi {

    @PostMapping("/user/createUser")
    public boolean createUser(@RequestBody UserEntity user);

    @GetMapping("/user/getUser/{id}")
    public UserEntity getUser(@PathVariable("id") Integer id);

    @GetMapping("/user/listUser")
    public List<UserEntity> listUser();
}

此处就不再演示效果了,可自行测试。

总结

本次我们演示了如何利用hystrix实现了几种不同的服务降级处理。有些同学可能会有疑问,标题说了熔断和降级啊,全文都在讲降级,熔断哪去了?此处告诉你答案:熔断和降级是配合使用的,hystrix默认是开启熔断的,@EnableHystrix注解点进去可以看到@EnableCircuitBreaker注解,此注解就是用来开启熔断的。熔断后的处理就是我们指定的fallback或者fallbackFactory

赞(0) 打赏
未经允许不得转载:IDEA激活码 » SpringCloud构建微服务之Hystrix熔断降级

一个分享Java & Python知识的社区