Fast-Retry:一个支持百万级多任务异步重试框架【送源码】

2024-06-05 02:28

本文主要是介绍Fast-Retry:一个支持百万级多任务异步重试框架【送源码】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

假设你的系统里有100万个用户,然后你要轮询重试的获取每个用户的身份信息, 如果你还在使用SpringRetry和GuavaRetry 之类的这种单任务的同步重试框架,那你可能到猴年马月也处理不完,即使加再多的机器和线程也是杯水车薪,而Fast-Retry正是为这种场景而生。

Fast-Retry

一个高性能的多任务重试框架,支持百万级任务的异步重试、以及支持编程式和注解声明式等多种使用方式、 也支持自定义结果重试逻辑。

What is this?

与主流的Spring-Retry、Guava-Retry等单任务同步重试框架不同,Fast-Retry是一个支持异步重试框架,支持异步任务的重试、超时等待、回调。

Spring-Retry、Guava-Retry均无法支持大批量任务的重试,即使加入线程池也无法解决,因为实际每个重试任务都是单独的同步逻辑,然后会会占用过多线程资源导致大量任务在等待处理,随着任务数的增加,系统吞吐量大大降低,性能指数级降低,而Fast-Retry在异步重试下的性能是前者的指数倍。

下图是三者的性能对比

  • 测试线程池: 8个固定线程

  • 单个任务逻辑: 轮询5次,隔2秒重试一次,总耗时10秒

  • 未测预计公式:当我们使用线程池的时候, 一般线程池中 总任务处理耗时 = 任务数/并发度 x 单个任务重试耗时

图片

图片

可以看到即使是处理100万个任务,Fast-Retry的性能也比Spring-Retry和Guava-Retry处理在50个任务时的性能还要快的多的多属实降维打击,这么快的秘密在于除了是异步,重要的是当别人在重试间隔里休息的时候,Fast-Retry还在不停忙命的工作着。

即使抛开性能不谈,SpringRetry使用繁琐,不支持根据结果的进行重试,GuavaRetry虽然支持,但是又没有提供注解声明式的使用。

快速开始

引入依赖

<dependency><groupId>io.github.burukeyou</groupId><artifactId>fast-retry-all</artifactId><version>0.2.0</version>
</dependency>

有以下三种方式去构建我们的重试任务

使用重试队列

RetryTask就是可以配置我们重试任务的一些逻辑,比如怎么重试,怎么获取重试结果,隔多久后重试,在什么情况下重试。它可以帮助我们更加自由的去构建重试任务的逻辑。但如果只是简单使用,强烈建议使用FastRetryBuilder 或者 @FastRetry注解

RetryQueue就是一个执行和调度我们重试任务的核心角色,其在使用上与线程池的API方法基本一致

ExecutorService executorService = Executors.newFixedThreadPool(8);
RetryQueue queue = new FastRetryQueue(executorService);
RetryTask<String> task = new RetryTask<String>() {int result = 0 ;// 下一次重试的间隔@Overridepublic long waitRetryTime() {return 2000;}// 执行重试,每次重试回调此方法@Overridepublic boolean retry() {return ++result < 5;}// 获取重试结果@Overridepublic String getResult() {return  result + "";}
};
CompletableFuture<String> future = queue.submit(task);
log.info("任务结束 结果:{}",future.get());

使用FastRetryBuilder

底层还是使用的RetryQueue去处理, 只是帮我们简化了构建RetryTask的逻辑

RetryResultPolicy<String> resultPolicy = result -> result.equals("444");
FastRetryer<String> retryer = FastRetryBuilder.<String>builder().attemptMaxTimes(3).waitRetryTime(3, TimeUnit.SECONDS).retryIfException(true).retryIfExceptionOfType(TimeoutException.class).exceptionRecover(true).resultPolicy(resultPolicy).build();CompletableFuture<String> future = retryer.submit(() -> {log.info("重试");//throw new Exception("test");//int i = 1/0;if (0 < 10){throw new TimeoutException("test");}return "444";
});String o = future.get();
log.info("结果{}", o);

使用@FastRetry注解

底层还是使用的RetryQueue去处理, 只是帮我们简化了构建RetryTask的逻辑,并且与Spring进行整合能对Spring的bean标记了FastRetry注解的方法进行代理, 提供了重试任务注解声明式的使用方式

  • 依赖Spring环境,所以需要在Spring配置类加上@EnableFastRetry注解启用配置,这个@FastRetry注解的使用才会生效

  • 如果将结果类型使用CompletableFuture包装,自动进行异步轮询返回,否则同步阻塞等待重试结果。(推荐)

下面定义等价于RetryQueue.execute方法

// 如果发生异常,每隔两秒重试一次@FastRetry(retryWait = @RetryWait(delay = 2))public String retryTask(){return "success";}

下面定义等价于 RetryQueue.submit方法,支持异步轮询

@FastRetry(retryWait = @RetryWait(delay = 2))
public CompletableFuture<String> retryTask(){return CompletableFuture.completedFuture("success");
}

自定义重试注解

如果不喜欢或者需要更加通用化的贴近业务的重试注解,提供一些默认的参数和处理逻辑,可以自行定义一个重试注解并标记上@FastRetry并指定factory,然后实现AnnotationRetryTaskFactory接口实现自己的构建重试任务的逻辑即可。@FastRetry默认实现就是:FastRetryAnnotationRetryTaskFactory

使用建议

无论是使用以上哪种方式去构建你的重试任务,都建议使用异步重试的方法,即返回结果是CompletableFuture的方法, 然后使用CompletableFuturewhenComplete方法去等待异步重试任务的执行结果。

其他

github项目地址

https://github.com/burukeYou/fast-retry

maven仓库地址

https://central.sonatype.com/artifact/io.github.burukeyou/fast-retry-all

 福利:

扫码回复【图书】可免费领取图书管理系统源码

图片

这篇关于Fast-Retry:一个支持百万级多任务异步重试框架【送源码】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1031808

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Spring使用@Retryable实现自动重试机制

《Spring使用@Retryable实现自动重试机制》在微服务架构中,服务之间的调用可能会因为一些暂时性的错误而失败,例如网络波动、数据库连接超时或第三方服务不可用等,在本文中,我们将介绍如何在Sp... 目录引言1. 什么是 @Retryable?2. 如何在 Spring 中使用 @Retryable

Python使用asyncio实现异步操作的示例

《Python使用asyncio实现异步操作的示例》本文主要介绍了Python使用asyncio实现异步操作的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录1. 基础概念2. 实现异步 I/O 的步骤2.1 定义异步函数2.2 使用 await 等待异

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核

Python中的异步:async 和 await以及操作中的事件循环、回调和异常

《Python中的异步:async和await以及操作中的事件循环、回调和异常》在现代编程中,异步操作在处理I/O密集型任务时,可以显著提高程序的性能和响应速度,Python提供了asyn... 目录引言什么是异步操作?python 中的异步编程基础async 和 await 关键字asyncio 模块理论

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte