AMQP 与 RabbitMQ 四大模型

AMQP

AMQP 是 Advanced Message Queuing Protocol(高级消息队列协议) 的缩写,是一套跨语言、跨平台的消息传递开放标准。

核心特点是与语言 / 平台无关: 它解决了不同技术栈(比如 Java、Python、Go)、不同平台(Windows、Linux)的应用之间消息通信的兼容性问题------ 只要遵循 AMQP 协议,无论应用用什么语言开发,都能通过支持 AMQP 的消息中间件(比如 RabbitMQ)实现可靠的消息传递。

SpringAMQP介绍

Spring AMQP 是 基于 AMQP 协议的一套 Java API 规范 ,它把 AMQP 协议的能力封装成了更易用的 Spring 风格 API(比如RabbitTemplate、@RabbitListener),让 Java 开发者可以用更简洁的方式使用 AMQP 协议。

它包含两部分:

spring-amqp:是 AMQP 协议的基础抽象层,定义了核心接口和模型;

spring-rabbit:是底层实现(默认基于 RabbitMQ),负责与 RabbitMQ 服务器通信。

RabbitMQ 的 4 大核心模型

SpringAMQP 完美实现了 RabbitMQ 的 4 大核心模型。

RabbitMQ 的核心是交换机(Exchange) + 队列(Queue) + 绑定(Binding),4 大核心模型本质是交换机的四种类型,决定了消息如何从生产者路由到消费者。 他们分别是:

  1. 工作队列模式(Work Queue / 任务队列)

  2. 发布订阅模式(Fanout / 广播模式)

  3. 路由模式(Direct / 路由模式)

  4. 主题模式 (topic)

核心差异在于交换机的类型和路由规则。

WorkQueues

1、引入:当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。 此时就可以使用work 模型,多个消费者共同处理消息处理,消息处理的速度就能大大提高了。

2、workQueues的问题:默认情况下,RabbitMQ 会将消息一次轮询投递给绑定在队列上的每一个消费者,但并没有考虑消费者是否已经处理完消息,导致 "能者闲、弱者忙"。

3、解决方案:消费者端配置prefetch=1,表示消费者每次仅预取 1 条消息,处理完成后再获取下一条,实现 "能者多劳":

bash 复制代码
spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 关键配置,解决平均分配问题

总结:Work模型的使用

  • 多个消费者绑定到一个队列,同一条消息只会被一个消费者处理

  • 通过设置prefetch来控制消费者预取的消息数量

Fanout

1、Fannout exchange会将收到的消息广播到每一个跟其绑定的queue,所有绑定队列的消费者都会收到消息;所以也叫广播模式;

无路由规则,是最简单的交换机;

适合 "一对多" 的消息通知场景(如公告、通知)。

2、使用要点:

1)需先创建 Fanout 交换机和多个队列,并将队列绑定到交换机(无 bindingKey);

2)生产者:RabbitTemplate.convertAndSend(交换机名, "", 消息),第二个参数为 routingKey,Fanout 模式下传空即可

3)消费者:分别监听绑定到该交换机的不同队列,均可收到相同消息。

java 复制代码
//生产者
@Test
public void testFanoutExchange() {
    // 交换机名称
    String exchangeName = "hmall.fanout";
    // 消息
    String message = "hello, everyone!";
    rabbitTemplate.convertAndSend(exchangeName, "", message);
}
​
//消费者
@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg) {
    System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
}
​
@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg) {
    System.out.println("消费者2接收到Fanout消息:【" + msg + "】");
}
​

Direct(直连)

一、特点:生产者发送消息时指定RoutingKey(路由键),交换机会将消息路由到绑定键(BindingKey)与路由键完全匹配的队列。

具体讲,在Direct模型下:

队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey路由key) 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey。 Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息。

二、实践

1、控制台操作

首先在控制台声明两个队列direct.queue1和direct.queue2, 然后声明一个direct类型的交换机,命名为hmall.direct: 然后使用redblue作为key,绑定direct.queue1hmall.direct

同理,使用redyellow作为key,绑定direct.queue2hmall.direct

代码:

消费者:在consumer服务中添加下述方法:

java 复制代码
@RabbitListener(queues = "direct.queue1")
public void listenDirectQueue1(String msg) {
    System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
}
​
@RabbitListener(queues = "direct.queue2")
public void listenDirectQueue2(String msg) {
    System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
}

