在本文中,我们将学习如何使用Spring Boot 2.x和Redis执行异步任务,最后的代码演示了本文中描述的步骤。
您可能还会喜欢:Spring和线程:异步
Spring/Spring Boot
Spring是可用于Java应用程序开发的最流行的框架。因此,Spring拥有最大的开源社区之一。除此之外,Spring在其博客上提供了广泛而最新的文档,涵盖了框架的内部工作原理和示例项目-StackOverflow上有10万多个问题。
在早期,Spring仅支持基于XML的配置,因此,它很容易受到批评。后来,Spring引入了基于注释的配置,该配置更改了所有内容。Spring 3.0是第一个支持基于注释的配置的版本。2014年,发布了Spring Boot 1.0,彻底改变了我们对Spring框架生态系统的看法。可以在此处找到更详细的时间表。
Redis Redis是最流行的NoSQL内存数据库之一。Redis支持不同类型的数据结构。Redis支持不同类型的数据结构,例如集合,哈希表,列表,简单的键-值对,仅举几例。Redis调用和操作的延迟为bot亚毫秒级,这使其在开发人员社区中更具吸引力。
为什么要执行异步任务 一个典型的API调用包括五件事:
出于多种原因,可以在以后的某个时间安排任务。例如,必须在订单创建或装运后7天生成发票。同样,不需要立即发送电子邮件通知,因此我们可以延迟它们。
考虑到这些实际示例,有时,我们需要异步执行任务以减少API响应时间。例如,我们收到一个立即删除1K +记录的请求,如果我们在同一API调用中删除所有这些记录,那么肯定会增加API响应时间。为了减少API响应时间,我们可以在后台运行一个任务,以删除这些记录。
Delayed Queue 每当我们计划任务以给定时间或特定间隔运行时,我们就会使用计划在特定时间或间隔进行的cron作业。我们可以使用UNIX风格的crontabs,Chronos等其他工具来运行计划任务。如果我们使用的是Spring框架,则可以使用现成的Scheduled注释。
大多数cron作业会查找何时需要采取特定措施的记录,例如,在7天后查找所有发货以及未生成发票的记录。这些调度机制中的大多数都存在缩放问题,我们在其中扫描数据库以查找相关的行/记录。在许多情况下,这会导致全表扫描表现很差 想象一下实时应用程序和此批处理系统使用相同数据库的情况。由于它不可扩展,因此我们需要一些可扩展的系统,该系统可以在给定的时间或间隔执行任务,而不会出现任何性能问题。有许多以这种方式扩展的方法,例如以批处理方式运行任务或在用户/区域的特定子集上运行任务。另一种方法是在给定时间运行特定任务,而不依赖于其他任务,例如无服务器功能。一个延迟队列可以的情况下,一旦定时器达到预定时间的作业将被触发使用。有许多可用的排队系统/软件,但很少有提供此功能的系统,例如SQS 它提供15分钟的延迟,而不是7个小时或7天之类的任意延迟。
Rqueue Rqueue是为Spring框架构建的消息代理,该代理将数据存储在Redis中,并提供了一种在任意延迟下执行任务的机制。由于Redis与其他广泛使用的排队系统(例如Kafka或SQS)相比,具有一些优势,因此Rqueue得到了Redis的支持。在大多数Web应用程序的后端中,Redis用于存储缓存的数据或其他目的。在当今世界上,有8.4% 的Web应用程序正在使用Redis数据库。
通常,对于队列,我们使用Kafka,SQS或其他一些系统。这些系统带来了不同维度的额外开销,例如,使用Rqueue和Redis可以将金钱减少为零。
除了成本外,如果我们使用Kafka,那么我们需要进行基础架构设置,维护,即需要更多操作,因为大多数应用程序已经在使用Redis,因此我们不会有操作开销。实际上,相同的Redis服务器/群集可与Rqueue一起使用,因为 Rqueue支持任意延迟。
Message Delivery Rqueue保证至少一次发送消息,因为长时间的数据不会在数据库中丢失。您可以在这里阅读更多有关此内容:Rqueue简介。
我们将需要的工具:
为了简单起见,我们将使用 Spring Boot 。我们将从https://start.spring.io/的Spring Boot初始化程序创建一个Gradle项目。
对于依赖关系,我们将需要:
目录/文件夹结构如下所示:
我们将使用Rqueue库以任意延迟执行任何任务。Rqueue是基于Spring的异步任务执行器,可以在任何延迟下执行任务。它是由Spring消息传递库构建的,并由Redis支持。
我们将添加Rqueue Spring Boot starter 2.7.0依赖项:
com.github.sonus21:rqueue-spring-boot-starter:2.7.0-RELEASE
dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.github.sonus21:rqueue-spring-boot-starter:2.0.0-RELEASE' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } }
出于测试目的,我们将启用Spring Web MVC功能,以便我们可以发送测试请求。
如下所示更新应用程序文件:
@SpringBootApplication @EnableRedisRepositories @EnableWebMvc public class AsynchronousTaskExecutorApplication { public static void main(String[] args) { SpringApplication.run(AsynchronousTaskExecutorApplication.class, args); } }
使用Rqueue添加侦听器非常简单。这就像用注释方法一样简单RqueueListener。该RqueuListener注释具有可根据使用情况来设置多个领域。对于死信队列,设置deadLetterQueue为将任务推送到另一个队列,否则,任务将在失败时被丢弃。我们还可以使用该字段设置任务应重试多少次。 numRetries
创建一个名为的Java文件,MessageListener并添加一些方法以在后台执行消息:
@Component @Slf4j public class MessageListener { @RqueueListener(value = "${email.queue.name}") public void sendEmail(Email email) { log.info("Email {}", email); } @RqueueListener(value = "${invoice.queue.name}") public void generateInvoice(Invoice invoice) { log.info("Invoice {}", invoice); } }
我们将需要Email和Invoice类来分别存储电子邮件和发票数据。为简单起见,类仅包含少数几个字段。
Invoice.java:
import lombok.Data; @Data @AllArgsConstructor @NoArgsConstructor public class Invoice { private String id; private String type; }
Email.java:
import lombok.Data; @Data @AllArgsConstructor @NoArgsConstructor public class Email { private String email; private String subject; private String content; }
任务提交 可以使用RqueueMessageEnqueuer Bean提交任务。有多种方法可以使任务排队,具体取决于用例,请使用一种可用方法。对于简单任务,请使用延迟任务。 RqueueMessageEnqueuerenqueueenqueueIn
我们需要自动连线RqueueMessageEnqueuer或使用构造函数来注入此bean。
这是创建用于测试目的的Controller的方法。
我们将计划在30秒内完成发票生成。为此,我们将在发票队列中提交延迟为30000(毫秒)的任务。另外,我们将尝试发送可以在后台执行的电子邮件。为此,我们将添加两个GET方法,sendEmail和; 我们也可以使用POST。 generateInvoice
@RestController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @Slf4j public class Controller { private @NonNull RqueueMessageEnqueuer rqueueMessageEnqueuer; @Value("${email.queue.name}") private String emailQueueName; @Value("${invoice.queue.name}") private String invoiceQueueName; @Value("${invoice.queue.delay}") private Long invoiceDelay; @GetMapping("email") public String sendEmail( @RequestParam String email, @RequestParam String subject, @RequestParam String content) { log.info("Sending email"); rqueueMessageEnqueuer.enqueue(emailQueueName, new Email(email, subject, content)); return "Please check your inbox!"; } @GetMapping("invoice") public String generateInvoice(@RequestParam String id, @RequestParam String type) { log.info("Generate invoice"); rqueueMessageEnqueuer.enqueueIn(invoiceQueueName, new Invoice(id, type), invoiceDelay); return "Invoice would be generated in " + invoiceDelay + " milliseconds"; } }
在·application.properties·文件中添加以下内容:
email.queue.name=email-queue invoice.queue.name=invoice-queue # 30 seconds delay for invoice invoice.queue.delay=300000
现在该启动Spring Boot应用程序了。应用程序成功启动后,请点击以下链接以发送电子邮件。
http:// localhost:8080 / email?[email protected]&subject=%22test%20email%22&content=%22testing%20email%22
在日志中,我们可以看到电子邮件任务正在后台执行:
Below is our invoice scheduling after 30 seconds:
http://localhost:8080/invoice?id=INV-1234&type=PROFORMA
结论 现在,我们可以使用Rqueue计划任务,而无需太多样板代码!在配置和使用Rqueue库时,我们进行了重要考虑。要记住的重要一件事是,默认情况下,无论任务是延迟任务还是非延迟任务,都假定需要尽快执行任务。
原文链接:https://codingdict.com/