Hystrix降级和熔断实验

实验为目的

1)Hystrix 线程池打满再来请求服务降级和熔断

2)hystrix 某个时间窗口内的buket时间内服务请求书和错误率导致降级和熔断

3)hystrix 滑动窗口配置,影响熔断以及熔断状态切换时间

4)hystrix 熔断状态切换(CLOSE,OPNE,HALF_OPEN)

5)hystrix.stream 或者Hystrix Dashboard 使用

PS: HystrixDashboard只是为了展示和验证,看代码时因为不熟悉RxJava的,滑动窗口统计部分可能看起来比较费力,可以通过这里仪表盘验证自己的想法和预测。

feign中使用Hystrix核心链路

在使用Feign的场景下,一次远程调用经历了入戏图中几个组件,每个组件有自己的配置,比如超时时间,线程池数量,方法耗时。
在这里插入图片描述

这几个组件的一些配置可能会使得Hystrix触发降级和熔断【比如超时和线程池满了,以及业务异常】,所以有必要对上面的相关因素做一些了解,否则实验过程中会出现一些出乎意外的结果。

请求流程

不做无准备之仗,再次之前先要对Hystrix的执行流程要有个清晰的认识,前面也看到,有feign,ribbon这两个组件,去掉之后还有rxjava语法,我在看的时候遇到很多不懂的地方这里将总结的流程发出来。
在这里插入图片描述

图中大致可以看到几个核心的逻辑:

  • Hystrix判断是否熔断打开
    • 一个bucket时间内请求数达到阈值,并且错误率达到阈值----> 熔断打开
    • 一个bucket时间内请求数未达到阈值 ----> 熔断不打开 【即便是错误率100%】
  • Hystrix 熔断状态切换
  • Hystrix 执行结果汇入滑动窗口

还能得出一些逻辑:

  • 熔断直接进入降级逻辑
  • 降级不一定是熔断状态
  • 熔断是在达到熔断指标之后下一次请求进入的时候判断得出的
  • 统计结果跟时间窗口每个bucket存储的各项数据指标有关系

实战演示相关准备

提供方代码

一个很普通的Controller,以服务提供者角色对外提供服务

@Slf4j
@RestController
@RequestMapping("/user")
public class UserResource implements UserServiceFeignApi {

    private Random random = new Random();

    /**
     * @description 模拟服务提供方方法耗时很长,主要是位让hystrix线程池打满,看看线程池慢之后降级,熔断
     * @author yzMa
     * @date 2019/8/6
     * @param  
     * @return  
     */
    @GetMapping("/get/{id}")
    @Override
    public UserModel getById(@PathVariable Long id) throws InterruptedException {
        int nextVal = 600000; //random.nextInt(10000);
        log.info("sleep time ={}",nextVal);
        Thread.sleep(nextVal);

        UserModel userModel = new UserModel();
        userModel.setId(id);
        userModel.setName("myz"+nextVal);
        return userModel;
    }

    /**
     * @description  模拟方法抛出异常,快速返回,以及随机业务耗时
     * @author yzMa
     * @date 2019/11/1
     * @param
     * @return
     */
    @GetMapping("/hi/{name}")
    @Override
    public String sayHi(@PathVariable(name = "name") String name,
                        @RequestParam(name = "fast",defaultValue = "false") boolean fast,
                        @RequestParam(name = "throwEx",defaultValue = "false") boolean throwEx) throws InterruptedException {

        String val = "hi,"+name;
        if(throwEx){
            throw new RuntimeException("服务端异常");
        }

        if(fast){
            return val;
        }

        int waitTime = random.nextInt(2000);
        log.info("wait time {} ms",waitTime);

        Thread.sleep(waitTime);

        return val;
    }
}

两个方法在演示中的作用:

UserServiceFeignApi#getById(Long)
  • 模拟服务提供方方法耗时很长,主要是位让hystrix线程池打满,看看线程池慢之后降级,熔断
UserServiceFeignApi#sayHi(String,boolean,boolean);
  • 模拟服务提供方方法抛出异常,快速返回,以及随机业务耗时

二方包代码

@FeignClient(name = "sc-user",fallbackFactory = UserServiceFallbackFactory.class)
public interface UserServiceFeignApi {
    String USER_PREFIX = "/user";

    @GetMapping(USER_PREFIX+"/get/{id}")
    UserModel getById(@PathVariable("id") Long id) throws InterruptedException;

    @GetMapping(USER_PREFIX+"/hi/{name}")
    String sayHi(@PathVariable(name = "name") String name,
                 @RequestParam(name = "fast",defaultValue = "false") boolean fast,
                 @RequestParam(name = "throwEx",defaultValue = "false") boolean throwEx) throws InterruptedException;
}

服务方提供的接口,翻遍消费方调用,可以直接被消费方扫描,就像执行本地接口方法

消费方代码

@Slf4j
@RestController
@RequestMapping("/test/user")
public class TestUserController {

