原文:(八)RabbitMQ消息队列-通过Topic主题模式分发消息

前两章我们讲了RabbitMQ的direct模式和fanout模式,本章介绍topic主题模式的应用。如果对direct模式下通过routingkey来匹配消息的模式已经有一定了解那fanout也很好理解。简单的可以理解成direct是通过routingkey精准匹配的,而topic是通过routingkey来模糊匹配。

在topic模式下支持两个特殊字符的匹配。

* (星号) 代表任意 一个单词
# (井号) 0个或者多个单词

注意:上面说的是单词不是字符。

如下图所示,RabbitMQ direct模式通过RoutingKey来精准匹配,RoutingKey为red的投递到Queue1,RoutingKey为black和white的投递到Queue2。

我们可以假设一个场景,我们要做一个日志模块来收集处理不同的日志,日志区分包含三个维度的标准:模块、日志紧急程度、日志重要程度。模块分为:red、black、white;紧急程度分为:critical、normal;把重要程度分为:medium、low、high在RoutingKey字段中我们把这三个维度通过两个“.“连接起来。

现在我们需要对black模块,紧急程度为critical,重要程度为high的日志分配到队列1打印到屏幕;对所以模块重要程度为high的日志和white紧急程度为critical的日志发送到队列2持久化到硬盘。如下示例:

  • RoutingKey为“black.critical.high”的日志会投递到queue1和queue2,。

  • RoutingKey为“red.critical.high”的日志会只投递到queue2。

  • RoutingKey为“white.critical.high”的日志会投递到queue2,并且虽然queue2的两个匹配规则都符合但只会向queue2投递一份。

新建topic.php用来发布三种routingkey的消息。


