SpringCloud-Hystrix

一、简介

Hystrix 是针对微服务分布式系统采用的熔断保护中间件,在微服务中都相互依赖,如果不能对依赖的服务进行隔离,服务本身也有可能发生故障,Hystrix 通过 HystrixCommand 对调用进行隔离,这样可以故障连锁反应,能够让接口调用快速失败并迅速恢复正常,或者回退并优雅降级。

二、Hystrix简单的使用

1. 引入依赖

       <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-core</artifactId>
            <version>1.5.18</version>
        </dependency>

2. 编写代码 继承 HystrixCommand

public class MyHystrixCommand extends HystrixCommand<String> {

    private final String name;

    public MyHystrixCommand(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("MyGroup"));

        this.name = name;
    }

    @Override
    protected String run() throws Exception {
        return this.name + ":" +Thread.currentThread().getName();
    }

 
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //同步调用
        String result = new MyHystrixCommand("Alliex").execute();
        System.out.println(result);

        //异步调用
        Future<String> future = new MyHystrixCommand("Alliex").queue();
        System.out.println(future.get());

 
    }

3. 回退支持

    @Override
    protected String run() throws Exception {
        TimeUnit.SECONDS.sleep(2);
        System.out.println("get Data");
        return this.name + ":" +Thread.currentThread().getName();
    }

  //回退支持
    @Override
    protected String getFallback() {
        return "执行失败了";
    }

运行代码结果如下,证明已经触发了回调

4. 信号量策略配置

    public MyHystrixCommand(String name) {

        //信号量策略配置
        super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
              .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                .withExecutionIsolationStrategy(HystrixCommandProperties
                        .ExecutionIsolationStrategy.SEMAPHORE)));
        this.name = name;
    }

运行结果如下,之前在run方法中输出了线程的名称,通过这个就可以确定是线程隔离还是信号量隔离

5. 线程隔离策略配置

运行结果如下

 6. 结果缓存

   增加 getCacheKey() 方法, 在run方法中输出 get Data ,将main方法中的代码改为如下写法

  @Override
    protected String getCacheKey() {
        return String.valueOf(this.name);
    }

   @Override
    protected String run() throws Exception {
//        TimeUnit.SECONDS.sleep(2);
        System.out.println("get Data");
        return this.name + ":" +Thread.currentThread().getName();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //缓存的测试代码
        HystrixRequestContext hystrixRequestContext = HystrixRequestContext.initializeContext();
        String result =  new MyHystrixCommand("Alliex").execute();
        System.out.println(result);
        Future<String> future = new MyHystrixCommand("Alliex").queue();
        System.out.println(future.get());
        hystrixRequestContext.shutdown();

    }

运行结果如下,可以看到只输出一个get Data 证明走了缓存

 

7.缓存清除

public class ClearCacheHystrixCommand extends HystrixCommand<String> {

    private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("MyKey");

    private final String name;

    public ClearCacheHystrixCommand(String name){
        super(HystrixCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey("MyGroup")
        ).andCommandKey(GETTER_KEY));
        this.name = name;
    }

    /*----------------------清除缓存-------------------------------*/
    public static void flushCache(String name){
        HystrixRequestCache.getInstance(GETTER_KEY, HystrixConcurrencyStrategyDefault.getInstance()).clear(name);
    }

    @Override
    protected String getCacheKey() {
        return String.valueOf(name);
    }

    @Override
    protected String run() throws Exception {
        System.out.println("get data");
        return this.name + ":" + Thread.currentThread().getName();
    }

    @Override
    protected String getFallback() {
        return "失败了";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        String result = new ClearCacheHystrixCommand("Alliex").execute();
        System.out.println(result);
        ClearCacheHystrixCommand.flushCache("Alliex");
        Future<String> future = new ClearCacheHystrixCommand("Alliex").queue();
        System.out.println(future.get());

    }
}

 运行结果如下,可以看到输出了两次 get data 证明缓存清楚成功

8. 合并请求

public class MyHystrixCollapser extends HystrixCollapser<List<String>,String,String> {

    private final String name;

    public MyHystrixCollapser(String name) {
        this.name = name;
    }

    @Override
    public String getRequestArgument() {
        return name;
    }