publisher:在publisher服务的SpringAmqpTest类中添加测试方法:

java 复制代码
@Test
public void testSendDirectExchange() {
    // 交换机名称
    String exchangeName = "hmall.direct";
    // 消息
    String message = "红色警报!日本乱排核废水,导致海洋生物变异,惊现哥斯拉!";
    // 发送消息
    rabbitTemplate.convertAndSend(exchangeName, "red", message);
}
​
​
@Test
public void testSendDirectExchange() {
    // 交换机名称
    String exchangeName = "hmall.direct";
    // 消息
    String message = "最新报道,哥斯拉是居民自治巨型气球,虚惊一场!";
    // 发送消息
    rabbitTemplate.convertAndSend(exchangeName, "blue", message);
}

结果:测试第一个方法是由于使用的red这个key,所以两个消费者都收到了消息

我们再切换为blue这个key(即测试第二个方法)你会发现,只有消费者1收到了消息。

Topic

Topic类型的ExchangeDirect相比,都是可以根据RoutingKey把消息路由到不同的队列。 只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候使用通配符! BindingKey 一般都是有一个或多个单词组成,多个单词之间以.分割,例如: item.insert通配符规则;

#:匹配一个或多个词 *:匹配不多不少恰好1个词

如图所示,假如此时publisher发送的消息使用的RoutingKey共有四种:

  • china.news代表有中国的新闻消息;

  • china.weather 代表中国的天气消息;

  • japan.news 则代表日本新闻

  • japan.weather 代表日本的天气消息;

解释:

  • topic.queue1:绑定的是china.# ,凡是以 china.开头的routing key 都会被匹配到,包括:china.news ;china.weather

  • topic.queue2:绑定的是#.news ,凡是以 .news结尾的 routing key 都会被匹配。包括:china.news;japan.news;

二、控制台实操

在控制台按照图示例子创建队列、交换机,并利用通配符绑定队列和交换机

讨论

1、RabbitMq和AMQP 协议的关系

rabbitmq是一个中间件,而 AMQP 协议是一个协议,也就是说使用rabbitmq作为message queue的发送者和消费者只要遵循 AMQP 协议就能够跨平台,跨语言的进行交流;

2、本文介绍的4中模型中,

workqueues模型没有交换机的参与。(可通过prefetch实现能者多劳的效果)

而真正生产环境都会经过exchange来发送消息,而不是直接发送到队列,交换机的类型有以下三种:fanout:广播;direct:定向;topic:话题。它们核心差异体现在交换机类型和路由规则的不同。

3、 SpringAMQP 则为这些模型提供了简洁易用的 Java 实现方式,通过对应的 API 和注解,能让开发者高效实现不同场景下的分布式消息传递 。

总结:

本文介绍了 AMQP 跨语言跨平台的核心特性,以及 SpringAMQP 对 AMQP 协议的 Spring 风格封装和其两大组成部分;并介绍了RabbitMQ 以交换机、队列、绑定为核心的四大模型(WorkQueues,Fanout,Direct,Topic);介绍他们的特点,解决的问题,相应的控制台实现,并举了一些代码实例来辅助说明他们。

相关推荐
灰子学技术10 小时前
istio从0到1:如何解决分布式配置同步问题
分布式·云原生·istio
小马爱打代码10 小时前
ZooKeeper:入门实战
分布式·zookeeper·云原生
永远都不秃头的程序员(互关)11 小时前
CANN赋能AIGC分布式训练:硬核通信,加速大模型智能生成新纪元
分布式·aigc
像少年啦飞驰点、11 小时前
从零开始学 RabbitMQ:小白也能懂的消息队列实战指南
java·spring boot·微服务·消息队列·rabbitmq·异步编程
lekami_兰11 小时前
RabbitMQ 延迟队列实现指南:两种方案手把手教你搞定
后端·rabbitmq·延迟队列
杜子不疼.12 小时前
CANN集合通信库HCCL的大规模分布式训练通信优化与拓扑感知实践
分布式
ALex_zry1 天前
Redis Cluster 分布式缓存架构设计与实践
redis·分布式·缓存
为什么不问问神奇的海螺呢丶1 天前
n9e categraf rabbitmq监控配置
分布式·rabbitmq·ruby
TTBIGDATA1 天前
【Atlas】Atlas Hook 消费 Kafka 报错:GroupAuthorizationException
hadoop·分布式·kafka·ambari·hdp·linq·ranger