<?php /*
* topic 模式
* create by superrd
*/ $exchangeName = 'extopic';
$routeKey1 = "black.critical.high";
$routeKey2 = "red.critical.high";
$routeKey3 = "white.critical.high"; $message1 = 'black-critical-high!';
$message2 = 'red-critical-high!';
$message3 = 'white-critical-high!'; $connection = new AMQPConnection(array('host' => '10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));
$connection->connect() or die("Cannot connect to the broker!\n");
try {
$channel = new AMQPChannel($connection);
$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setType(AMQP_EX_TYPE_TOPIC);
$exchange->setFlags(AMQP_DURABLE);
$exchange->declareExchange(); $exchange->publish($message1,$routeKey1);
var_dump("[x] Sent ".$message1);
$exchange->publish($message2,$routeKey2);
var_dump("[x] Sent ".$message2);
$exchange->publish($message3,$routeKey3);
var_dump("[x] Sent ".$message3); } catch (AMQPConnectionException $e) {
var_dump($e);
exit();
}
$connection->disconnect();

q1.php用来监听queue1队列:


<?php /*
* topic 模式
* create by superrd
*/ $queueName = 'queue1';
$exchangeName = 'extopic';
$routeKey = "black.critical.high"; $connection = new AMQPConnection(array('host' => '10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));
$connection->connect() or die("Cannot connect to the broker!\n"); $channel = new AMQPChannel($connection);
$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setType(AMQP_EX_TYPE_TOPIC);
$exchange->setFlags(AMQP_DURABLE);
$exchange->declareExchange(); $queue = new AMQPQueue($channel);
$queue->setName($queueName);
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue(); $queue->bind($exchangeName, $routeKey); //阻塞模式接收消息 echo "Message:\n";
while(True){
$queue->consume('processMessage');
//自动ACK应答
//$queue->consume('processMessage', AMQP_AUTOACK);
} $conn->disconnect();
/*
* 消费回调函数
* 处理消息
*/
function processMessage($envelope, $q) {
$msg = $envelope->getBody();
echo $msg."\n"; //处理消息
$q->ack($envelope->getDeliveryTag()); //手动发送ACK应答
}

q2.php用来监听queue2队列:

<?php

/*
* topic 模式
* create by superrd
*/ $queueName = 'queue2';
$exchangeName = 'extopic';
$routeKey1 = "#.high";
$routeKey2 = "white.critical.*"; $connection = new AMQPConnection(array('host' => '10.99.121.137', 'port' => '5672', 'vhost' => '/', 'login' => 'superrd', 'password' => 'superrd'));
$connection->connect() or die("Cannot connect to the broker!\n"); $channel = new AMQPChannel($connection);
$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setType(AMQP_EX_TYPE_TOPIC);
$exchange->setFlags(AMQP_DURABLE);
$exchange->declareExchange(); $queue = new AMQPQueue($channel);
$queue->setName($queueName);
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue(); $queue->bind($exchangeName, $routeKey1);
$queue->bind($exchangeName, $routeKey2); //阻塞模式接收消息 echo "Message:\n";
while(True){
$queue->consume('processMessage');
//自动ACK应答
//$queue->consume('processMessage', AMQP_AUTOACK);
} $conn->disconnect();
/*
* 消费回调函数
* 处理消息
*/
function processMessage($envelope, $q) {
$msg = $envelope->getBody();
echo $msg."\n"; //处理消息
$q->ack($envelope->getDeliveryTag()); //手动发送ACK应答
}

先运行q1.php和q2.php脚本保持订阅状态。然后执行topic.php脚本发布消息。q1和q2收到的消息如下:

如上截图,验证了我们之前的结论。

另外还有一些特殊情况例如:

  1. 如果binding_key 是 “#” - 它会接收所有的Message,不管routing_key是什么,就像是fanout

    exchange。
  2. 如果 “*” and “#” 没有被使用,那么topic exchange就变成了direct exchange。

RabbitMQ技术交流QQ群:327034977(添加时请备注RabbitMQ)

(八)RabbitMQ消息队列-通过Topic主题模式分发消息的更多相关文章

  1. RabbitMQ消息队列(八)-通过Topic主题模式分发消息(.Net Core版)

    前两章我们讲了RabbitMQ的direct模式和fanout模式,本章介绍topic主题模式的应用.如果对direct模式下通过routingkey来匹配消息的模式已经有一定了解那fanout也很好 ...

  2. (九)RabbitMQ消息队列-通过Headers模式分发消息

    原文:(九)RabbitMQ消息队列-通过Headers模式分发消息 Headers类型的exchange使用的比较少,以至于官方文档貌似都没提到,它是忽略routingKey的一种路由方式.是使用H ...

  3. ActiveMQ之topic主题模式

    开发环境我们使用的是ActiveMQ 5.11.1 Release的Windows版,官网最新版是ActiveMQ 5.12.0 Release,大家可以自行下载,下载地址.需要注意的是,开发时候,要 ...

  4. (转)RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  5. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  6. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)[转]

    上篇文章中,我们把每个Message都是deliver(提供)到某个Consumer.在这篇文章中,我们将会将同一个Message deliver(提供)到多个Consumer中.这个模式也被成为 & ...

  7. 译: 5. RabbitMQ Spring AMQP 之 Topic 主题

    在上一个教程中,我们提高了消息传递的灵活 我们使用direct交换而不是使用仅能够进行虚拟广播的fanout交换, 并且获得了基于路由key 有选择地接收消息的可能性. 虽然使用direct 交换改进 ...

  8. Azure Messaging-ServiceBus Messaging消息队列技术系列4-复杂对象消息是否需要支持序列化和消息持久化

    在上一篇中,我们介绍了消息的顺序收发保证: Azure Messaging-ServiceBus Messaging消息队列技术系列3-消息顺序保证 在本文中我们主要介绍下复杂对象消息是否需要支持序列 ...

  9. 使用jedis实现Redis消息队列(MQ)的发布(publish)和消息监听(subscribe)

    前言: 本文基于jedis 2.9.0.jar.commons-pool2-2.4.2.jar以及json-20160810.jar 其中jedis连接池需要依赖commons-pool2包,json ...

随机推荐

  1. Java设计模式23种(搞笑版) (转)

        昨天做了一下支付宝的笔试题目被打击了,大量的逻辑推理和数学规律运算题目,其中还有问道Java设计模式的题目,一点都不知道,今天看到一份不错的介绍,非常好理解,作者是谁我没有办法考证,但是所有权 ...

  2. 《深入理解java虚拟机》:类的初始化

    深入理解java虚拟机>:类的初始化 类从被载入到虚拟机内存中開始.到卸载出内存为止,它的整个生命周期包含:载入.验证.准备.解析.初始化.使用和卸载七个阶段.当中验证.准备.解析3个部分统称为 ...

  3. php 函数 pathinfo() 在分析文件名时,会含有上级目录

    php 函数 pathinfo() 在分析文件名时,会含有上级目录对一些含有中文的多级目录,这个函数取得的文件名可能会包含上级目录,

  4. android audio

    package com.javacodegeeks.android.audiocapturetest; import java.io.IOException; import android.media ...

  5. UVA 12333 Revenge of Fibonacci

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  6. JavaScript 实现表格单列按字母排序

    <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title> ...

  7. RocketMQ集群消费的那些事

    说明 RocketMQ集群消费的时候,我们经常看到类似注释里面 (1,(2 的写法,已经有时候有同学没注意抛异常的情况就是(3 模拟的情况.那么这3种情况到底是怎么样的呢?你是否都了然于心呢?下面我们 ...

  8. AndroidStudio 内存泄漏分析 Memory Monitor

    ok.写一段内存泄漏的code private TextView txt; @Override protected void onCreate(Bundle savedInstanceState) { ...

  9. 【例题 7-13 UVA-1374】Power Calculus

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 结论:每次只用新生成的数字就好了. 然后就是IDA*了. 迭代深搜+剪枝. [代码] /* 1.Shoud it use long ...

  10. 【部分原创】python实现视频内的face swap(换脸)

    1.准备工作,按博主的环境为准 Python 3.5 Opencv 3 Tensorflow 1.3.1 Keras 2 cudnn和CUDA,如果你的GPU足够厉害并且支持的话,可以选择安装 那就先 ...