美文网首页微服务架构和实践
断路器hystrix原理及使用

断路器hystrix原理及使用

作者: billJiang | 来源:发表于2017-08-28 13:04 被阅读0次
    hystrix原理图.png

    原理

    在微服务架构中,服务之间形成调用链路,链路中的任何一个服务提供者都可能面临着相应超时、宕机等不可用的情况,在高并发的情况下,这种情况会随着并发量的上升恶化,形成“雪崩效应”,而断路器hystrix正是用来解决这一个问题的组件。

    断路器基本原理为:

    • 正常情况下,断路器关闭,服务消费者正常请求微服务
    • 一段事件内,失败率达到一定阈值(比如50%失败,或者失败了50次),断路器将断开,此时不再请求服务提供者,而是只是快速失败的方法(断路方法)
    • 断路器打开一段时间,自动进入“半开”状态,此时,断路器可允许一个请求方法服务提供者,如果请求调用成功,则关闭断路器,否则继续保持断路器打开状态。

    断路器hystrix是保证了局部发生的错误,不会扩展到整个系统,从而保证系统的即使出现局部问题也不会造成系统雪崩。

    本文示例代码:helloworld+helloworldfeign+hello+world

    主要见springcloud-demo下hello/world/helloworld/helloworldfeign项目。

    配置/使用

    下面讲解在restTemplate和feign中断路器的配置和使用步骤

    restTemplate+ribbon整合Hystrix

    • 引入hystrix依赖
      <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
       </dependency>
    

    虽然Eureka依赖了ribbon,ribbon依赖了hystrix-core,但还是要引用了上面的maven依赖,因为下面用到的@HystrixCommand注解用到了hystrix-javanica包

    • 启动类加上@EnableCircuitBreaker注解(@EnableHystrix也可以)
    • 修改HelloWorldController的入口请求方法
    @GetMapping("/message")
        @HystrixCommand(fallbackMethod = "getMessageFallback")
        public HelloworldMessage getMessage() {
            HelloMessage hello = getMessageFromHelloService();
            WorldMessage world = getMessageFromWorldService();
            HelloworldMessage helloworld = new HelloworldMessage();
            helloworld.setHello(hello);
            helloworld.setWord(world);
            log.debug("Result helloworld message:{}", helloworld);
            return helloworld;
        }
    
        /**
         * 断路方法
         * @return
         */
        public HelloworldMessage getMessageFallback(){
           HelloMessage helloMessage=new HelloMessage();
           helloMessage.setName("hello");
           helloMessage.setMessage("error occurs");
    
           WorldMessage worldMessage=new WorldMessage();
           worldMessage.setMessage("world error occurs");
           HelloworldMessage helloworldMessage=new HelloworldMessage();
           helloworldMessage.setHello(helloMessage);
           helloworldMessage.setWord(worldMessage);
           return helloworldMessage;
        }
    

    通过@HystrixCommand注解的fallbackMethod指向断路方法,该方法会在调用hello服务或者world服务失败时被调用。
    @HystrixCommand 注解还可以配置超时事件等其他属性。

    • 测试

    1)依次启动eureka server:discovery/trace/hello/world/helloword项目
    2)在浏览器输入地址http:\\localhost:8020/message,则返回正确的结果
    3)停止hello项目,再次输入上述地址,则执行断路器中的方法。

    feign下整合Hystrix

    • feign禁用Hystrix
      在Spring Cloud中,只要Hystrix在项目的classpath中,Feign就会用断路器包裹Feign客户端的所有方法,如果要禁用Hystrix则可以通过自定义feign的配置来解决。
    @Configuration
    public class FeignConfiguration{
         @Bean
         @Scope("prototype")
         public Feign Builder feignBuilder(){
               return Feign.builder();
         }
    }
    

    要禁用Hystrix的接口引用该配置即可

    @FeignClient(name="hello",configuration=FeignConfiguration.class)
    public interface HelloService{
        ......
    }
    

    feign使用Hystrix

    • 启用Hystrix
      默认情况下feign已经整合了Hystrix,在配置文件中开启即可(本人用的的Dalston.SR2版本的Spring Cloud,需要在配置文件开启)
    feign:
      hystrix:
        enabled: true
    
    • 接口指定回退类
      在HelloService中修改FeignClient类,指定fallback的类
    package com.example.helloworldfeign.service;
    
    import com.example.helloworldfeign.model.HelloMessage;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    
    /**
     * @author billjiang 475572229@qq.com
     * @create 17-8-23
     */
    @FeignClient(value="hello",fallback = HelloServiceFallback.class)
    public interface HelloService {
    
        @GetMapping("/message")
        HelloMessage hello();
    
    
    }
    
    

    实现了接口fallback的类的实现:

    package com.example.helloworldfeign.service;
    
    import com.example.helloworldfeign.model.HelloMessage;
    import org.springframework.stereotype.Component;
    
    /**
     * @author billjiang 475572229@qq.com
     * @create 17-8-28
     */
    @Component
    public class HelloServiceFallback implements HelloService {
        @Override
        public HelloMessage hello() {
            HelloMessage helloMessage=new HelloMessage();
            helloMessage.setName("hello");
            helloMessage.setMessage("error occurs");
            return helloMessage;
        }
    }
    
    

    world项目同上

    • 测试

    1)依次启动eureka server:discovery/trace/hello/world/helloword-feing项目
    2)在浏览器输入地址http:\\localhost:8030/message,则返回正确的结果
    3)停止hello项目,再次输入上述地址,则执行断路器中的方法。

    查看断路器错误日志
    如果要查看详细的断路器的日志,可以通过注解@FeignClient的fallbackFactory来实现,如下代码所示:

    
    import com.example.helloworldfeign.model.HelloMessage;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    
    /**
     * @author billjiang 475572229@qq.com
     * @create 17-8-23
     */
    @FeignClient(value="hello",fallbackFactory = HelloServiceFallbackFactory.class)
    public interface HelloService {
    
        @GetMapping("/message")
        HelloMessage hello();
    
    
    }
    
    

    HelloServiceFallbackFactory类:

    package com.example.helloworldfeign.service;
    
    import com.example.helloworldfeign.model.HelloMessage;
    import feign.hystrix.FallbackFactory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * @author billjiang 475572229@qq.com
     * @create 17-8-28
     */
    @Component
    public class HelloServiceFallbackFactory implements FallbackFactory<HelloService> {
        private final static Logger LOGGER= LoggerFactory.getLogger(HelloServiceFallbackFactory.class);
        @Override
        public HelloService create(Throwable throwable) {
            return new HelloService() {
                @Override
                public HelloMessage hello() {
                    //print the error
                    LOGGER.error("fallback ,the result is:",throwable);
                    HelloMessage helloMessage=new HelloMessage();
                    helloMessage.setName("hello");
                    helloMessage.setMessage("error occurs");
                    return helloMessage;
                }
            };
        }
    }
    
    

    这样会在控制台把具体导致熔断的信息输出,以便跟踪错误。

    相关文章

      网友评论

        本文标题:断路器hystrix原理及使用

        本文链接:https://www.haomeiwen.com/subject/uuwwdxtx.html