美文网首页
SpringCloud微服务架构-使用Hystrix实现微服务的

SpringCloud微服务架构-使用Hystrix实现微服务的

作者: breezedancer | 来源:发表于2017-10-21 10:04 被阅读564次

    继续我们 SpringCloud 之旅,签名谈及到了 Eureka实现服务注册与发现,有使用 Ribbon 实现负责均衡,使用 Feign 实现声明式 API 调用,接下来我们的处理下容错问题了。

    Hystrix 介绍

    Hystrixs 是Netflix 实现的一个开源延迟和容错库,我们发现一个请求出现问题的时候,需要能够自动处理这个错误,避免错误的扩展,比如 A 服务依赖 B,B 又依赖 C,如果此时 C 发生错误,首先影响到 B,B 又影响到 A,这样的雪崩效应最终导致整个系统故障。

    Hystrix 通过如下几点实现:

    • [x] 包裹请求
    • [x] 跳闸机制
    • [x] 资源隔离
    • [x] 监控
    • [x] 回退机制
    • [x] 自我修复

    集成 Hystrix

    首先在 movie 的 pom 里面增加依赖

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

    其次在启动类上增加@EnableCircuitBreaker和@EnableHystrix,为项目启用断路器支持

    再次在 control 里面修改对应的方法,使得某个方法不能正常使用的时候,使用默认返回值。

        @GetMapping("/user/{id}")
        @HystrixCommand(fallbackMethod="findByUserIdFallback")
        public User findByUserId(@PathVariable Integer id){
            return restTemplate.getForObject("http://MS-SIMPLE-PROVIDER-USER/user/find?id="+id, User.class);
            //return userFeignClient.findById(id);
        }
        
        //这个方法是上面的方法发生错误的时候调用
        public User findByUserIdFallback(Integer id){
            User user=new User();
            user.setId(0);
            user.setName("NULL");
            user.setNickName("默认用户");
            user.setPassword("");
            user.setLastLoginDt(null);
            return user;
        }
    

    在原先的方法上增加@HystrixCommand(fallbackMethod="findByUserIdFallback"),使得错误发生的时候能够调用下面的回调方法,回调方法参数与上面的一模一样。
    @HystrixCommand该注解的里面参数非常多,需要的时候可以查阅文档,包括超时多久进行回调,线程池配置参数等。

    以上是一个基本的演示配置,接下来我们先运行试试看,开启 eureka,开启 user,开启 movie,在浏览器浏览 http://localhost:8010/user/1 返回的就是 我们默认的用户信息,因为之前的user模块需要用户密码访问,我们这里面直接访问是不行的。


    如果发现
    com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect]: Factory method 'hystrixCommandAspect' threw exception; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/JoinPoint
    

    需要增加

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.6</version>
            </dependency>
    

    Feign 使用 Hystrix

    上面的例子没有使用 Feign 的,现在我们来用 Feign 使用 Hystrix。不废话,直接来干货吧。
    因为 feign 是接口,我们需要在接口做一些动作。

    首先使用之前的 FeignClient 接口方式来,对项目进行修正下,注释掉 movie 项目 Controller 的userUserFeignClient和adminUserFeignClient,以及相关的代码,然后修改映射方法为

        @GetMapping("/user/{id}")
    //  @HystrixCommand(fallbackMethod="findByUserIdFallback")
        public User findByUserId(@PathVariable Integer id){
            //return restTemplate.getForObject("http://MS-SIMPLE-PROVIDER-USER/user/find?id="+id, User.class);
            return userFeignClient.findById(id);
        }
    

    接下来在接口UserFeignClient 做如下修改

    @FeignClient(name="MS-SIMPLE-PROVIDER-USER",fallback=UserFeignClientFallBack.class)
    public interface UserFeignClient {
    
        @RequestMapping(value="/user/find?id={id}",method=RequestMethod.GET)
        public User findById(@PathVariable("id") Integer id);
        
    }
    

    这里需要一个UserFeignClientFallBack类实现了该接口

    @Component
    public class UserFeignClientFallBack implements UserFeignClient{
    
        
        @Override
        public User findById(Integer id) {
            User user=new User();
            user.setId(0);
            user.setName("NULL");
            user.setNickName("默认用户");
            user.setPassword("");
            user.setLastLoginDt(null);
            return user;
        }
    }
    

    这些操作完成后重启 movie,访问 http://localhost:8010/user/1
    同样得到

    使用回调工厂检查原因

    改变不是太大,在接口的地方回调的是一个工厂类

    package cn.ts.ms.movie.feign;
    
    import org.springframework.stereotype.Component;
    
    import cn.ts.ms.movie.model.User;
    import feign.hystrix.FallbackFactory;
    
    @Component
    public class UserFeignClientFactory implements FallbackFactory<UserFeignClient> {
    
        @Override
        public UserFeignClient create(Throwable cause) {
            return new UserFeignClient(){
                @Override
                public User findById(Integer id) {
                    
                    //这里打印输出错误
                    System.out.println(cause);
                    
                    User user=new User();
                    user.setId(0);
                    user.setName("NULL");
                    user.setNickName("默认用户-Factory");
                    user.setPassword("");
                    user.setLastLoginDt(null);
                    return user;
                }
            };
        }
    
    }
    

    修改接口出的 fallback 类@FeignClient(name="MS-SIMPLE-PROVIDER-USER",fallbackFactory=UserFeignClientFactory.class),注意是fallbackFactory

    重启运行 movie,效果一样

    全局禁用Hystrix
    只须在application.yml中配置feign.hystrix.enabled=false即可。

    Hystrix线程隔离策略与传播上下文

    hystrix的隔离策略有两种:线程隔离和信号量隔离
    线程隔离(THREAD):使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中的线程数量的限制。
    信号量隔离(SEMAPHORE):使用该方式,HystrixCommand将会在调用线程上执行,开销相对较小,并发请求受信号量个数的限制。

    hystrix中默认并且推荐使用线程隔离,因为这种方式有一个除网络超时以外的额外保护层。

    一般来说,只有当调用负载非常高时(如:每个实例每秒调用数百次)才需要使用信号量隔离,因为这种场景下使用线程隔离开销会比较大。信号量隔离一般仅适用于非网络调用的隔离。
    可使用execution.isolation.strategy属性指定隔离策略。

    使用 Hystrix Dashboard 来监控数据

    首先引入依赖

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

    启动类增加注解 @EnableHystrixDashboard

    重新启动 movie,浏览 http://localhost:8010/hystrix
    出现


    基本配置下进入

    相关文章

      网友评论

          本文标题:SpringCloud微服务架构-使用Hystrix实现微服务的

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