RabbitMQ 消息使用场景 (二)

109 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

Publish/Subscribe发布订阅模式

一次向多个消费者发送同一个消息,当很多微博用户都关注了A用户,当A发送动态是,微博就会给关注A的所有用户推送消息(类似kafka多个groupId的消息分发模式)。

这个机制是对Work Queues的一种补充,也就是把ProducerConsumer进行进一步解耦。Producer只负责发送消息,至于消息进入那个queue,由交换机(exchange)分配。

Producer示例代码:

channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); 
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));

Consumer示例代码:

channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); 
String queueName = channel.queueDeclare().getQueue(); 
//将消费的目标队列绑定到exchange上。
channel.queueBind(queueName, EXCHANGE_NAME, "");

注意:

  • 交换类型fanout,只负责所有已绑定的队列上发送消息,不论你设置的路由键是什么。
  • 交换机只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与exchange绑定,那么消息会丢失。

Routing基于内容路由

有选择性的接收消息,例如我们构建一个简单的日志系统,我们能够向许多消费者发送日志消息,我们可以将error消息记录到日志文件,又同时可以将日志消息在控制台打印。

Producer示例代码:

channel.exchangeDeclare(EXCHANGE_NAME, "direct"); 
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));

Cousumer示例代码:

channel.exchangeDeclare(EXCHANGE_NAME, "direct"); 
channel.queueBind(queueName, EXCHANGE_NAME, routingKey1); 
channel.queueBind(queueName, EXCHANGE_NAME, routingKey2); 
channel.basicConsume(queueName, true, consumer);

注意:

  • 交换类型direct,会将绑定的路由键完全匹配的方式路由到指定的队列上。如果路由键不匹配,那么就不会发送到任何队列中去。

Topics主题

基于主题接收消息,在Routing模式下,我们有了新的要求,我们不仅仅是根据严重性来订阅,我们还需要根据日志来源来区分。

Producer示例代码:

channel.exchangeDeclare(EXCHANGE_NAME, "topic"); 
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));

Cousumer示例代码:

channel.exchangeDeclare(EXCHANGE_NAME, "topic"); 
channel.queueBind(queueName, EXCHANGE_NAME, routingKey1); 
channel.queueBind(queueName, EXCHANGE_NAME, routingKey2); 
channel.basicConsume(queueName, true, consumer);

注意:

  • *号表示匹配一个单词
  • #号表示匹配0个或多个

RPC远程调用

远程调用是同步阻塞的调用远程服务并获取结果。

RPC并不是消息中间件的处理强项。毕竟消息队列机制很大程度上是为了缓冲同步RPC造成的瞬间洪峰。而RabbitMQ远程同步调用并没有带来什么,而且还有一些更优的选择。不建议使用。