    @Override
    protected HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, String>> requests) {
        return new BatchCommand(requests);
    }

    @Override
    protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, String>> requests) {
       int count = 0;
        for (CollapsedRequest<String,String> request:requests) {
            request.setResponse(batchResponse.get(count++));

        }
    }

    private static  final class BatchCommand extends HystrixCommand<List<String>>{

        private final Collection<CollapsedRequest<String,String>> requests;

        private BatchCommand(Collection<CollapsedRequest<String,String>> requests) {

            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            .andCommandKey(HystrixCommandKey.Factory.asKey("ExampleGroup"))
            .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueOfKey")));
            this.requests = requests;
        }

        @Override
        protected List<String> run() throws Exception {
            System.out.println("真正执行请求---------------------");
            ArrayList<String> response = new ArrayList<String>();
            for (CollapsedRequest<String,String> request: requests) {
                response.add("返回结果: "+request.getArgument());
            }
            return response;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        HystrixRequestContext hystrixRequestContext = HystrixRequestContext.initializeContext();
        Future<String> future = new MyHystrixCollapser("Alliex").queue();
        Future<String> future2 = new MyHystrixCollapser("Alliex2").queue();
        System.out.println(future.get()+"="+future2.get());
        hystrixRequestContext.shutdown();
    }
}

 运行结果如下,可以看到指输出了一次,证明两个任务被合并到了一起

三、Springcloud 整合 Hystrix

1. 引入依赖

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

 2. 加注解

    在启动类上加 @EnableHystrix 或者  @EnableCircuitBreaker 这两个主句只能加一个。

3. 写测试方法

@RestController
public class TestHystrixController {

    private RestTemplate restTemplate;

    @Autowired
    public TestHystrixController(RestTemplate restTemplate){
        this.restTemplate = restTemplate;
    }

    @GetMapping("/callHello")
    @HystrixCommand(defaultFallback = "defaultCallHello")
    public String callHello(){
        String result = restTemplate.getForObject("http://localhost:8088/hello",String.class);
        return  result;
    }
    public  String defaultCallHello(){
        return "hello fail";
    }


}

运行结果如下, 证明执行了回退方法

四、 Feign 整合 Hystrix

 1. 开启 Feign 对 Hystrix的支持

#开启hystrix false为禁用
feign.hystrix.enabled=true

2. Feign回退内容定义

@Component
public class UserRemoteClientFallback implements UserRemoteClient {
    @Override
    public String sayHelloToPerson(String userName) {
        return "hello fail";
    }
}

3. 制定 Fallback的方式

@FeignClient(value = "eureka-client-user-service"
        ,configuration = FeignConfiguration.class
        ,fallback = UserRemoteClientFallback.class
//        ,fallbackFactory = UserRemoteClientFallbackFactory.class
        )
public interface UserRemoteClient {

    @GetMapping("/user/helloToPerson")
    String sayHelloToPerson(@RequestParam("userName") String userName);
}

停掉 eureka-client-user-service 服务,运行结果如下,证明进入了回退的方法

4. FallbackFactory方式

   通过fallback可以实现服务不可用时的回退功能,如果想知道触发回退的原因可以使用 FallbackFactory

@Component
public class UserRemoteClientFallbackFactory implements FallbackFactory<UserRemoteClient> {

    private Logger logger = LoggerFactory.getLogger(UserRemoteClientFallbackFactory.class);

    @Override
    public UserRemoteClient create( Throwable cause) {
        logger.error("UserRemoteClient 回退" ,cause);
        return userName -> "hello fail";
    }
}
@FeignClient(value = "eureka-client-user-service"
        ,configuration = FeignConfiguration.class
//        ,fallback = UserRemoteClientFallback.class
        ,fallbackFactory = UserRemoteClientFallbackFactory.class
        )
public interface UserRemoteClient {

    @GetMapping("/user/helloToPerson")
    String sayHelloToPerson(@RequestParam("userName") String userName);
}

运行结果如下:

 可以看到控制台已经输出了错误原因。

 5. Hystrix 监控

    a. 引入依赖


<!--        Hystrix监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version> 2.2.2.RELEASE</version>
        </dependency>

b. 在配置文件中加如下的配置

management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

c. 访问地址 http://localhost:8080/actuator/hystrix.stream 可以看到一只在ping ,直到你访问 http://localhost:8080/test/fegin?userName=xxx 时就有内容输出了,如下图

6. 整合Dashboard 查看监控数据

a. 引入依赖

<!--        整合dasboard查看监控数据-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

b. 启动类中加入注解 @EnableHystrixDashboard

c. 访问 http://localhost:8080/hystrix ,可以看到下面的页面

在第一输入框中输入我们刚才监控的地址:http://localhost:8080/actuator/hystrix.stream Delay 和title可以自定义,点击按钮后可以看到下图所示的界面:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值