Spring Cloud 学习笔记 —— Resilience4 简介和基本用法

10.1 Resilience4 简介

Resilience4j 是 Spring Cloud Greenwich 版推荐的容错解决方案。 可能成为主流的解决方案,因为 Hystrix 的公司 Netflix 不再更新, Resilience4j 是受 Hystrix 启发设计出来的 ;相比 Hystrix,Resilience4j 专门为 Java 8 以及函数式编程而设计,更加轻量级,没有任何外部依赖性,除了 resilience4j 自身的依赖,不需要其他依赖
在这里插入图片描述
在这里插入图片描述

  • Resilience4j 主要提供功能
    (1)断路器
    (2)限流
    (3)基于信号量的隔离
    (4)缓存
    (5)请求限时
    (6)请求重试

10.2 Resilience4j 在 JavaSe基本用法

搭建环境

  • (1)创建一个普通的 maven 项目 resilience4j 作为 javaboycloud 项目的 module。并添加 junit 依赖
    在这里插入图片描述
    在这里插入图片描述
		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

10.2.1 断路器

Resilience4j 提供了很多功能,不同功能对应不同依赖,按需添加

  • (1)引入 resilience4j-circuitbreaker 依赖
		<dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-circuitbreaker</artifactId>
            <version>1.5.0</version>
        </dependency>

(2)在 test 目录,创建一个包路径 org.javaboy.resilience4j,新建类 Resilience4jTest,
获取一个 CircuitBreakRegistry 实例,可以调用 ofDefault 方法,也可以自定义。
一个正常执行的例子:

@Test
    public void test1(){
        // 获取一个 CircuitBreakerRegistry 实例,可以 ofDefaults 来获取 CircuitBreakerRegistr 实例,也可以自定义属性
        CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults();

        CircuitBreakerConfig config =  CircuitBreakerConfig.custom()
                //故障率阈值百分比,超过这个阈值,断路器就会打开
                .failureRateThreshold(50)
                //断路器保持打开的时间,在到达设置的时间后,断路器会进入 half open 状态
                .waitDurationInOpenState(Duration.ofMillis(1000))
                // 当断路器处于 half open 状态,环形缓冲区的大小
                .ringBufferSizeInHalfOpenState(2)
                //当断路器关闭时,环形缓冲区的大小
                .ringBufferSizeInClosedState(2)
                .build();
        CircuitBreakerRegistry r1 = CircuitBreakerRegistry.of(config);
        //第一种写法
        CircuitBreaker cb1 = r1.circuitBreaker("javaboy");
        CircuitBreaker cb2 = r1.circuitBreaker("javaboy2", config);
        CheckedFunction0<String> supplier = CircuitBreaker.decorateCheckedSupplier(cb1, () -> "Hello resilience4j");
        Try<String> result = Try.of(supplier)
                .map(v -> v + "hello world");
        System.out.println(result.isSuccess());
        System.out.println(result.get());
    }

运行结果:
在这里插入图片描述

一个出异常的断路器

@Test
    public void test2(){
        CircuitBreakerConfig config =  CircuitBreakerConfig.custom()
                //故障率阈值百分比,超过这个阈值,断路器就会打开,默认也是 50%
                .failureRateThreshold(50)
                //断路器保持打开的时间,在到达设置的时间后,断路器会进入 half open 状态
                .waitDurationInOpenState(Duration.ofMillis(1000))
                // 当断路器处于 half open 状态,唤醒缓冲区的大小
                .ringBufferSizeInClosedState(2)
                .build();
        CircuitBreakerRegistry r1 = CircuitBreakerRegistry.of(config);
        CircuitBreaker cb1 = r1.circuitBreaker("javaboy");
        //获取断路器状态
        System.out.println(cb1.getState());//CLOSED
        //第一条数据
        cb1.onError(0, TimeUnit.SECONDS,new RuntimeException());
        //获取断路器状态
        System.out.println(cb1.getState());//CLOSED
        //第二条数据
        cb1.onSuccess(0,TimeUnit.SECONDS);
        //获取断路器状态
        System.out.println(cb1.getState());//OPEN,因为一共两次,其中一共错误,故障率到达 50%,断路器开启,不在向下执行
        CheckedFunction0<String> supplier = CircuitBreaker.decorateCheckedSupplier(cb1, () -> "Hello resilience4j");
        //有 Try.of 也有 Try.run
        Try<String> result = Try.of(supplier)
                .map(v -> v + "hello world");
        System.out.println(result.isSuccess());//false
        System.out.println(result.get());
    }

