Java利用配置重试策略解决超时问题

目录
  • 使用场景
  • 示例
  • 执行流程
  • 配置
  • 注意
  • 总结

在web应用中,由于网络原因或其他不可预测的原因,应用间会出现调用失败的情形,通过配置重试策略可以有效解决外在原因导致的系统故障。

使用场景

  • 微服务间各个服务模块间的调用
  • 第三方模块远程交易调用
  • 非业务异常导致可能失败的情况

示例

构建Retryer

private Retryer retryer = RetryerBuilder.newBuilder()
        .retryIfException() // 异常时重试
        .retryIfResult(input -> input!=null && input instanceof Boolean && !Boolean.valueOf((Boolean) input)) // 返回值为false时重试
        // 对应Future获取超时时间
        .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(4, TimeUnit.SECONDS,Executors.newFixedThreadPool(2))) //重试次数限制
        .withRetryListener(new RetryListener() { // 重试执行逻辑
            @Override
            public <V> void onRetry(Attempt<V> attempt) {
                log.info("onRetry -> 重试次数:{},距第一次重试时长:{}", attempt.getAttemptNumber(),attempt.getDelaySinceFirstAttempt());
                if(attempt.hasException()){ // 是否异常导致重试
                    Throwable exception = attempt.getExceptionCause(); // 执行的异常
                    log.info("异常:{}", exception);
                }
                if(attempt.hasResult()){ // 是否有返回
                    V result = attempt.getResult();
                    log.info("返回:{}",result);
                }
            }
        })
        // 控制每次重试间隔时间,如果AttemptTimeLimiter设置多线程
        .withWaitStrategy(WaitStrategies.fixedWait(3,TimeUnit.SECONDS)) // 等待策略
        .withBlockStrategy(BlockStrategies.threadSleepStrategy()) // 阻塞策略
        //
        .withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 停止策略
        .build();

使用Retryer让业务代码拥有重试能力

前两次执行时模拟返回false,则会执行重试;当第3次时,正常执行业务代码并返回true,结束重试

@Test
public void retryWhenResult() throws ExecutionException, RetryException {
   retryer.call(() -> {
       if(counter.incrementAndGet() == 3){// 模拟前2此返回false,触发重试
           log.info(" 执行业务代码:{}次",counter.get());
           return true;
       }
       return false; 
   });
}

模拟前3次出现异常,则会执行重试;当第3次时,正常执行业务代码,结束重试

@Test
public void retryWhenException() throws ExecutionException, RetryException {
    retryer.call(() -> {
        if( counter.getAndIncrement() == 3 ){// 模拟前5此出现异常,触发重试
            return counter;
        }
        log.info(" 执行业务代码: {}次", counter.get());
         throw new RuntimeException("ERROR"); 
    });
}

模拟前5此出现异常,由于Retryer配置重试次数为5,则最终业务代码不会执行

@Test
public void retryWhenResultOnFailure() throws ExecutionException, RetryException {
    retryer.call(() -> {
        if(counter.incrementAndGet() == 8){// 模拟前7此返回false,由于配置重试5次,因此最终失败
            log.info(" 执行业务代码:{}次",counter.get());
            return true;
        }
        return false;
    });
}

执行流程

执行流程

通过RetryerBuilder构建Retryer,调用Retryer#call,封装业务代码为其回调函数

  • 开始循环执行
  • 由AttemptTimeLimiter#call执行回调函数
  • 将结果封装为Attempt,包括两种类型ResultAttempt,ExceptionAttempt。如果成功,记录执行结果、持续时长;如果失败,记录异常、持续时长
  • 执行监听RetyrListener#onRetry,可以配置多个监听
  • 执行拒绝断言Predicate,根据返回值、执行异常、返回异常类型判断是否终止重试
  • 如果满足条件,则继续重试;否则结束重试,并返回Attempt包含回调结果
  • 根据终止策略StopStrategy判断是否终止重试
  • 根据等待策略WaitStrategy获取等待时长
  • 根据阻塞策略BlockStrategy与上一步等待时长阻塞重试,如果出现异常则抛出RetryException
  • 重复执行以上逻辑

