Java RabbitMQ:快速生产者和慢速消费者
我有一个应用程序,它使用RabbitMQ作为消息队列在两个组件之间发送/接收消息:发送方和接收方。发送者以非常快的方式发送消息。接收方接收消息,然后执行一些非常耗时的任务(主要是为非常大的数据量编写数据库)。由于接收者需要很长时间来完成任务,然后检索队列中的下一条消息,因此发送者将继续快速填充队列。所以我的问题是:这会导致消息队列溢出吗 消息使用者如下所示:Java RabbitMQ:快速生产者和慢速消费者,java,multithreading,rabbitmq,amqp,producer-consumer,Java,Multithreading,Rabbitmq,Amqp,Producer Consumer,我有一个应用程序,它使用RabbitMQ作为消息队列在两个组件之间发送/接收消息:发送方和接收方。发送者以非常快的方式发送消息。接收方接收消息,然后执行一些非常耗时的任务(主要是为非常大的数据量编写数据库)。由于接收者需要很长时间来完成任务,然后检索队列中的下一条消息,因此发送者将继续快速填充队列。所以我的问题是:这会导致消息队列溢出吗 消息使用者如下所示: public void onMessage() throws IOException, InterruptedException {
public void onMessage() throws IOException, InterruptedException {
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
String queueName = channel.queueDeclare("allDataCase", true, false, false, null).getQueue();
channel.queueBind(queueName, EXCHANGE_NAME, "");
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
JSONObject json = new JSONObject(message);
String caseID = json.getString("caseID");
//following takes very long time
dao.saveToDB(caseID);
}
}
消费者收到的每条消息都包含一个caseID。对于每个caseID,它会将大量数据保存到数据库中,这需要很长时间。目前,RabbitMQ只设置了一个使用者,因为生产者/使用者对caseID的发布/订阅使用相同的队列。那么,我如何加快使用者吞吐量,以便使用者能够赶上生产者并避免队列中的消息溢出呢?我应该在消费者部分使用多线程来加速消费率吗?或者我应该使用多个消费者同时消费传入的消息吗?或者,是否有任何异步方式可以让使用者在不等待消息完成的情况下异步使用消息?欢迎提出任何建议 “那么我如何加快消费者吞吐量,使消费者能够赶上生产者,避免队列中的消息溢出?”这是答案“使用多个消费者同时消费传入消息”,使用多线程并行运行这些消费者实现无共享原则,作为回答,我建议:两者都要 您可以利用拥有多个接收者的优势,以及将每个接收者设置为在单独的线程中执行任务,从而允许接收者接受队列中的下一条消息
当然,这种方法假设每个操作的结果(如果我理解正确的话,在db上的写入)不会以任何方式影响其他消息响应的后续操作的结果。您有很多方法来提高性能
如果数据不需要立即持久化,您可以修改应用程序,以便使用者只需从队列中删除消息并将其保存到缓存的集合中,例如在Redis中。引入第二个进程,然后依次读取和处理缓存的消息。这将确保队列长度不会增长到足以导致流控制,同时防止数据库被写请求轰炸,写请求通常比读请求更昂贵。您的使用者现在只需从队列中删除消息,稍后由另一个进程处理。虽然添加更多使用者可能会加快速度,但真正的问题将保存到数据库中 这里已经有很多关于添加使用者(线程和/或机器)和更改QoS的答案,所以我不再重复。相反,您应该认真考虑使用该模式将消息聚合成一组消息,然后批量将该组插入到数据库中。 每个消息的当前代码可能会打开一个连接,插入数据,然后关闭该连接(或返回池)。更糟糕的是,它甚至可能正在使用事务 通过使用聚合器模式,您可以在刷新之前缓冲数据 现在编写一个好的聚合器是很棘手的。您需要决定如何缓冲(即每个工人都有自己的缓冲区或像Redis这样的中央缓冲区)。我相信Spring integration有一个聚合器。从中,这里有两种方法:工作队列、发布/订阅。我是我们