【Spring Cloud总结】17.Hystrix简介及简单代码示例

接上篇《16.超时机制,断路器模式简介》  Spring Cloud版本为Finchley.SR2版

上一篇我们介绍了超时机制以及断路器模式,并且引申出了Spring Cloud的断路器组件Hystrix。本篇我们来学习Hystrix的基础知识。
本部分官方文档:https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html#_circuit_breaker_hystrix_clients

一、Hystrix断路器简介

Hystrix的读音是 [hIst'rIks](嗨斯捶克斯~哈哈哈),在英文里面是豪猪的意思,大概是下面这个:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第1张图片
豪猪身上有很多刺,这些刺可以很好的保护自己,所以开发团队给这个保护组件起名为Hystrix。

首先我们来看一下Spring Cloud官方文档对Hystrix的介绍:
Netflix创建了一个名为Hystrix的库,实现了断路(熔断)器的模式。一般在微服务架构通常有多层服务调用:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第2张图片

“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝,这里默认服务5秒失败20次就认为服务异常),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩的发生:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第3张图片

拥有一个断路器可以停止级联故障,并且给予失败的服务有自我恢复的时间。回退机制中的备选响应(FallBack)可以是另外一个服务,或者是一个静态数据,当然也可以是一个空值。

二、引入并使用Hystrix

我们需要引入Hystrix组件的话,在pom文件中添加spring-cloud-starter-netflix-hystrix的依赖即可:


    org.springframework.cloud
    spring-cloud-starter-netflix-hystrix

然后在启动类上添加@EnableCircuitBreaker注解,引入断路器:

@SpringBootApplication
@EnableCircuitBreaker
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

然后在需要使用断路器进行备选响应的服务上,添加@HystrixCommand注解,并指定服务异常之后回退的具体方法(fallbackMethod):

@Component
public class StoreIntegration {

    @HystrixCommand(fallbackMethod = "defaultStores")
    public Object getStores(Map parameters) {
        //do stuff that might fail
    }

    public Object defaultStores(Map parameters) {
        return /* something useful */;
    }
}

当调用getStores服务异常的时候,就会自动进行服务降级,调用“fallbackMethod”参数指定的回退方法。
上面例子看起来还是比较简单的,而实际上Hystrix的使用也是这么方便的。那么为什么引入@HystrixCommand就能实现断路器模式呢?
首先我们要知道,@HystrixCommand是由名为“javanica”的Netflix contrib 库提供,什么是“javanica”呢?
javanica是Netflix contrib下的一个子项目,其在github上的仓库地址为:
https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica
我们可以在其github首页的README.md公告中了解到,javanica工程实现了一个HystrixCommandAspect切面类,使用AOP切面机制,处理请求服务的前置和后置逻辑:


        ...
        
        ...

然后就可以直接使用@HystrixCommand进行服务的直接访问了:

public class UserService {
...
    @HystrixCommand
    public User getUserById(String id) {
        return userResource.getUserById(id);
    }
}
...

那么,说到底,@HystrixCommand其实并不是Hystrix的原生注解(其在com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand包下),而是“javanica”项目对原来的Hystrix进行了改进和封装,使开发者更方便的使用Hystrix。

我们可以直接去Hystrix的github首页,然后在其wiki上(https://github.com/Netflix/Hystrix/wiki/How-To-Use)看看原始的Hystrix是如何使用的:
继承HystrixCommand类,实现run方法,getFallback回退方法:

public class CommandHelloWorld extends HystrixCommand {
 
    private final String name;
 
    public CommandHelloWorld(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.name = name;
    }
 
    @Override
    protected String run() {
        // a real example would do work like a network call here
        return "Hello " + name + "!";
    }
    
    @Override
    protected String getFallback() {
        return "Hello Failure " + name + "!";
    }
}

或者是继承HystrixObservableCommand类,实现construct方法,resumeWithFallback回退方法:

public class CommandHelloWorld extends HystrixObservableCommand {
 
    private final String name;
 
    public CommandHelloWorld(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.name = name;
    }
 
    @Override
    protected Observable construct() {
        return Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscriber observer) {
                try {
                    if (!observer.isUnsubscribed()) {
                        // a real example would do work like a network call here
                        observer.onNext("Hello");
                        observer.onNext(name + "!");
                        observer.onCompleted();
                    }
                } catch (Exception e) {
                    observer.onError(e);
                }
            }
         } ).subscribeOn(Schedulers.io());
    }
    
    /**
     * fallback方法的写法,覆写resumeWithFallback方法
     * 当调用出现异常时,会调用该降级方法
     */
    @Override
    public Observable resumeWithFallback() {
        return Observable.create(new OnSubscribe() {
            @Override
            public void call(Subscriber observer) {
                try {
                    if (!observer.isUnsubscribed()) {
                        observer.onNext("Hello Failure");
                        observer.onNext(name + "!");
                        observer.onCompleted();
                    }
                } catch (Exception e) {
                    observer.onError(e);
                }
            }
        }).subscribeOn(Schedulers.io());
    }
}