配置

构建Retryer主要通过RetryerBuilder.newBuilder()实现,其相关配置如下:

配置 策略 名称 描述
AttemptTimeLimiters   任务执行时长限制  
  NoAttemptTimeLimit 无时长限制  
  FixedAttemptTimeLimit 固定时长限制  
WaitStrategies   重试等待策略  
  ExponentialWaitStrategy 指数等待策略 按指数增加重试间隔时长,比如第一次2^1100、2^2100、2^3*100...最多300000
  FibonacciWaitStrategy 斐波那契等待策略 1100、1100、2100、3100、5*100...
  FixedWaitStrategy 固定时长等待策略 按配置的固定间隔时间
  RandomWaitStrategy 随机时长等待策略 随机间隔时间,可以设置随机值范围
  IncrementingWaitStrategy 递增等待策略 根据配置的初始值与增量进行累加时间
  ExceptionWaitStrategy 异常等待策略 根据异常类型指定等待时间
  CompositeWaitStrategy 复合等待策略 可配置多个策略进行组合
BlockStrategies   阻塞策略 根据WaitStrategies获取阻塞时长
  ThreadSleepStrategy 线程等等策略 通过Thread.sleet()实现
StopStrategies   重试停止策略  
  NeverStopStrategy 无限制策略  
  StopAfterAttemptStrategy 限定次数策略  
  StopAfterDelayStrategy 限定时长策略  
  NoAttemptTimeLimit 限定次数  

注意

AttemptTimeLimiter中的FixedAttemptTimeLimit依赖于guava中的SimpleTimeLimiter,但是在guava高版本中该类已经成了私有类

总结

Guava Retrying模块能够通过简单的将代码实现业务逻辑重试的功能,并且其配置中包含了重试的次数、时长控制、重试阻塞、终止策略等等, 在项目中是非常常用的一项技术。

