(3)RabbitMQ交换器(Exchange)
1.前言
上个章节也有简单介绍过RabbitMQ交换器,这里主要了解下它的类型和如何使用。交换器有四种类型,分别是direct、fanout、topic、headers。
2.Virtual host(虚拟主机)
每一个RabbitMQ服务器都能创建虚拟的消息服务器,我们称之为虚拟主机(virtual host),
简称为vhost。每一个vhost本质上是一个独立的小型RabbitMQ服务器,拥有自己独立的队列、交换器及绑定关系等(可避免队列和交换器等命名冲突),并且它拥有自己独立的权限。删除一个vhost同时也会删除其下所有的队列、交换器、绑定关系、用户权限、参数和策略等信息。vhost之间也是绝对隔离的,无法将vhost1中的交换器与vhost2中的队列进行绑定,这样既保证了安全性,又可以确保可移植性。
注:vhost是AMQP概念的基础,客户端在连接的时候必须制定一个vhost。RabbitMQ默认创建的vhost为"/",如果不需要多个vhost或者对vhost的概念不是很理解,那么用这个默认的vhost也是非常合理的,使用默认的用户名guest和密码guest就可以访问它。但是为了安全和方便,建议重新建立一个新的用户来访问它。
2.1RabbitMQ常见端口
●RabbitMQ管理平台http协议端口号:15672
●RabbitMQ集群通信端口号:25672
●RabbitMQ的AMQP内部通信端口号:5672
3.交换器类型
演示还是沿用上个章节注册用户业务场景。
3.1前期准备
●新建一个名称叫User的Virtual host。
注:图片省略前缀命名
3.2Direct交换器
官网图:
direct交换器会把消息路由到那些绑定键(BindingKey)和路由键(RoutingKey)完全匹配的队列中。假设我们插入用户信息后,有如下两种场景:
①在发送邮件同时推送优惠卷到邮件队列或者推送优惠卷同时发送邮件到优惠卷队列。
如果我们在发送消息的时候设置交换器为”exchange.direct.insert_user”、路由键为”route.direct.insert_user”,无需设置队列,则消息会同时路由到Email Queue、Coupons Queue队列中。
//发送邮件同时推送优惠卷Or推送优惠卷同时发送邮件 var body = Encoding.UTF8.GetBytes("发送邮件同时推送优惠卷"); channel.BasicPublish(exchange: "exchange.direct.insert_user", routingKey: "route.direct.insert_user", mandatory: true, basicProperties: props, body: body);
如下表格所示:
类型 |
交换器 |
路由key |
队列 |
消息 |
Direct |
exchange.direct.insert_user |
route.direct.insert_user |
queue.direct.email |
发送邮件同时推送优惠卷; 推送优惠卷同时发送邮件; |
queue.direct.coupons |
发送邮件同时推送优惠卷; 推送优惠卷同时发送邮件; |
②发送邮件到邮件队列或者推送优惠卷到优惠卷队列。
如果我们在发送消息的时候设置交换器为”exchange.direct.insert_user”、路由键为”route.direct.send_email”或者”route.direct.send_coupons”、队列为”queue.direct.email”和”queue.direct.coupons”,则消息会路由到Email Queue或者Coupons Queue队列中。
//发送邮件Or推送优惠卷 var body = Encoding.UTF8.GetBytes("发送邮件"); channel.BasicPublish(exchange: "exchange.direct.insert_user", routingKey: "route.direct.send_email", mandatory: true, basicProperties: props, body: body);
Or
var body = Encoding.UTF8.GetBytes("推送优惠卷"); channel.BasicPublish(exchange: "exchange.direct.insert_user", routingKey: "route.direct.send_coupons", mandatory: true, basicProperties: props, body: body);
如下表格所示:
类型 |
交换器 |
路由key |
队列 |
消息 |
Direct |
exchange.direct.insert_user |
route.direct.send_email |
queue.direct.email |
发送邮件; |
route.direct.send_coupons |
queue.direct.coupons |
推送优惠卷; |
3.3Fanout交换器
官网图:
fanout交换器会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。如下列场景:
●把注册用户成功消息推送给邮件与优惠卷队列。
我们在发送一条“注册成功,发放100元优惠卷”消息的时候设置交换器为”exchange.fanout.insert_user”和队列为”queue.fanout.email”和”queue.fanout.coupons”,无需设置路由键,则消息会路由到Email Queue和Coupons Queue队列中。
var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "exchange.fanout.insert_user", routingKey: string.Empty, mandatory: true, basicProperties: props, body: body);
如下表格所示:
类型 |
交换器 |
路由key |
队列 |
消息 |
Fanout |
exchange.fanout.insert_user |
|
queue.fanout.email |
注册成功,发放100元优惠卷; |
|
queue.fanout.coupons |
注册成功,发放100元优惠卷; |
3.4Topic交换器
官网图:
topic类型的交换器在匹配规则上进行了扩展,它与direct类型的交换器相似,也是将消息路由到绑定键(BindingKey)和路由键(RoutingKey)相匹配的队列中,但这里的匹配规则有些不同,它有如下约定:
●RoutingKey为一个点号"."分隔的字符串(被点号"."分隔开的每段独立的字符串称为一个单词),如"quick.orange.rabbit"、"lazy.pink.rabbit"、"quick.brown.fox"。
●BindingKey和RoutingKey一样也是点号"."分隔的字符串。
●BindingKey中可以存在两种特殊字符串"*"和"#",用于做模糊匹配,其中"*"用于匹配一个单词,"#"用于匹配多个单词(可以是零个)。
下面就不通过注册用户业务来演示了,而是通过官网图来解释topic类型的交换器如何使用。如下面场景所示:
我们在发送消息的时候设置交换器为”exchange.topic.animals”,队列为”queue.topic.orange_animals”并配置绑定键(BindingKey)为”*.orange.*”、队列为”queue.topic.rabbits-lazy_animals”并配置绑定键(BindingKey)为”*.*.rabbit”、”lazy.#”。如下图所示:
队列:queue.topic.orange_animals
队列:queue.topic.rabbits-lazy_animals
如果路由键(RoutingKey)是如下配置,则会路由到不同队列中,如表格所示:
类型 |
交换器 |
路由key |
绑定key |
队列 |
消息 |
Topic |
exchange.topic.animals |
quick.orange.rabbit |
*.orange.*、*.*.rabbit |
queue.topic.orange_animals、queue.topic.rabbits-lazy_animals |
quick.orange.rabbit |
lazy.orange.elephant |
lazy.#、*.orange.* |
queue.topic.orange_animals、queue.topic.rabbits-lazy_animals |
lazy.orange.elephant |
||
quick.orange.fox |
*.orange.* |
queue.topic.orange_animals |
quick.orange.fox |
||
lazy.brown.fox |
lazy.# |
queue.topic.rabbits-lazy_animals |
lazy.brown.fox |
||
lazy.pink.rabbit |
lazy.#、*.*.rabbit |
queue.topic.rabbits-lazy_animals |
lazy.pink.rabbit |
||
quick.brown.fox |
|
|
如上面表格可以知道:
●路由键为"quick.orange.rabbit"的消息会同时路由到队列orange_animals、rabbits-lazy_animals中;
●路由键为"lazy.orange.elephant"的消息会同时路由到队列orange_animals、rabbits-lazy_animals中;
●路由键为"quick.orange.fox"的消息只会路由到队列orange_animals中;
●路由键为"lazy.brown.fox"的消息只会路由到队列rabbits-lazy_animals中;
●路由键为"lazy.pink.rabbit"的消息只会路由到队列rabbits-lazy_animals中;
●路由键为"quick.brown.fox"的消息将会被丢弃或者返回给生产者(需要设置mandatory参数),因为它没有匹配任何路由键;
注:headers交换器,实际项目中我没用过,这里就不介绍了,感兴趣请自行百度学习。
参考文献:
RabbitMQ实战指南