RabbitMQ的工作流程

----------------------- virtual host ------------------------------
|                                -> queue                         |
|publisher -> exchange -> [binding] -> queue  -> consumer            |
|                                -> queue                         |
----------------------- virtual host ------------------------------

RabbitMQ是通过virtual host的概念来实行环境隔离的.

以下,来理解下各个概念

Virtual Host

为了在一个单独的代理上实现多个隔离的环境(用户、用户组、交换机、队列 等),AMQP提供了一个虚拟主机(virtual hosts - vhosts)的概念

默认的virtual host/.

创建一个virtual host

rabbitmqctl add_vhost test

例如:
➜  ~  rabbitmqctl add_vhost test
Creating vhost "test" ...
➜  ~

删除一个virtual host

rabbitmqctl delete_vhost test

例如:

➜  ~  rabbitmqctl delete_vhost test
Deleting vhost "test" ...
➜  ~

列出所有virtual host

rabbitmqctl list_vhosts name tracing

例如:

➜  ~  rabbitmqctl list_vhosts
Listing vhosts ...
/
test
➜  ~


➜  ~  rabbitmqctl list_vhosts name tracing
Listing vhosts ...
/	false
test	false
➜  ~

exchange (交换机)

交换机是用来发送消息的AMQP实体。交换机拿到一个消息之后将它路由给一个或零个队列。它使用哪种路由算法是由交换机类型和被称作绑定(bindings)的规则所决定的

default exchange (默认交换机)

默认交换机(default exchange)实际上是一个由消息代理预先声明好的没有名字(名字为空字符串)的*直连交换机(direct exchange)*。它有一个特殊的属性使得它对于简单应用特别有用处:那就是每个新建队列(queue)都会自动绑定到默认交换机上,绑定的路由键(routing key)名称与队列名称相同。

Direct exchange(直连交换机)

直连型交换机(direct exchange)是根据消息携带的路由键(routing key)将消息投递给对应队列的。直连交换机用来处理消息的单播路由(unicast routing)(尽管它也可以处理多播路由)

注意,这个路由键必须完全匹配才能投递.

funout exchange (扇形交换机)

扇型交换机(funout exchange)将消息路由给绑定到它身上的所有队列,而不理会绑定的路由键。如果N个队列绑定到某个扇型交换机上,当有消息发送给此扇型交换机时,交换机会将消息的拷贝分别发送给这所有的N个队列。扇型用来交换机处理消息的广播路由(broadcast routing)。

topic exchanges (主题交换机)

主题交换机(topic exchanges)通过对消息的路由键和队列到交换机的绑定模式之间的匹配,将消息路由给一个或多个队列。主题交换机经常用来实现各种分发/订阅模式及其变种。主题交换机通常用来实现消息的多播路由(multicast routing)。

headers exchange (头交换机)

头交换机使用多个消息属性来代替路由键建立路由规则。通过判断消息头的值能否与指定的绑定相匹配来确立路由规则.

头交换机可以视为直连交换机的另一种表现形式。头交换机能够像直连交换机一样工作,不同之处在于头交换机的路由规则是建立在头属性值之上,而不是路由键。路由键必须是一个字符串,而头属性值则没有这个约束,它们甚至可以是整数或者哈希值(字典)等

交换机常用属性

  1. Name: 交换机名
  2. Durability: (消息代理重启后,交换机是否还存在)
  3. Auto-delete: (当所有与之绑定的消息队列都完成了对此交换机的使用后,删掉它)
  4. Arguments:(依赖代理本身)

常用命令

列出所有交换机

rabbitmqadmin -V test list exchanges

例如:

➜  ~  rabbitmqadmin -V / list exchanges
+--------------------+---------+
|        name        |  type   |
+--------------------+---------+
|                    | direct  |
| amq.direct         | direct  |
| amq.fanout         | fanout  |
| amq.headers        | headers |
| amq.match          | headers |
| amq.rabbitmq.log   | topic   |
| amq.rabbitmq.trace | topic   |
| amq.topic          | topic   |
+--------------------+---------+
➜  ~

声明一个交换机

rabbitmqadmin declare exchange name=my-new-exchange type=fanout

type可以参考上面的类型.

queue (队列)