运行结果:
在这里插入图片描述
.ringBufferSizeInClosedState(2)表示当有两条数据时才会统计故障率,所以,下面的手动故障,至少调用两次 onError 或者一次 onError 、一次 onSuccess 断路器才会打开。

10.2.2 限流

Resilience4j 中的限流 RateLimiter 本身和前面的断路器很像,有 RateLimiterRegistry、RateLimiterConfig.

  • (1)添加依赖
		<dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-ratelimiter</artifactId>
            <version>1.5.0</version>
        </dependency>
  • (2)测试
@Test
   public void test3(){
               // 每个周期为 1 秒(limitRefreshPeriod(Duration.ofMillis(1000)))
       RateLimiterConfig config = RateLimiterConfig.custom().limitRefreshPeriod(Duration.ofMillis(1000))
               // 为了测试方便,只允许两个请求,即每秒两个请求
               .limitForPeriod(2)
               // 限流之后的冷却时间
               .timeoutDuration(Duration.ofMillis(1000))
               .build();
       RateLimiter rateLimiter = RateLimiter.of("javaboy", config);

       CheckedRunnable checkedRunnable = RateLimiter.decorateCheckedRunnable(rateLimiter, () -> {
           System.out.println(new Date());
       });
       // 调用 Java 8 流式编程的 run 方法
       //一共调用四次,因为每秒只能处理两个,所以应该分两秒打印结果
       Try.run(checkedRunnable)
               .andThenTry(checkedRunnable)
               .andThenTry(checkedRunnable)
               .andThenTry(checkedRunnable)
               //失败了,打印错误 
               .onFailure(t-> System.out.println(t.getMessage()));
   }

运行结果:
在这里插入图片描述
如果把.limitForPeriod(4)参数改为4,那么结果在一秒打印:
在这里插入图片描述

10.2.3 请求重试

Spring 家族中使用的比较多的时 Spring-retry,Resilience4j 中也提供了重试的功能,而且 Resilience4j 的重试更加轻量级,而且可以根据结果来决定是否要进行重试。一句话:Resilience4j 更好用一些。

  • (1)添加依赖
		<dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-retry</artifactId>
            <version>1.5.0</version>
        </dependency>
  • (2)测试:
@Test
    public void test4(){
        RetryConfig config = RetryConfig.custom()
                // 最大重试次数 2 次
                .maxAttempts(4)
                // 重试时间间隔
                .waitDuration(Duration.ofMillis(500))
                // 发生指定异常重试
                .retryExceptions(RuntimeException.class)
                .build();
        Retry retry = Retry.of("javaboy", config);
        // 开启重试功能之后,run 方法如果抛异常,会自动触发重试功能
        Retry.decorateRunnable(retry,new Runnable(){
            int count = 0;
            @Override
            public void run() {
                System.out.println(count);
                if(count++ < 3){
                    throw new RuntimeException();
                }
                System.out.println("retry");
            }
        }).run();
    }

运行结果:
在这里插入图片描述

这里的重试,是以面向切面的方式来代理 run() 方法,count 的属性时会递增的,重试了两次还不成功,就抛出异常了,即代理不重试了,抛出异常;如果把 .maxAttempts(4)改成 4 次,那第四次 count = 3,那么就会不走 if 判断结果就成功了:
在这里插入图片描述
这就是重试功能,本来应该报错的,经过重试后,返回了正确的结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值