【Java编程】一个高性能、支持百万级多任务重试框架:Fast-Retry

news/2025/1/10 0:21:58/文章来源:https://www.cnblogs.com/o-O-oO/p/18660097

前言

假设你的系统里有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() {return2000;}// 执行重试,每次重试回调此方法@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){thrownew 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的方法, 然后使用CompletableFuture的whenComplete方法去等待异步重试任务的执行结果。

其他

github项目地址

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

maven仓库地址

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

原创 数据之恋

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/865955.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac m1 安装ffmpeg,配置环境变量

1 首先要安装brew 2 git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg 3 cd ffmpeg 4 执行脚本 ./configure --prefix=/opt/local 5 编译 sudo make ,需要提权,要不系统目录无法创建文件夹 6 安装 make install 7 安装成功,查看 ffmpeg版本 /opt/local/bin/ffmpeg -ve…

如何在 LobeChat 中使用 Ollama

本文介绍了如何在LobeChat中使用Ollama框架运行本地大型语言模型。文章详细说明了在macOS、Windows和Linux操作系统下安装和配置Ollama的步骤,并指导用户如何通过Docker容器部署Ollama。此外,文章还介绍了如何在LobeChat中安装和选择Ollama模型进行对话。Ollama 是一款强大的…

密码综合实战

这种加密本质上是换汤不换药的,我们需要有所创新,下面是我的想法(key{A}和key{B}表示的是A和B独有的秘钥): 假设现在有服务器192.168.1.1,本机扮演角色A,服务器扮演角色B,进行如下逻辑:A拥有A的专属秘钥(汉字秘钥)进行一次加密发送给B,B接受到后再用B的专属秘钥再次加…

FrontEnd性能优化.md

性能优化 性能优化\浏览器渲染原理 Get Started有这样几个问题,我们来思考下:1.我们平常浏览的网页是否是应用?2.在操作系统中的应用是如何运行的3.浏览器究竟是什么4.webkit和浏览器的关系5.浏览器是如何呈现网页的6.经典问题:从浏览器的地址栏输入一个网址直到网页内容呈…

Tita OKR 应用技巧:OKR 评分

OKR 评分价值 OKR(目标与关键成果)评分主要有以下几方面价值: 一、目标管理方面明确目标完成程度OKR评分可以直观地展现目标的达成情况。例如,一个产品团队设定了提升用户满意度的目标,通过OKR评分,可以清楚地看到用户满意度指标从初始的60%提升到了75%还是80%等具体数值…

ArmSoM RK3588/RK3576核心板,Rockchip Display 使用

1. Display简介​ RK3588 的VOP (video output process)分为4个Port:port分辨率VP0 4KVP1 4KVP2 4KVP3 1080PRK3588 VP 和各显⽰接口的连接关系: 需要注意的是,RK3588 的 HDMI 和 DP ⽀持 8K 输出,但是在 8K 输出模式下,⼀个显⽰接口需要同时占⽤ VP0 和 VP1 。所以如果产…

JNI接口--实现Java调用C++

1、JNI原理概述 通常为了更加灵活高效地实现计算逻辑,我们一般使用C/C++实现,编译为动态库,并为其设置C接口和C++接口。用C++实现的一个库其实是一个或多个类的简单编译链产物,然后暴露其实现类的构造方法和纯虚接口类。这样就可以通过多态调用到库内部的实现类及其成员方法…

Leaflet 实现离线瓦片资源 + 飞线迁徙 + 自定义标记点位实现

npm install leaflet 注意构建webpack配置module: {rules: [{test: /\.(png|jpg|gif|jpeg|svg)$/,include: /node_modules[\\/]leaflet/,use: [{loader: url-loader,options: {outputPath: static/images}}]}] } 注意外部资源代理方式proxy: {/cdn: {target: https:// + ip + :…

Training Transformers with 4-bit Integers

目录概符号说明4-bit FQTLearned Step Size QuantizationHadamard QuantizationBit Splitting and Leverage Score Sampling代码Xi H., Li C., Chen J. and Zhu J. Training transformers with 4-bit integers. NeurIPS, 2023.概 本文针对 4-bit 中训练中一些特点 (针对 transf…

python SQLAlchemy ORM——从零开始学习 02简单的增删查改

02 简单的增删查改 前情提要:承接了01中的engine以及User类 2-1 了解会话机制个人理解 在SQLAlchemy 增删查改中是依赖会话(Session)这个机制进行操作的,我个人的理解是用“会话“进行连接数据库周期的一系列管理操作(以下是ai生成对此会话的理解)ai理解 在 SQLAlchemy 中…

YASKAWA机械手维修DX100示教器通电无反应

安川机器人DX100示教器通电无反应可能由多种原因导致,以下是一些常见的原因及对应的解决方法:可能原因电源问题:电源线破损或电源插座接触不良。 硬件故障:示教器内部电路板或元件(如内存条、处理器或显示屏等)损坏。 软件问题:软件发生错误或版本不匹配。 其他故障:…

春节电商爆单背后的协作黑科技!

每到春节,电商平台的交易额都会迎来新一轮爆发。但你是否思考过,支撑这一庞大运作的团队如何在高压之下确保高效协作?答案或许就藏在你忽略的细节里:在线文档协作。 春节购物高峰的背后:团队协作挑战重重 春节期间,消费者习惯于提前囤年货、抢促销,购物高峰往往集中爆发…