rabbitmq 消息的状态转换
tutorial:http://www.rabbitmq.com/tutorials/tutorial-two-java.html
这里解释接收消息端关于 acknowledge和prefetch的设置问题
这里有两段代码,sender,负责发送100条消息; recv,负责接收消息,每接收到一条消息sleep 1 秒。
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//channel.basicQos(1,false);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try{
Thread.sleep(1000);
}catch (Exception e){ }
//channel.basicAck(envelope.getDeliveryTag(), false); }
};
channel.basicConsume(QUEUE_NAME, true, consumer);
先展示一个基础版本的recv。
运行这段代码遇到两个费解的现象
1. 先启动sender产生100条消息,后启动两个recv,发现所有消息都被第一个启动的recv接收了,第二个recv没有接收到任何消息。但如果先两个recv,再启动sender,那么两个recv是平均分配消息的。
2. 先启动sender,启动第一个recv,处理10条消息,关掉recv,再启动第二个recv,第二个recv没有消息。11~100条消息丢失了。
为了说明上面的问题,我们先描述一下一个消息在rmq server端的状态
在server端,消息进入queue后,首先是ready状态。如果有recv 消费这条消息,那么消息进入 unack 状态,当recv ack这条消息后,server端将删除消息。
现象1的解释:
先启动sender,server端有100个ready 消息。启动recv1,虽然recv1还没有来得及处理这些消息,但recv1 接收了100个消息。在server端100个消息都进入unack状态。因为我们设置的ack方式是autoack, line 20
因此所有消息立刻就从server端删除了。当我再启动recv2时,队列已经没有消息了,所以recv2没有接收到任何消息。反过来,先启动两个recv,sender生产消息的时候,server会按round robbin方式分配消息,因此两个recv各接收50条消息
现象2的解释:
因为消息都已经发送给了recv1,server端收到了ack,删除了消息,系统中只有recv1缓存了消息,如果关掉recv1,所有消息都会丢失。recv2无法拿到recv1未处理的消息。
下面我们看看改进版本。变化在于
- line 20 autoack 改为false
- line 16 每条消息处理后ack
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//channel.basicQos(1,false);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try{
Thread.sleep(1000);
}catch (Exception e){ }
channel.basicAck(envelope.getDeliveryTag(), false); }
};
channel.basicConsume(QUEUE_NAME, false, consumer);
可以发现现象1 依旧,但现象2 不同了。我们可以通过命令查看server端的状态
rabbitmqctl list_queues name messages_unacknowledged messages_ready
启动sender后 unack=0,ready=100
启动recv1 后 unack=100, ready=0,所有消息都给了recv1
等recv1 处理几条消息后 unack=89, ready=0,recv1处理并ack了11条消息,
关闭recv1 后 unack=0, ready=85,未ack的消息都回到ready状态
启动recv2,unack=89, ready =0,所有消息都转给了recv2.
如果消息量很大,那么缓存消息就可能吃掉recv的所有内存导致系统崩溃。因此我们打开 line2。这样recv在ack一个消息后才会领取下一个消息。再来看看按照上面流程queue里消息的状态
启动sender后 unack=0,ready=100
启动recv1 后,unack=1, ready=99
启动recv2后,unack=2, ready=95
在消息处理完前,unack都是2,recv1和recv2 各持有一个消息
rabbitmq 消息的状态转换的更多相关文章
- SpringCloud之RabbitMQ消息队列原理及配置
本篇章讲解RabbitMQ的用途.原理以及配置,RabbitMQ的安装请查看SpringCloud之RabbitMQ安装 一.MQ用途 1.同步变异步消息 场景:用户下单完成后,发送邮件和短信通知. ...
- RabbitMQ 消息确认机制
消息确认机制 在之前异常处理部分就已经写了,对于consumer的异常退出导致消息丢失,可以时候consumer的消息确认机制.重复的就不说了,这里说一些不一样的. consumer的消息确认机制 当 ...
- (转)RabbitMQ消息队列(九):Publisher的消息确认机制
在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...
- RabbitMQ消息队列(九):Publisher的消息确认机制
在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...
- 使用EasyNetQ组件操作RabbitMQ消息队列服务
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现,是实现消息队列应用的一个中间件,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合, ...
- RabbitMQ 消息顺序、消息幂等、消息重复、消息事务、集群
1. 消息顺序 场景:比如下单操作,下单成功之后,会发布创建订单和扣减库存消息,但扣减库存消息执行会先于创建订单消息,也就说前者执行成功之后,才能执行后者. 不保证完全按照顺序消费,在 MQ 层面支持 ...
- RabbitMQ消息队列系列教程(二)Windows下安装和部署RabbitMQ
摘要 本篇经验将和大家介绍Windows下安装和部署RabbitMQ消息队列服务器,希望对大家的工作和学习有所帮助! 目录 一.Erlang语言环境的搭建 二.RabbitMQ服务环境的搭建 三.Ra ...
- RabbitMQ消息队列(四)-服务详细配置与日常监控管理
RabbitMQ服务管理 启动服务:rabbitmq-server -detached[ /usr/local/rabbitmq/sbin/rabbitmq-server -detached ] 查看 ...
- RabbitMQ 消息队列 应用
安装参考 详细介绍 学习参考 RabbitMQ 消息队列 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. M ...
随机推荐
- uva1330 在一个大的矩阵中寻找面积最大的子矩阵
大白书 P50页 #include <algorithm> #include <cstdio> using namespace std; ; int ma[maxn][maxn ...
- linux常用命令:cal 命令
cal命令可以用来显示公历(阳历)日历.公历是现在国际通用的历法,又称格列历,通称阳历.“阳历”又名“太阳历”,系以地球绕行太阳一周为一年,为西方各国所通用,故又名“西历”. 1.命令格式: cal ...
- python webdriver 从无到有搭建数据驱动自动化测试框架的步骤和总结
一步一步搭建数据驱动测试框架的过程和总结 跟吴老学了搭建自动化数据驱动的框架后,我在自己练习的时候,尝试从简单的程序进行一点一点的扩展和优化,到实现这个数据驱动的框架. 先说一下搭建自动化测试框架的目 ...
- Linux基础命令---e2image
e2image e2Image程序将位于设备上的ext2.ext3或ext4文件系统元数据保存到由图像文件指定的文件中.通过对这些程序使用-i选项,image文件可以由dupe2fs和调试器来检查.这 ...
- PHP读取sphinx 搜索返回结果完整实战实例
PHP读取sphinx 搜索返回结果完整实战实例 网上搜索N久都没有一个正在读取返回sphinx结果的实例,都是到了matches那里就直接var_dump或者print_r了,没有读取到字段的例子, ...
- centos infiniband网卡安装配置
硬件:Mellanox InfiniBand,主要包括 HCA(主机通道适配器)和交换机两部分 软件:CentOS 6.4 MLNX_OFED_LINUX-2.1-1.0.0-rhel6.4-x86_ ...
- C/C++之标准库和标准模板库
C++强大的功能来源于其丰富的类库及库函数资源.C++标准库的内容总共在50个标准头文件中定义.在C++开发中,要尽可能地利用标准库完 成.这样做的直接好处包括:(1)成本:已经作为标准提供,何苦再花 ...
- Linux下Tomcat同时部署两个工程然而只有一个能访问问题
Linux下Tomcat同时部署两个工程然而只有一个能访问问题 问题: Linux下单个部署到Tomcat下的时候都正常,两个一起部署,只有一个能访问: 解决方案: 由于采用#./shutdown.s ...
- linux内核分析 第三周
一.Linux内核源码(简单分析) README 一开始刚接触内核源码的时候,不知道代码文件是什么功能.不清楚如何使用文件的时候,就需要打开README. README提供了内核的各种编译方法.生成文 ...
- linux内核分析 第六周
一.进程的描述 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. 1.进程控制块PCB--task_struct 进程状态 进程打开的文件 进程优先级信息 2. ...