zoukankan      html  css  js  c++  java
  • SpringCloud入门实战(6)-Hystrix使用

    Hystrix是一个用于分布式系统的延迟和容错的开源库。在分布式系统里,许多依赖不可避免的调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性。本文主要介绍Hystrix的基本使用,文中使用到的软件版本:Spring Boot 2.2.5.RELEASE、Spring Cloud Hoxton.SR3、Java 1.8.0_191。

    1、Hystrix作用

    1.1、资源隔离

    包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。

      线程切换 支持异步 支持超时 支持熔断 限流 开销
    信号量
    线程池

    1.2、降级

    超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。

    1.3、融断

    当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。

    1.4、缓存

    提供了请求缓存、请求合并实现。

    2、Hystrix处理过程

    1.构造一个 HystrixCommand或HystrixObservableCommand对象,用于封装请求,并在构造方法配置请求被执行需要的参数;
    2.执行命令,Hystrix提供了4种执行命令的方法;
    3.判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。Hystrix支持请求缓存,但需要用户自定义启动;
    4.判断熔断器是否打开,如果打开,跳到第8步;
    5.判断线程池/队列/信号量是否已满,已满则跳到第8步;
    6.执行HystrixObservableCommand.construct()或HystrixCommand.run(),如果执行失败或者超时,跳到第8步;否则,跳到第9步;
    7.统计熔断器监控指标;
    8.走Fallback备用逻辑
    9.返回请求响应

    3、Hystrix参数说明

    配置项默认值说明
    hystrix.command.default.execution.isolation.strategy THREAD 隔离策略,THREAD, SEMAPHORE
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 1000 线程超时时间
    hystrix.command.default.execution.timeout.enabled true 启用超时设置
    hystrix.command.default.execution.isolation.thread.interruptOnTimeout true 线程超时时,是否可被中断
    hystrix.command.default.execution.isolation.thread.interruptOnCancel false 线程取消时,是否可被中断
    hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 10 最大并发信号量
    hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 10 最大并发备用信号量
    hystrix.command.default.fallback.enabled true 启用fallback
    hystrix.command.default.circuitBreaker.enabled true 启用断路器
    hystrix.command.default.circuitBreaker.requestVolumeThreshold 20 在一个时间窗口内触发断路器的最小请求量
    hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 5000 触发断路器时,服务休眠时间
    hystrix.command.default.circuitBreaker.errorThresholdPercentage 50 触发断路器时,最小错误比率
    hystrix.command.default.circuitBreaker.forceOpen false 强制打开断路器
    hystrix.command.default.circuitBreaker.forceClosed false 强制关闭断路器
    hystrix.command.default.metrics.rollingStats.timeInMilliseconds 10000 数据采集时间段
    hystrix.command.default.metrics.rollingStats.numBuckets 10 采集数据份,必须能被timeInMilliseconds整除
    hystrix.command.default.metrics.rollingPercentile.enabled true 开启采集滚动百分比
    hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds 60000 滚动百分收集时间段
    hystrix.command.default.metrics.rollingPercentile.numBuckets 6 滚动百分比收集份数,必须能被timeInMilliseconds整除
    hystrix.command.default.metrics.rollingPercentile.bucketSize 100 每份数据的最大统计请求量
    hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds 500 健康检查间隔时间
    hystrix.command.default.requestCache.enabled true 开启请求缓存,HystrixRequestCache
    hystrix.command.default.requestLog.enabled true 开启请求日志,记录在HystrixRequestLog
    hystrix.collapser.default.maxRequestsInBatch Integer.MAX_VALUE 单批次最大请求量
    hystrix.collapser.default.timerDelayInMilliseconds 10 批次请求延迟启动时间
    hystrix.collapser.default.requestCache.enabled true 开启批次请求缓存, HystrixCollapser.execute(), HystrixCollapser.queue()
    hystrix.threadpool.default.coreSize 10 核心线程数
    hystrix.threadpool.default.maximumSize 10 最大线程数
    hystrix.threadpool.default.maxQueueSize -1 最大阻塞线程队列
    hystrix.threadpool.default.queueSizeRejectionThreshold 5 队列上限,超过会拒绝请求
    hystrix.threadpool.default.keepAliveTimeMinutes 1 线程保持活跃时间(分钟)
    hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize false 启用maximumSize参数
    hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 10000 线程池数据采集时间段
    hystrix.threadpool.default.metrics.rollingStats.numBuckets 10 线程池数据采集份数

    4、使用

    4.1、结合springboot使用

    4.1.1、引入依赖

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

    4.1.2、配置Hystrix(application.yml)

    根据需要配置Hystrix,也可以使用默认的配置。参数的意思可以参考上面的参数说明。

    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 1000
          circuitBreaker:
            requestVolumeThreshold: 3

    4.1.3、启动类增加@EnableCircuitBreaker(或@EnableHystrix)

    package com.inspur.scdemo.client;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    @EnableCircuitBreaker
    public class ClientApplication {
        public static void main(String[] args) {
            SpringApplication.run(ClientApplication.class, args);
        }
    }

    4.1.4、编写controller

    package com.inspur.scdemo.client.controller;
    
    import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/hystrix")
    /**defaultFallback为默认的降级方法,没有参数,返回值要与Hystrix方法的返回值相同*/
    @DefaultProperties(commandProperties = {
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
    }, defaultFallback = "defaulFallback")
    public class HystrixController {
        private Logger logger = LoggerFactory.getLogger(HystrixController.class);
    
        @RequestMapping("/test")
        /**fallbackMethod为降级方法,需要与Hystrix方法的签名和返回值一致*/
        @HystrixCommand(
            commandProperties = {
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
            },
            fallbackMethod = "fallback")
        public String test(long id) {
            logger.info(id + "");
    
            try {
                Thread.sleep(1000 * 5);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "test";
        }
    
        @RequestMapping("/test2")
        @HystrixCommand()
        public String test2(long id) {
            logger.info(id + "");
    
            try {
                Thread.sleep(1000 * 5);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "test2";
        }
    
        public String fallback(long id) {
            logger.info(id + "");
            return "fallback";
        }
    
        public String defaulFallback() {
            return "defaulFallback";
        }
    }

    方法上的配置优先级最高,其次是类上的配置,最后时配置文件中的配置。

    访问http://localhost:9002/hystrix/test?id=2,前三次会等待3秒,然后返回"fallback";第三次已触发熔断,第四次访问会快速返回"fallback"

    访问http://localhost:9002/hystrix/test2?id=2,前三次会等待2秒,然后返回"defaultFallback";第三次已触发熔断,第四次会快速返回"defaultFallback"

    4.2、与Feign结合使用

    4.2.1、配置启用Hystrix

    feign:
      hystrix:
        enabled: true

    4.2.2、定义Feign接口

    package com.inspur.scdemo.client.feign;
    
    import com.inspur.scdemo.client.entity.CallResult;
    import com.inspur.scdemo.client.entity.User;
    import com.inspur.scdemo.client.feign.fallback.UserFallBack;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestParam;
    
    //scdemo-server为服务名称
    @FeignClient(name = "scdemo-server", fallback = UserFallBack.class)
    public interface IUserFeign {
        @PostMapping("/user/addUser")
        CallResult<User> addUser(@RequestBody User user);
    
        @PostMapping("/user/getUser")
        CallResult<User> getUser(@RequestParam("id") long id);
    }

    4.2.3、定义降级实现类

    package com.inspur.scdemo.client.feign.fallback;
    
    import com.inspur.scdemo.client.entity.CallResult;
    import com.inspur.scdemo.client.entity.User;
    import com.inspur.scdemo.client.feign.IUserFeign;
    import org.springframework.stereotype.Component;
    
    @Component
    public class UserFallBack implements IUserFeign {
        @Override
        public CallResult<User> addUser(User user) {
            return new CallResult<>(1, "增加用户服务暂不可用!");
        }
    
        @Override
        public CallResult<User> getUser(long id) {
            return new CallResult<>(1, "获取用户服务暂不可用!");
        }
    }

    4.2.4、Controller中调用Feign接口

    package com.inspur.scdemo.client.controller;
    
    import com.inspur.scdemo.client.entity.CallResult;
    import com.inspur.scdemo.client.entity.User;
    import com.inspur.scdemo.client.feign.IUserFeign;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/userfeign")
    public class FeignController {
        private Logger logger = LoggerFactory.getLogger(FeignController.class);
        @Autowired
        private IUserFeign userFeign;
    
        @RequestMapping("/addUser")
        public CallResult<User> addUser(String name, String address) {
            logger.info("name={},address={}", name, address);
            CallResult<User> result = new CallResult<>();
            try {
                User user = new User();
                user.setName(name);
                user.setAddress(address);
                CallResult<User> resultServer = userFeign.addUser(user);
                logger.info("server返回结果:{}" + resultServer);
    
                User user2 = resultServer.getResult();
                user2.setName("client-" + user2.getName());
                result.setResult(user2);
            } catch (Exception e) {
                result = new CallResult<User>(-1, "发生异常");
                e.printStackTrace();
            }
            return result;
        }
    
        @RequestMapping("/getUser")
        public CallResult<User> getUser(long id) {
            logger.info(id + "");
    
            CallResult<User> result = null;
            try {
                result = userFeign.getUser(id);
            } catch (Exception e) {
                result = new CallResult<User>(-1, "发生异常");
                e.printStackTrace();
            }
            return result;
        }
    }

    当scdemo-server服务不存在或调用超时,都会返回降级实现类中返回的信息。

    4.3、与SpringCloud Gateway结合使用

    4.3.1、引入依赖

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

    4.3.2、编写回退controller

    package com.inspur.scdemo.gateway.controller;
    
    import com.inspur.scdemo.gateway.entity.CallResult;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class FallbackController {
        @RequestMapping("/fallback")
        public CallResult<String> fallback() {
            return new CallResult<>(-10, "服务不可用");
        }
    }

    4.3.3、配置Hystrix filter

    spring:
      cloud:
        gateway:
          discovery:
            locator:
              enabled: false #是否开启服务注册和发现功能;将为每一个服务创建一个router,这个router把以服务名开头的请求路径转发到对应的服务上
              lower-case-service-id: true #将请求路径上的服务名转为小写
          routes:
          - id: client
            uri: lb://scdemo-client
            predicates:
            - Path=/scdemo-client/**
            filters:
            - StripPrefix=1 #路由时会去除/scdemo-client
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback

    通过网关调用服务时,当scdemo-client服务不存在或调用超时,都会返回降级controller中fallback方法返回的信息。

    5、hystrix-dashboard

    Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图形化界面,通过Hystrix Dashboard,我们可以在页面上看到服务接口的调用情况。

    5.1、dashboard服务(端口9002)

    5.1.1、引入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>

    5.1.2、启动类增加@EnableHystrixDashboard

    5.1.3、控制台

    http://localhost:9002/hystrix/

    5.2、被监控的服务(端口9001)

    5.2.1、引入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    5.2.2、配置端点

    management:
      endpoints:
        web:
          exposure:
            include: hystrix.stream

    5.2.3、查看Hystrix指标流

    http://localhost:9001/actuator/hystrix.stream,调用9001上Hystrix保护的接口,会有信息输出:

    5.3、dashboard中监控服务

    在dashboard的控制台(http://localhost:9002/hystrix/)中输入被监控的服务(http://localhost:9001/actuator/hystrix.stream),点击"Monitor Stream",即可呈现监控的情况:

     注:dashboard服务和被监控的服务可以在同一服务里面。

  • 相关阅读:
    Easyui datagrid 修改分页组件的分页提示信息为中文
    Easyui datagrid 实现表格记录拖拽
    Java:内部类
    算法导论:Trie字典树
    算法导论:找零钱问题
    lintcode:组成最大的数
    lintcode:验证二叉查找树
    lintcode:将二叉查找树转换成双链表
    lintcode:二叉树的路径和
    lintcode:字符串置换
  • 原文地址:https://www.cnblogs.com/wuyongyin/p/13594941.html
Copyright © 2011-2022 走看看