    @Autowired
    private UserServiceFeignApi userServiceFeignApi;

    @GetMapping("/get/{id}")
    public UserModel get(@PathVariable Long id) throws InterruptedException {

        long startTime = System.currentTimeMillis();
        System.out.println("开始执行"+startTime);
        UserModel userModel = userServiceFeignApi.getById(id);
        System.out.println("消耗时间:"+(System.currentTimeMillis()-startTime));
        return userModel;
    }

    @GetMapping("/hello/{name}")
    public String hello(@PathVariable String name,
                        @RequestParam(defaultValue = "false")boolean fast,
                        @RequestParam(defaultValue = "false")boolean throwEx) throws InterruptedException {

        return userServiceFeignApi.sayHi(name,fast,throwEx);
    }
}

代码依然很简单,直接调用feign接口。

降级逻辑

@Slf4j
@Component
public class UserServiceFallback implements UserServiceFeignApi {
    @Override
    public UserModel getById(Long id) throws InterruptedException {
        log.info("getById| fallback id={}",id);
        UserModel userModel = new UserModel();
        userModel.setId(0L);
        userModel.setName("fallback");
        return userModel;
    }

    @Override
    public String sayHi(String name,boolean fast,boolean throwEx) throws InterruptedException {
        return fast?("fallback-service-fast "+name) :("fallback-service "+name);
    }
}

降级逻辑也很简单

Hystrix 隔离配置

hystrix:
  command:
    default:
      circuitBreaker:
        sleepWindowInMilliseconds: 5000
        requestVolumeThreshold: 20
        errorThresholdPercentage: 50
      metrics:
        rollingStats:
          timeInMilliseconds: 10000
        healthSnapshot:
          intervalInMilliseconds:500
      execution:
        isolation:
          semaphore:
            maxConcurrentRequests: 2
          strategy: SEMAPHOR
          thread:
            timeoutInMilliseconds: 500000 #【注意URL超时和线程Future超时】 默认500秒超时 主要是为了访问某些让线程hold住  测试下面的熔断场景
    UserServiceFeignApi#sayHi(String,boolean,boolean): # HystrxiCommand在Feign中默认的commandKey就是类似于方法签名
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000 # 5s 超时
      circuitBreaker:
        requestVolumeThreshold: 6
        sleepWindowInMilliseconds: 60000
  threadpool:
    sc-user: #HystrixCommand在Feign中默认的的groupKey就是serviceId
      allowMaximumSizeToDivergeFromCoreSize: true
      coreSize: 2 #默认时间
      maximumSize: 4
      keepAliveTimeMinutes: 1
      maxQueueSize: -1
      queueSizeRejectionThreshold: 6 # maxQueueSize=-1 时候这个配置时无效的

配置相关含义介绍

  • HystrixCommand的goupKey ,在Feign表现为serviceId=sc-user ,该serviceId表示的类以及类的所有方法公用一个线程池,来执行远程调用。hystrix线程池属于应用级别
  • HystrixCommand的CommandKey,在Feign表现为Feign接口的方法比如UserServiceFeignApi#sayHi(String,boolean,boolean)有自己独立的配置
    • 隔离策略
    • 超时时间
    • 熔断器配置
      • 滑动窗口的时长
      • 滑动窗口的buket的数量,因此可以推导出有一个窗口有多少个buket,再结合定时任务移动一个bucket就能统计出每个bucket的指标信息决定是否要熔断
        hystrix 隔离策略,熔断配置,线程池的future超时属于方法级别
  • Hystrix 默认没有指定特定的commandKey的时候使用默认commandKey=default hystrix 默认配置

开始试验

测试hystrix线程池打满再次请求fallback

我们用jmeter来发送请求,线程数跟Hystrix线程池数量一样,

Future超时时间
URL超时时间
提供方接口耗时都很长
这样一来运行Jmeter的时候线程池就全部打满,并被hold住,再次在浏览器发送请求。

测试方法为UserServiceFeignApi#getById(Long) 如下的特征:

  • 方法耗时时间可以sleep时间长一些

  • hystrix的线程池Future的超时时间大于Feign(即URL的超时时间)

  • Feign的超时时间大于方法耗时

  • Feign中设置的超时时间最终设置的是上图的http部分,默认是java.net.URL的超时时间

    • feign:
        hystrix:
          enabled: true # 该版本需要手工启用
        client:
          config:
            sc-user: # 在客户端配置的服务提供方 配置信息的key
              readTimeout: 400000 #4000  Url的超时时间
              connectTimeout: 20000
      

测试提供方抛出异常降级和熔断

  • 见后边提供方代码

测试时间窗口内buket的请求数和错误率降级和熔断

  • 见后边提供方代码

Hystrix 滑动窗口介绍

受篇幅影响 Rxjava的滑动窗口部分可以到这里查看,这里的rxjava部分完全是从Hystrix中抽离出来的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值