到此这篇关于Java利用配置重试策略解决超时问题的文章就介绍到这了,更多相关Java配置重试策略解决超时内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java基于Guava Retrying实现重试功能

    在接口调用中由于各种原因,可能会重置失败的任务,使用Guava-Retrying可以方便的实现重试功能. 首先,需要引用Guava-Retrying的包 <dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>

  • Java编程Retry重试机制实例详解

    本文研究的主要是Java编程Retry重试机制实例详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下 1.业务场景 应用中需要实现一个功能: 需要将数据上传到远程存储服务,同时在返回处理成功情况下做其他操作.这个功能不复杂,分为两个步骤:第一步调用远程的Rest服务逻辑包装给处理方法返回处理结果:第二步拿到第一步结果或者捕捉异常,如果出现错误或异常实现重试上传逻辑,否则继续逻辑操作. 2.常规解决方案演化 1)try-catch-redo简单重试模式: 包装正

  • Java利用配置重试策略解决超时问题

    目录 使用场景 示例 执行流程 配置 注意 总结 在web应用中,由于网络原因或其他不可预测的原因,应用间会出现调用失败的情形,通过配置重试策略可以有效解决外在原因导致的系统故障. 使用场景 微服务间各个服务模块间的调用 第三方模块远程交易调用 非业务异常导致可能失败的情况 示例 构建Retryer private Retryer retryer = RetryerBuilder.newBuilder()         .retryIfException() // 异常时重试         

  • Spring Kafka中如何通过参数配置解决超时问题详解

    目录 背景 思路 过程 步骤一,查询版本特性 步骤二,查源码 步骤三,查自身的代码 总结 背景 这是我们团队负责的一个不太核心的服务.之前与外部交互时应外部要求由普通kafka集群改成加密kafka集群.我们是数据生产端. 改的过程中并跑上线,60%的请求耗时增加了2倍,也还是在百毫秒的量级可以接受.但是每次重启的第一个请求要5s以上,会超过:运行过程中,一两个月也会有一次超时.因为我们有三次重试,整体没有影响成功率. 上线的时候我们问过网络组,还专门请教过公司专业负责kafka的团队.结论是:

  • Java中Druid连接池连接超时获取不到连接的解决

    错误内容: com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 30000, active 600, maxActive 600, creating 0 detail: Service Error:Cannot find a proper coonection from STDB 错误日志截图: 解决过程: 1.添加了三个参数 作用是如果超过3分钟,连接未释放,那么关闭连接,并报错. 2.进行请求,并查看日志 确认获

  • 详解Java利用深度优先遍历解决迷宫问题

    目录 什么是深度优先 一个简单的例子 程序实现 什么是深度优先 什么是深度,即向下,深度优先,即向下优先,一口气走到底,走到底发现没路再往回走. 在算法实现上来讲,深度优先可以考虑是递归的代名词,深度优先搜索必然需要使用到递归的思路. 有的人可能会说了,我可以用栈来实现,以迭代的方式,那么问题来了,栈这种数据结构,同学们认为是否也囊括了递归呢?Java语言的方法区本身也是实现在一个栈空间上的. 一个简单的例子 我们以一个简单的迷宫为例,以1代表墙,0代表路径,我们构造一个具有出入口的迷宫. 1

  • Java利用策略模式实现条件判断,告别if else

    目录 定义 使用场景 案例 需求 实现方案 方案分析 总结 定义 策略模式定义了一系列算法,并且将每个算法封装起来,使得他们可以相互替换,而且算法的变化不会影响使用算法的客户端. 使用场景 一个系统需要动态的在几种算法中选择一种,可以把每个算法封装到具体的策略类中 一个类中定义了多种行为,可以去代替条件转移语句,减少硬编码 系统中各个算法或者说函数是彼此独立的,而且要求对客户隐藏算法具体实现细节的时候 多个类只区别在表现行为的不同,可以使用策略模式,在运行时动态的选择要执行的行为 案例 需求 根

  • Java利用深度搜索解决数独游戏详解

    目录 一.问题描述 二.输入和输出 三.输入和输出样例 四.分析 五.算法设计 六.代码 七.测试 一.问题描述 数独是一项非常简单的任务.如下图所示,一张 9 行 9 列的表被分成 9 个 3*3 的小方格.在一些单元格中写上十进制数字 1~9,其他单元格为空.目标是用 1 ~9 的数字填充空单元格,每个单元格一个数字,这样在每行.每列和每个被标记为 3*3 的子正方形内,所有 1~9 的数字都会出现.编写一个程序来解决给定的数独任务. 二.输入和输出 1.输入 对于每个测试用例,后面都跟 9

  • Java利用Optional解决空指针异常

    目录 背景介绍 案例 基本用法解析 转换与过滤 案例优化 源码解析 总结 背景介绍 Java 8 引入了一个十分实用的 Optional 类,它主要是为了解决空指针异常(NullPointerException).当我们对对象的属性进行检查,判断它的值是否为期望的格式,最终却发现我们查看的并不是一个对象,而是一个空指针,它会立即抛出一个让人厌烦的 NullPointerException 异常. 本质上,Optional 类是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象

  • Java利用Guava Retry实现重处理

    目录 一.pom依赖 二.使用示例 三.重试时机 1. 根据异常进行重试 2. 根据返回结果进行重试 四.停止重试策略StopStrategy 1. NeverStopStrategy 2. StopAfterAttemptStrategy 3. StopAfterDelayStrategy 五.重试间隔策略.重试阻塞策略 1.BlockStrategy 2. WaitStrategy 六.重试监听器RetryListener 七.重试原理 八.总结 在日常开发中,尤其是在微服务盛行的时代下,我

  • feign的ribbon超时配置和hystrix的超时配置说明

    先看下我的配置: ribbon: MaxAutoRetries: 1 #最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试 MaxAutoRetriesNextServer: 1 #切换实例的重试次数 OkToRetryOnAllOperations: false # 对所有的操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false ConnectTimeout: 1000 #请求连接的超时时间 ReadTimeo

随机推荐