原文地址: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 公平分发和消息接收确认(转载)的更多相关文章

  1. (六)RabbitMQ消息队列-消息任务分发与消息ACK确认机制(PHP版)

    原文:(六)RabbitMQ消息队列-消息任务分发与消息ACK确认机制(PHP版) 在前面一章介绍了在PHP中如何使用RabbitMQ,至此入门的的部分就完成了,我们内心中一定还有很多疑问:如果多个消 ...

  2. RabbitMQ:消息发送确认 与 消息接收确认(ACK)

    默认情况下如果一个 Message 被消费者所正确接收则会被从 Queue 中移除 如果一个 Queue 没被任何消费者订阅,那么这个 Queue 中的消息会被 Cache(缓存),当有消费者订阅时则 ...

  3. RabbitMQ消息队列(六)-消息任务分发与消息ACK确认机制(.Net Core版)

    在前面一章介绍了在.Net Core中如何使用RabbitMQ,至此入门的的部分就完成了,我们内心中一定还有很多疑问:如果多个消费者消费同一个队列怎么办?如果这几个消费者分任务的权重不同怎么办?怎么把 ...

  4. 【python】-- RabbitMQ 队列消息持久化、消息公平分发

    RabbitMQ 队列消息持久化 假如消息队列test里面还有消息等待消费者(consumers)去接收,但是这个时候服务器端宕机了,这个时候消息是否还在? 1.队列消息非持久化 服务端(produc ...

  5. rabbitMQ学习笔记(三) 消息确认与公平调度消费者

    从本节开始称Sender为生产者 , Recv为消费者   一.消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将 ...

  6. RabbitMQ简单应用の公平分发(fair dipatch)

    公平分发(fair dipatch)和轮询分发其实基本一致,只是每次分发的机制变了,由原来的平均分配到现在每次只处理一条消息 1.MQ连接工厂类Connection package com.mmr.r ...

  7. RabbitMQ基本用法、消息分发模式、消息持久化、广播模式

    RabbitMQ基本用法 进程queue用于同一父进程创建的子进程间的通信 而RabbitMQ可以在不同父进程间通信(例如在word和QQ间通信) 示例代码 生产端(发送) import pika c ...

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

    1.什么是RabbitMQ工作队列 我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据.因此如果一 ...

  9. RabbitMQ的轮询模式和公平分发

    一.常用的消息模式 我们在工作的使用中,经常会遇到多个消费者监听同一个队列的情况,模型如下图所示: 当有多个消费者时,我们的消息会被哪个消费者消费呢,我们又该如何均衡消费者消费信息的多少呢: 主要有两 ...

随机推荐

  1. Dapper存储过程以及多次查询和批量写入操作

    一.存储过程操作 1. 准备存储过程 newsreturnvalue(该存储过程计算2个参数的和并返回) USE [ZPC.Contact] GO SET ANSI_NULLS ON GO SET Q ...

  2. Learning to Rank:pointwise, pairwise, listwise 总结

    值得看: 刘铁岩老师的<Learning to Rank for Information Retrieval>和李航老师的<Learning to rank for informat ...

  3. 解决ffmpeg执行报错“ffmpeg: error while loading shared libraries: libavdevice.so.58: cannot open shared object file: No such file or directory”的问题

    问题现象: 执行ffmpeg命令后报错: ffmpeg: error : cannot open shared object file: No such file or directory 出问题的环 ...

  4. docker下部署服务

    一.zabbix部署 需求: 因最近项目过多,人力监控耗费时间,打算部署一个zabbix,但又不想部署在宿主机上,就想起了docker,docker快速的移植性是最大的亮点,好了,言归正传开始干. 部 ...

  5. IOS IAP APP内支付 Java服务端代码

    IOS IAP APP内支付 Java服务端代码   场景:作为后台需要为app提供服务,在ios中,app内进行支付购买时需要进行二次验证. 基础:可以参考上一篇转载的博文In-App Purcha ...

  6. Linux下安装redis 3.0及C语言中客户端实现demo

    1.获取安装文件 wget http://download.redis.io/redis-stable.tar.gz 2.解压文件 tar xzvf redis-stable.tar.gz 3.进入目 ...

  7. yii2中 选择布局的方式,可以设置不使用布局

    ###yii2中 选择布局的方式,可以设置不使用布局 控制器内成员变量 public $layout = false; //不使用布局 public $layout = "main" ...

  8. Centos7.3 安装MYSQL

    安装mysql         1.进入到要存放安装包的位置             mkdir /home/lnmp             cd /home/lnmp         2.查看系统 ...

  9. web服务器/HTTP协议基础

    1.http协议:一种规范和约定,实现客户端和服务器的通信2.http请求格式:请求行+请求头+请求体 请求行:method + request-URI + http-version 方法+请求的资源 ...

  10. Python标准库之sched模块介绍

    sched——通用时间调度器 sched模块实现了一个通用事件调度器,在调度器类使用一个延迟函数等待特定的时间,执行任务.同时支持多线程应用程序,在每个任务执行后会立刻调用延时函数,以确保其他线程也能 ...