我有一个应用程序,每当对端点进行 REST 调用时,我都需要触发电子邮件。设计是每当调用 REST 调用时,我将数据保存在数据库中,发出一个异步事件并返回。
我的问题是,由于大量请求不断涌现,发出的异步事件在很长一段时间内都没有机会。有时,随着服务器运行数周,延迟不断增加。
场景
- 调用服务器端点
- 服务器将数据保存到数据库,发出一个 Spring 异步事件
- 从端点返回
调用 2 会延迟,因为有时会很晚调用监听器。
public class DataController {
@Inject
ApplicationEventPublisher eventPublisher;
@RequestMapping(value = "data", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void addData(@RequestBody DataDTO data) {
dataService.addData(data);
eventPublisher.publishEvent(new DataRequest(new DataDTO());
}
}
public class DataRequest extends ApplicationEvent {
private DataDTO dataDTO;
public DataRequest(DataDTO dataDTO) {
super(dataDTO);
this.dataDTO = dataDTO;
}
}
@Component
public class DataListener {
@EventListener
@Async
private void dataListener(DataDTO dataDTO) {
// Send email
}
}
因为它是一个异步事件,JVM 给了 dataListener 很晚执行的机会。有时 较早触发的事件比之后触发的事件获得机会晚。
所以 2 个基本问题
- 电子邮件延迟。延迟范围从 1 分钟到 4 小时到 8 天等不等
- 如果一个事件在中午 12 点触发发送电子邮件至 xyz@gmail.com,另一个事件在中午 12:15 发送电子邮件至 abc@gmail.com,则 abc@gmail.com 有可能收到电子邮件在 xyz@gmail.com 之前。
感谢您的帮助
最佳答案
Spring 异步事件受限于线程池的大小,一旦传入请求高于 Activity 线程的大小,就会出现延迟。
您需要使用 RabbitMQ、Kafka 等消息队列。您的架构应该更改为执行以下操作;
- 在 REST 端点中使用电子邮件地址、数据库条目数据等所有信息序列化 JSON 消息,并将该 JSON 消息存储在消息队列中并返回状态代码
- 消息队列(独立的 Java 应用程序)必须有消费者,当消息队列中有数据时,他们会轮询或收到通知。
- 这些消费者应该反序列化 JSON 消息,在数据库中保存一个条目并发送电子邮件。
通过这种架构,您可以在高负载时增加消费者,从而根据需要进行扩展。
关于java - Spring 中的异步事件需要大量时间来执行(轮到它了),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45273708/