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

2017-10-21  本文已影响564人  breezedancer

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

Hystrix 介绍

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

Hystrix 通过如下几点实现:

集成 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
出现


基本配置下进入
上一篇下一篇

猜你喜欢

热点阅读