Spring 中的异步事件需要大量时间来执行(轮到它了)

Aks*_*hta 3 java spring asynchronous spring-mvc

我有一个应用程序,每当对端点进行 REST 调用时,我都需要在其中触发电子邮件。设计是每当调用 REST 调用时,我将数据保存在数据库中,发出一个异步事件并返回。

我的问题是,由于大量请求不断涌现,发出的异步事件在很长一段时间内都没有机会。有时,当服务器启动数周时,延迟会不断增加。

场景

  1. 服务器端点被调用
  2. 服务器将数据保存到 db,发出一个 Spring 异步事件
  3. 从端点返回

由于有时调用侦听器很晚,因此调用 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
    }
}
Run Code Online (Sandbox Code Playgroud)

由于它是一个 Async event ,JVM 给了 dataListener 很晚执行的机会。有时,较早触发的事件比之后触发的事件获得的机会晚。

所以2个基本问题

  1. 电子邮件延迟。延迟范围从 1 分钟到 4 小时到 8 天不等
  2. 如果在中午 12 点触发一个事件向 xyz@gmail.com 发送电子邮件,另一个在下午 12:15 向 abc@gmail.com 发送电子邮件,则 abc@gmail.com 有可能在 xyz@ 之前收到电子邮件gmail.com。

感谢你的帮助

sha*_*zin 6

Spring 异步事件受限于线程池的大小,一旦传入请求大于活动线程的大小,就会出现延迟。

您需要使用 RabbitMQ、Kafka 等消息队列。您的架构应该更改为执行以下操作;

  1. 使用电子邮件地址、数据库条目数据等所有信息在 REST 端点中序列化 JSON 消息,然后将该 JSON 消息存储在消息队列中并返回状态代码
  2. 消息队列(单独的 Java 应用程序)必须有消费者,它们在消息队列中有数据时轮询或得到通知。
  3. 这些消费者应该反序列化 JSON 消息,在数据库中保存一个条目并发送电子邮件。

使用这种架构,您可以在高负载时增加消费者,从而根据需要进行扩展。