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
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
rabbitmq 公平分发和消息接收确认(转载)的更多相关文章
- (六)RabbitMQ消息队列-消息任务分发与消息ACK确认机制(PHP版)
原文:(六)RabbitMQ消息队列-消息任务分发与消息ACK确认机制(PHP版) 在前面一章介绍了在PHP中如何使用RabbitMQ,至此入门的的部分就完成了,我们内心中一定还有很多疑问:如果多个消 ...
- RabbitMQ:消息发送确认 与 消息接收确认(ACK)
默认情况下如果一个 Message 被消费者所正确接收则会被从 Queue 中移除 如果一个 Queue 没被任何消费者订阅,那么这个 Queue 中的消息会被 Cache(缓存),当有消费者订阅时则 ...
- RabbitMQ消息队列(六)-消息任务分发与消息ACK确认机制(.Net Core版)
在前面一章介绍了在.Net Core中如何使用RabbitMQ,至此入门的的部分就完成了,我们内心中一定还有很多疑问:如果多个消费者消费同一个队列怎么办?如果这几个消费者分任务的权重不同怎么办?怎么把 ...
- 【python】-- RabbitMQ 队列消息持久化、消息公平分发
RabbitMQ 队列消息持久化 假如消息队列test里面还有消息等待消费者(consumers)去接收,但是这个时候服务器端宕机了,这个时候消息是否还在? 1.队列消息非持久化 服务端(produc ...
- rabbitMQ学习笔记(三) 消息确认与公平调度消费者
从本节开始称Sender为生产者 , Recv为消费者 一.消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将 ...
- RabbitMQ简单应用の公平分发(fair dipatch)
公平分发(fair dipatch)和轮询分发其实基本一致,只是每次分发的机制变了,由原来的平均分配到现在每次只处理一条消息 1.MQ连接工厂类Connection package com.mmr.r ...
- RabbitMQ基本用法、消息分发模式、消息持久化、广播模式
RabbitMQ基本用法 进程queue用于同一父进程创建的子进程间的通信 而RabbitMQ可以在不同父进程间通信(例如在word和QQ间通信) 示例代码 生产端(发送) import pika c ...
- RabbitMQ学习第二记:工作队列的两种分发方式,轮询分发(Round-robin)和 公平分发(Fair dispatch)
1.什么是RabbitMQ工作队列 我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据.因此如果一 ...
- RabbitMQ的轮询模式和公平分发
一.常用的消息模式 我们在工作的使用中,经常会遇到多个消费者监听同一个队列的情况,模型如下图所示: 当有多个消费者时,我们的消息会被哪个消费者消费呢,我们又该如何均衡消费者消费信息的多少呢: 主要有两 ...
随机推荐
- [转帖]18W喂不饱有必要买30W充电器吗?iPhone 11 Pro Max充电评测
18W喂不饱有必要买30W充电器吗?iPhone 11 Pro Max充电评测 https://www.cnbeta.com/articles/tech/895237.htm 改天买一个 设备玩一玩 ...
- 【CodeForces】1172E. Nauuo and ODT
题解 看了一遍题解(以及代码)但是没写代码-- 后来做梦的时候忽然梦到了这道题--意识到我需要补一下-- 这道题就是,对于每种颜色,把没有染成这种颜色的点标成黑点,然后计算每个联通块的平方 然后每个点 ...
- Win10 鼠标右键新建菜单添加自定义文件
1. 引言 在鼠标右键(右单机)新建菜单中添加自定义文件,例如:写字板,markdown等. 效果图: 2. 操作步骤(以Win10为例) 1. win+R输入regedit进入注册表 2. 这里以添 ...
- laravel6.0路由
1.基本路由路由定义在routes目录下,路由执行是在控制器之前,路由路径 routes目录下api.php 关于接口路由定义文件包含的路由位于 api 中间件组约束之内,支持频率限制功能,这些路由是 ...
- MongoDB 正则表达式查询
正则表达式查询 $regex 注:^ 取反的意思 用特殊的转义字符需要在前面加一个斜杠 通过 ^取反 ,再通过$not取反,就可获得只包含一种类型的数据 \\d 数字 \\s 空格 \\ ...
- java之集合那些事
集合概述: 集合和数组都可以保存多个对象,但是数组的长度不可变,集合可以保存数量变化的数据.java中的集合类主要由两个接口派生出,Collection和Map Collection接口和Iterat ...
- IOS+H5页面自定义按钮无效
在IOS整合H5页面的时候,自定义的按钮失去效果,Android系统可以. 如图,确定和取消按钮在IOS系统无效. 解决办法是在两个按钮上加上一个style属性即可 <span class=&q ...
- hdu 1875 最小生成树 prime版
最小生成树prime版 大致的步骤 首先选取一个到集合最近的点 然后标记起在集合内部 然后更新最短距离 畅通工程再续 Time Limit: 2000/1000 MS (Java/Others) ...
- (九) spring 使用自定义限定符注解
案例一 定义接口 CD.java package interfacepackage; public interface CD { void play(); } 定义接口 player .java p ...
- Java 面向对象(一)面向对象思想
一.面向对象思想 1.概述 Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计.开发计算机程序. 这里的对象泛指现实中一切事 ...