队列在声明(declare)后才能被使用。如果一个队列尚不存在,声明一个队列会创建它。如果声明的队列已经存在,并且属性完全相同,那么此次声明不会对原有队列产生任何影响。如果声明中的属性与已存在队列的属性有差异,那么一个错误代码为406的通道级异常就会被抛出

常用属性

  1. Name: 队列名
  2. Durable:(消息代理重启后,队列依旧存在)
  3. Exclusive:(只被一个连接(connection)使用,而且当连接关闭后队列即被删除)
  4. Auto-delete:(当最后一个消费者退订后即被删除)
  5. Arguments:(一些消息代理用他来完成类似与TTL的某些额外功能)

常用命令

列出队列简要信息

rabbitmqadmin list queues vhost name node messages message_stats.publish_details.rate

例如:

➜  ~  rabbitmqadmin list queues vhost name node messages message_stats.publish_details.rate
+-------+-------------+------------------+----------+------------------------------------+
| vhost |    name     |       node       | messages | message_stats.publish_details.rate |
+-------+-------------+------------------+----------+------------------------------------+
| /     | yangzhiyong | rabbit@localhost | 0        |                                    |
+-------+-------------+------------------+----------+------------------------------------+
➜  ~

列出队列尽可能详细信息

rabbitmqadmin -f long -d 3 list queues

声明一个队列

rabbitmqadmin declare queue name=my-new-queue durable=false

发布一条消息

rabbitmqadmin publish exchange=amq.default routing_key=test payload="hello, world"

取出一条消息

rabbitmqadmin get queue=test requeue=false

Binding (绑定)

绑定(Binding)是交换机(exchange)将消息(message)路由给队列(queue)所需遵循的规则.

示例

扇形交换机使用例子

声明一个扇形交换机:
➜  ~  rabbitmqadmin declare exchange name=myexchange type=fanout
exchange declared


声明两个队列
➜  ~  rabbitmqadmin declare queue name=myqueue durable=true
queue declared

➜  ~  rabbitmqadmin declare queue name=myqueue2 durable=true
queue declared
➜  ~


绑定队列到交换机
➜  ~  rabbitmqadmin declare binding source=myexchange destination_type="queue" destination="myqueue" routing_key="ignore_routing_key"
binding declared
➜  ~

➜  ~  rabbitmqadmin declare binding source=myexchange destination_type="queue" destination="myqueue2" routing_key="ignore_routing_key"
binding declared
➜  ~

发布一条消息到交换myexchange
➜  ~  rabbitmqadmin publish exchange=myexchange routing_key="ignore_routing_key" payload="hello, world, from publisher"
Message published
➜  ~

从队列"myqueue"出队一条消息
➜  ~  rabbitmqadmin get queue=myqueue requeue=true
+--------------------+------------+---------------+------------------------------+---------------+------------------+------------+-------------+
|    routing_key     |  exchange  | message_count |           payload            | payload_bytes | payload_encoding | properties | redelivered |
+--------------------+------------+---------------+------------------------------+---------------+------------------+------------+-------------+
| ignore_routing_key | myexchange | 0             | hello, world, from publisher | 28            | string           |            | False       |
+--------------------+------------+---------------+------------------------------+---------------+------------------+------------+-------------+
➜


从队列"myqueue2"出队一条消息
➜  ~  rabbitmqadmin get queue=myqueue2 requeue=true
+--------------------+------------+---------------+------------------------------+---------------+------------------+------------+-------------+
|    routing_key     |  exchange  | message_count |           payload            | payload_bytes | payload_encoding | properties | redelivered |
+--------------------+------------+---------------+------------------------------+---------------+------------------+------------+-------------+
| ignore_routing_key | myexchange | 0             | hello, world, from publisher | 28            | string           |            | False       |
+--------------------+------------+---------------+------------------------------+---------------+------------------+------------+-------------+
➜

注意,扇形交换机会忽略routing_key的,只要队列绑定到了扇形交换机,那么扇形交换机就会将这些消息,都会发给每一个队列.

其他有兴趣的, 可以自行测试.

还有, 这里没有指明virtual host,那么就是默认的/.如果指定了virtual host,那么上面的每条命令的virtual host都要相同.

参考资料

  1. Rabbitmq rabbitmqctl文档
  2. Rabbitmq 中文文档

binding