调用的时候调用execute方法即可:

String s = new CommandHelloWorld("World").execute();

也可以使用queue方法异步执行,使用Future类获取相关结果:

Future fs = new CommandHelloWorld("World").queue();
String s = fs.get();

我们要感谢“javanica”项目然我们如此方便的使用Hystrix。

要配置@Hystrixcommand注解,可以使用其commandproperties属性。有关commandproperties属性的相关知识我们后面会详细介绍。

三、实例测试

我们在之前的microserver-consumer-movie工程上进行Hystrix的测试。首先在其pom.xml文件中添加Hystrix的依赖:


    org.springframework.cloud
    spring-cloud-starter-netflix-hystrix

然后在启动类MicroserverSimpleConsumerMovieApplication类添加@EnableCircuitBreaker注解:

package com.microserver.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import com.microserver.config.TestConfiguration;

@SpringBootApplication
@EnableCircuitBreaker
@EnableFeignClients
@RibbonClient(name = "microserver-provider-user",configuration=TestConfiguration.class )
public class MicroserverSimpleConsumerMovieApplication {
    public static void main(String[] args) {
        SpringApplication.run(MicroserverSimpleConsumerMovieApplication.class, args);
    }
}

我们还记得之前在MovieController中编写了“/movie/{id}”的服务,方法为findUserById,

@RestController
public class MovieController {

    //上面代码省略...
    
    @Autowired
    private UserFeignClient userFeignClient;
    
    @GetMapping("/movie/{id}")
    public User findUserById(@PathVariable Long id){
        return userFeignClient.findById(id);
    }
    
    //下面代码省略...
}

我们准备对这个服务进行异常断路和降级的操作。首先给findUserById方法添加@Hystrixcommand注解,并且配置其服务降级退回方法为“findUserByIdFallback”:

@RestController
public class MovieController {

    //上面代码省略...
    
    @Autowired
    private UserFeignClient userFeignClient;
    
    @GetMapping("/movie/{id}")
    @HystrixCommand(fallbackMethod = "findUserByIdFallback")
    public User findUserById(@PathVariable Long id){
        return userFeignClient.findById(id);
    }
    
    public User findUserByIdFallback(){
        User user = new User();
        user.setId(0L);
        return user;
    }
    
    //下面代码省略...
}

fallbackMethod对应的方法,其中的参数和返回值一定要和原来的服务相同。
然后重启movie工程、user工程以及eureka Server工程:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第4张图片
在eureka Server首页可以看到两个工程都是UP状态:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第5张图片

此时我们通过movie工程的“movie/{id}”服务来获取用户信息,请求id为1的用户信息:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第6张图片
可以看到此时反馈是正常的。这里要注意的是,我们首次访问的时候有可能会进降级方法,这是因为Hystrix默认的服务超时时间是1秒,这个时间太短了,对响应时间稍微长一点,或者网络速度稍微差一点的服务是不友好的。所以我们要在配置文件application.yml添加Hystrix的服务超时时间:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000

这里我们设置默认的服务超时时间为5秒(5000毫秒)。

下面我们模拟服务崩溃的情况,我们将user服务停止,这样movie去请求user的时候会失败的:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第7张图片
此时我们重新请求“movie/{id}”服务,可以看到返回的正是我们的降级服务findUserByIdFallback返回的Id为0的数据:
【Spring Cloud总结】17.Hystrix简介及简单代码示例_第8张图片
我们也可以观察到,浏览器在请求时也没有加载的迹象,我们打断点的时候,可以看到此时服务会在进入findUserById后,直接进findUserByIdFallback方法,而不会再去尝试请求原有服务。

一个简单的配置和演示就到这里,后面的博文会对Hystrix进行进一步的剖析。

参考:《51CTO学院Spring Cloud高级视频》
https://blog.csdn.net/syc000666/article/details/96097567
https://blog.csdn.net/zjl_pcw/article/details/87175077

转载请注明出处:https://blog.csdn.net/acmman/article/details/100523411

你可能感兴趣的:(Spring,Cloud,Spring,Cloud全面入门学习,@Hystrixcommand,Hystrix,Fallback,服务降级)