本篇围绕 RabbitMQ 中最基本的 fabric – queue 进行讨论,主要介绍其常用的几个属性设置,以及在实际使用中的约束条件。
常用queue属性
在 rabbitmq-c代码中可以看到如下代码
上图所示为queue声明时使用的结构体。其中最容易让使用者迷惑的3个属性是durable、exclusive和auto_delete。
上图所示为consumer从queue进行消息消费时用于设置属性的结构体。其中最容易让使用者迷惑的属性是exclusive(上图中的exclusive注释有点问题,请忽略)。
测试过程
在编写Python语言的测试程序时,我将行为分为以下几步
- 声明7个具有不同属性的queue,分别和名为test_exchage的exchange进行绑定(因为exchange为fanout类型,所以测试代码中的routing_key其实是不起作用的);
- 向exchange发送具有persistent属性的消息(delivery_mode=2);
- 创建7个消费者分别从上述7个queue中获取消息;
测试结果如下
可以看到,所有的7个消费者均收到了对应的消息内容。
下面我们从RabbitMQ服务器测查看以下上述测试能展现什么信息。
1.client和server建立了一条AMQP connection。
2.在该connection上使用了channel号1进程AMQP协议通信。
3.连接建立时的用户名为guest,以及各种channel属性设置情况。
4.在当前channel上共存在7个消费者,分别从7个不同的queue上获取消息;该channel上的消息均来自名为test_exchage的exchange(请原谅我测试过程中的英文拼写错误)。
从Exchanges选项卡上可以看到test_exchage下绑定了哪些queue。
从Queues选项卡上可以看到全部7个queue的属性情况
看到这里,眼尖的同学可能会发现问题所在了,那就是客户端代码中声明的queue属性并没有全部生效,为什么会这样呢?
首先分别看一下代码中声明的7个queue在服务器侧的详细信息。
a.test_1_queue没有设置任何属性,在界面上没有看到任何属性。
b. test_2_queue设置了durable属性,在界面上看到了“durable:true”。
c. test_3_queue设置了auto-delete属性,在界面上看到了“auto-delete:true”。
d. test_4_queue同时设置了durable和auto-delete属性,在界面上看到了“durable:true和auto-delete:true”。
e. test_5_queue同时设置了durable和exclusive属性,但在界面上只看到了“Exlusive owner”的存在。
f. test_6_queue同时设置了auto_delete和exclusive属性,在界面上同时看到“auto-delete:true”和“Exlusive owner”的存在。
g. test_7_queue同时设置了durable、auto_delete和exclusive属性,在界面上只看到了“auto-delete:true”和“Exlusive owner”的存在。
综上,可以得出如下结论
- durable属性和auto-delete属性可以同时生效;
- durable属性和exclusive属性会有性质上的冲突,两者同时设置时,仅exclusive属性生效;
- auto_delete属性和exclusive属性可以同时生效;
除此之外,还能得到其它一些有趣的结论:
- Queue的“Exlusive owner”对应的是connection而不是channel;
- Consumer存在于某个channel上的;
附上一张客户端同时设置durable、auto_delete和exclusive属性的抓包截图:
下面通过改变client侧代码,模拟不同情况下各种属性对queue的存在情况的影响。
a.在成功创建全部7个queue后,通过Ctrl+C异常终止客户端程序。
(上图为全部创建时的状态)
停止后,queue的情况如下图所示。
对比发现,此时只有 test_1_queue 和 test_2_queue 仍旧存在,其它queue已经被RabbitMQ服务器删除掉了(思考原因)。
b.客户端侧执行到消息发送后,结束当前操作(无consumer情况)。代码调整如下
此时仍旧可以看到queue的声明和绑定都是成功的。
此时客户端程序执行后会自动退出
再从web页面查看queue的情况如下
对比发现,此时仅test_1_queue、test_2_queue、test_3_queue和test_4_queue 存在(思考原因)。
这里有个细节值得说一下:虽然最终我们在web页面上只看到了4个queue的存在,但其实7个queue都被成功创建过(抓包可以证明),如果你够幸运,你也可能在web页面上看到一闪而过的另外3个queue。通过对比可以发现,导致另外3个queue消失的原因是exclusive属性的设置,前面我已经说过,queue的“Exlusive owner”对应的是connection,所以在这个实验中可以确定的是,connection仍旧是存在的(这里遗留个问题:为什么python执行退出后连接仍旧存在),而此时实际上不存在的是consumer,所以需要对之前得到的结论进行加强:具有exclusive属性的queue的存在条件是在connection上存在某个consumer订阅了该queue。同样可以得到另外一个结论:可以在没有创建consumer的情况下,创建出具有auto-delete属性的queue。
在RabbitMQ官方文档中其实已经对上述现象进行了说明,只不过一语带过,不注意的话容易忽略掉。在queue.declare方法中包含如下属性说明
此时肯定有人会问,除了queue.declare中具有exclusive属性,basic.consume中也具有exclusive属性,后者是什么含义呢?在文档说明中有如下内容
由此可以理解两个属性的差异和实际使用中应该注意的问题是什么!(自行思考)
在此情况下,若执行RabbitMQ server的重启(rabbitmqctl stop_app;rabbitmqctl start_app),可以看到仅有test_2_queue和test_4_queue仍旧存在。
测试版本
以上测试基于如下RabbitMQ版本
为什么使用这个版本?(我猜肯定有人会问)因为这个实验是我半年前就已经完成了的~~
CentOS 5.6 安装RabbitMQ http://www.linuxidc.com/Linux/2013-02/79508.htm
RabbitMQ客户端C++安装详细记录 http://www.linuxidc.com/Linux/2012-02/53521.htm
用Python尝试RabbitMQ http://www.linuxidc.com/Linux/2011-12/50653.htm
RabbitMQ集群环境生产实例部署 http://www.linuxidc.com/Linux/2012-10/72720.htm
Ubuntu下PHP + RabbitMQ使用 http://www.linuxidc.com/Linux/2010-07/27309.htm
在CentOS上安装RabbitMQ流程 http://www.linuxidc.com/Linux/2011-12/49610.htm
RabbitMQ概念及环境搭建 http://www.linuxidc.com/Linux/2014-12/110449.htm
RabbitMQ入门教程 http://www.linuxidc.com/Linux/2015-02/113983.htm
RabbitMQ 的详细介绍:请点这里
RabbitMQ 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-03/115519.htm