rabbitmq 公平分发和消息接收确认(转载)

原文地址:http://www.jianshu.com/p/f63820fe2638

当生产者投递消息到broker,rabbitmq把消息分发到消费者。 如果设置了autoAck=true 消费者会自动确认收到信息。这时broker会立即将消息删除,这种情况下如果消费者出现异常(连接中断)该消息就会丢失。为了保证消息能够被正确的消费,rabbitmq支持消息确认。


String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;

sender:


public class Send {

private final static String QUEUE_NAME = "hello";

public static void main(String[] argv) throws Exception {

ConnectionFactory factory = new ConnectionFactory();

factory.setHost("localhost");

Connection connection = factory.newConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(QUEUE_NAME, false, false, false, null);

String message = "Hello World!kkkkkkkkkkkkkk";

channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));

System.out.println(" [x] Sent ‘" + message + "‘");

channel.close();

connection.close();

}

}

receive:


public class Receive {

private final static String QUEUE_NAME = "hello";

public static void main(String[] argv) throws Exception {

ConnectionFactory factory = new ConnectionFactory();

factory.setHost("localhost");

Connection connection = factory.newConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(QUEUE_NAME, false, false, false, null);

System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

// channel.basicQos(1);//使得每个Consumer在同一个时间点最多处理一个Message。在接收到该Consumer的ack前,不会将新的Message分发给它

Consumer consumer = new DefaultConsumer(channel) {

@Override

public void handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException {

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

String message = new String(body, "UTF-8");

System.out.println(" [x] Received ‘" + message + "‘");

// channel.basicAck(envelope.getDeliveryTag(), false);

}

};

channel.basicConsume(QUEUE_NAME, false, consumer);

}

}

启动sender 发送3消息:

rabbitmq 中有了两条消息记录:

启动消费者:

channel.basicConsume(QUEUE_NAME, false, consumer);

消费者没有确认消息被消费,消息一直留在队列中,只有当从有新的消费者加入时,消息被分发到新的消费者。如果由于连接中断,消费者退出时,那么消息会被轮训分发到其余的消费者。

公平分发

rabbitmq 是以轮训的方式进行分发消息,将N个消息发到n个消费者,这样有可能出现某些消费者要处理一些耗时的消息堆积在那里,而有些消费者处理很简单的消息,无事可做。为了我解决这个问题我们可以使用:

channel.basicQos(1)

关于消息确认的疑问

"ACK机制可以保证消费者如果拿了队列的消息,处理出错了,那么队列中还有这个消息,仍然可以给下个机子来跑。但是,个人觉得一般处理消息出错都是因为代码逻辑或者出bug,即使 队列中后来仍然保留该消息,然后再给某一个消费者消费,不还是报错吗?
Ps:当然,如果一个机子宕掉,消息还有,还可以给另外的机子用,这种情景下 ACK 是很有用的。但是个人觉得这种应该是少数情况吧。"
官方介绍:
https://www.rabbitmq.com/confirms.html
consumer 做了一个ACK是为了告诉broker该条消息已经被消费,broker如果没有收到acknowledgment 会一直保存该信息,不会分发给其他的consumer,指导当前的consumer 发生异常断开连接 broker 才会将该条消息发送给其他的consumer.所以你的 consumer 代码必须能够处理各种异常,确保只要收到一条消息,最终一定能够执行一条 ACK / NACK。

它使得每个Consumer在同一个时间点最多处理一个Message。在接收到该Consumer的ack前,不会将新的Message分发给它。这样就以保证等消费者处理完数据之后才会发送改消息给该消费者。但是这样也可能会使得所有的消息积压在rabbitmq中。

关于上面这个疑问的解释:

首先你弄错了 acknowledgment(翻译:承认,承认书,感谢;)的目的。acknowledgment 是 consumer 告诉 broker 当前消息是否成功 consume,至于 broker 如何处理 NACK,取决于 consumer 是否设置了 requeue:如果 requeue=False,那么 NACK 后 broker 是会删除消息的。看看 RabbitMQ 官方的解释。Consumer 做一个 ACK,是为了告诉 Broker 这条消息已经被成功处理了(transaction committed)。只要没收到 consumer 的 acknowledgment,broker 就会一直保存着这条消息(但不会 requeue,更不会分配给其他 consumer,直到当前 consumer 发生断开连接之类的异常)。RabbitMQ 之所以是 guaranteed delivery,这是一个关键。换言之,你的 consumer 代码必须能够处理各种异常,确保只要收到一条消息,最终一定能够执行一条 ACK / NACK(当然也没人阻止你设置 no_ack=True,干脆不用 acknowledgment 机制,这个视业务需求而定)。

个人理解:也就是说,并非当前consumer没有ask,broker就会把消息发送给下一个consumer,而是当前consumer故障无应答才会发送给下一个consumer,如果只是没有接收到ask,那么broker就会一直保存着这个消息等待应答,同时不再发送消息给这个consumer。这样才是正确的逻辑,我的理解,应该要避免autoAck,在处理完这个消息之后再ask,之后才会接收下一个消息进行处理,否则处理还没有完成就接收下一个消息,会造成消息在应用服务器挤压,而不是在消息队列挤压。所以正确的接收方法是,配置多个consumer,然后每个consumer处理完消息之后再ask。

作者:roye9
链接:http://www.jianshu.com/p/f63820fe2638
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间: 2024-08-28 10:10:16

rabbitmq 公平分发和消息接收确认(转载)的相关文章

RabbitMQ消息确认机制—消息发送确认和 消息接收确认

/** * RabbitMQ消息确认机制 * 关于rabbit的生产和消费方的一些实用的操作: * producer的confirm和consumer的ack,这两者使用的模式都是用来保证数据完整性,防止数据丢失 */ /** * producer的confirm模式 * 业务场景描述: * 促销系统在做活动前,需要给用户的手机发送一条活动内容短信希望用户来参加, * 因为用户量有点大,所以通过往短信mq中插入数据方式,让短信服务来消费mq发短信: * 此时插入mq消息的服务为了保证给所有用户发

RabbitMQ学习第二记:工作队列的两种分发方式,轮询分发(Round-robin)和 公平分发(Fair dispatch)

1.什么是RabbitMQ工作队列 我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据.因此如果一个生产者对应一个消费者的话,很容易导致很多消息堆积在队列里.这时,就得使用工作队列了.一个队列有多个消费者同时消费数据. 下图取自于官方网站(RabbitMQ)的工作队列的图例 P:消息的生产者 C1:消息的消费者1 C2:消息的消费者2 红色:队列 生产者将消息发送到队列,多个消费者同时从队列中获

ActiveMQ(16):Message Dispatch的分发策略、消息批量确认和生产者流量控制

一.分发策略(Dispatch Policies) 1.1 严格顺序分发策略(Strict Order Dispatch Policy) 通常ActiveMQ会保证topic consumer以相同的顺序接收来自同一个producer的消息,但有时候也需要保证不同的topic consumer以 相同的顺序接收消息,然而,由于多线程和异步处理,不同的topic consumer可能会以不同的顺序接收来自不同producer的消息. Strict order dispatch policy会保证每

rabbitmq 学习-9- RpcClient发送消息和同步接收消息原理

rabbitmq 学习-9- RpcClient发送消息和同步接收消息原理

【RabbitMQ】5、RabbitMQ任务分发机制

当有Consumer需要大量的运算时,RabbitMQ Server需要一定的分发机制来balance每个Consumer的load.接下来我们分布讲解. 应用场景就是RabbitMQ Server会将queue的Message分发给不同的Consumer以处理计算密集型的任务: 1. Message acknowledgment 消息确认 每个Consumer可能需要一段时间才能处理完收到的数据.如果在这个过程中,Consumer出错了,异常退出了,而数据还没有处理完成,那么 非常不幸,这段数

RabbitMQ实战:理解消息通信

本系列是「RabbitMQ实战:高效部署分布式消息队列」书籍的总结笔记. 前段时间总结完了「深入浅出MyBatis」系列,对MyBatis有了更全面和深入的了解,在掘金社区也收到了一些博友的喜欢,很高兴.另外,短暂的陪产假就要结束了,小宝也二周了,下周二就要投入工作了,希望自己尽快调整过来,加油努力. 从本篇开始总结「RabbitMQ实战」系列的阅读笔记,RabbitMQ是一个开源的消息代理和队列服务器,可以通过基本协议在完全不同的应用之间共享数据,可以将作业排队以便让分布式服务进行处理. 本篇

Python实现RabbitMQ中6种消息模型

RabbitMQ与Redis对比 ? RabbitMQ是一种比较流行的消息中间件,之前我一直使用redis作为消息中间件,但是生产环境比较推荐RabbitMQ来替代Redis,所以我去查询了一些RabbitMQ的资料.相比于Redis,RabbitMQ优点很多,比如: 具有消息消费确认机制 队列,消息,都可以选择是否持久化,粒度更小.更灵活. 可以实现负载均衡 RabbitMQ应用场景 异步处理:比如用户注册时的确认邮件.短信等交由rabbitMQ进行异步处理 应用解耦:比如收发消息双方可以使用

RabbitMQ介绍2 - 理解消息AMQP

理解消息AMQP通信.官方解释: http://www.rabbitmq.com/tutorials/amqp-concepts.html 概念:生产者producer,消费者consumer,队列queue,交换器exchange,路由键routing key,绑定键binding key. producer发布消息,消息经过交换器传播放入队列,消费者从队列中得到消息. ConnectionFactory, connection, channel信道.connectionFactory用来建立

【RabbitMQ】如何进行消息可靠投递【上篇】

说明 前几天,突然发生线上报警,钉钉连发了好几条消息,一看是RabbitMQ相关的消息,心头一紧,难道翻车了? [橙色报警]?应用[xxx]在[08-15?16:36:04]发生[错误日志异常],alertId=[xxx].由[org.springframework.amqp.rabbit.listener.BlockingQueueConsumer:start:620]触发. 应用xxx?可能原因如下 服务名为: ?异常为:org.springframework.amqp.rabbit.lis