RabbitMQ 的7种工作模式

RabbitMQ 共提供了7种⼯作模式,进⾏消息传递,.

官⽅⽂档:RabbitMQ Tutorials | RabbitMQ

1.Simple(简单模式)

P:⽣产者,也就是要发送消息的程序

C:消费者,消息的接收者

Queue:消息队列,图中⻩⾊背景部分.类似⼀个邮箱,可以缓存消息;⽣产者向其中投递消息,消费者从其中取出消息.

特点:⼀个⽣产者P,⼀个消费者C,消息只能被消费⼀次.也称为点对点(Point-to-Point)模式.适⽤场景:消息只能被单个消费者处理

2.Work Queue(工作队列)

⼀个⽣产者P,多个消费者C1,C2.在多个消息的情况下,Work Queue 会将消息分派给不同的消费者,每个消费者都会接收到不同的消息.

特点:消息不会重复,分配给不同的消费者.

**适⽤场景:**集群环境中做异步处理。⽐如 12306 短信通知服务,订票成功后,订单消息会发送到RabbitMQ,短信服务从 RabbitMQ 中获取订单信息,并发送通知信息(在短信服务之间进⾏任务分配)

3.Publish/Subscribe(发布/订阅)

图中 X 表⽰交换机,在订阅模型中,多了⼀个 Exchange ⻆⾊,过程略有变化

⼀个⽣产者P,多个消费者C1,C2,X 代表交换机消息复制多份,每个消费者接收相同的消息 ⽣产者发送⼀条消息,经过交换机转发到多个不同的队列,多个不同的队列就有多个不同的消费者 适合场景:消息需要被多个消费者同时接收的场景.如:实时通知或者⼴播消息

⽐如中国⽓象局发布"天⽓预报"的消息送⼊交换机,新浪,百度,搜狐,⽹易等⻔户⽹站接⼊消息,通过队列绑定到该交换机,⾃动获取⽓象局推送的⽓象数据

概念介绍:Exchange:交换机(X)

作⽤:⽣产者将消息发送到 Exchange,由交换机将消息按⼀定规则路由到⼀个或多个队列中(上图中⽣产者将消息投递到队列中,实际上这个在 RabbitMQ 中不会发⽣,因为在 RabbitMQ 中生产者的信息要经过交换机路由,不会直接发给队列)

RabbitMQ 交换机有四种类型:

fanout,direct,topic,headers,不同类型有着不同的路由策略.AMQP 协议⾥还有另外两种类型, System 和 ⾃定义,此处不再描述.

  1. Fanout:⼴播,将消息交给所有绑定到交换机的队列( Publish/Subscribe 模式)

  2. Direct:定向,把消息交给符合指定 routing key 的队列(Routing模式)

  3. Topic:通配符,把消息交给符合 routing pattern(路由模式)的队列 (Topics模式)

  4. headers 类型的交换器不依赖于路由键的匹配规则来路由消息,⽽是根据发送的消息内容中的 headers 属性进⾏匹配.headers 类型的交换器性能会很差,⽽且也不实⽤,基本上不会看到它的存在.

Exchange(交换机)只负责转发消息,不具备存储消息的能⼒,因此如果没有任何队列与Exchange 绑定,或者没有符合路由规则的队列那么消息就会丢失

RoutingKey路由键.⽣产者将消息发给交换器时,指定的⼀个字符串,⽤来告诉交换机应该如何处理这个消息.

BindingKey:绑定.RabbitMQ 中通过Binding(绑定)将交换器与队列关联起来,在绑定的时候⼀般会指定⼀个 Binding Key,这样 RabbitMQ 就知道如何正确地将消息路由到队列了.

⽐如下图:如果在发送消息时,设置了 RoutingKey 为 orange,消息就会路由到Q1

当消息的 Routingkey 与队列绑定的 Bindingkey相匹配时,消息才会被路由到这个队列. BindingKey其实也属于路由键中的⼀种,

官⽅解释为:the routingkey to use for the binding. 可以翻译为:在绑定的时候使⽤的路由键.⼤多数时候,包括官⽅⽂档和 RabbitMQ Java API 中都把 BindingKey 和 RoutingKey看作RoutingKey,为了避免混淆,可以这么理解:

  1. 在使⽤绑定的时候,需要的路由键是 BindingKey.

  2. 在发送消息的时候,需要的路由键是 RoutingKey.

4.Routing(路由模式)

路由模式是发布订阅模式的变种,在发布订阅基础上,增加路由 key 发布订阅模式是⽆条件的将所有消息分发给所有消费者,路由模式是 Exchange 根据 RoutingKey 的规则,将数据筛选后发给对应的消费者队列 适合场景:需要根据特定规则分发消息的场景.

⽐如系统打印⽇志,⽇志等级分为 error,warning,info,debug,就可以通过这种模式,把不同的⽇志发送到不同的队列,最终输出到不同的文件

5.Topics(通配符模式)

路由模式的升级版,在 routingKey 的基础上,增加了通配符的功能,使之更加灵活.Topics 和Routing 的基本原理相同,即:⽣产者将消息发给交换机,交换机根据 RoutingKey 将消息转 发给与 RoutingKey 匹配的队列.类似于正则表达式的⽅式来定义 Routingkey 的模式.

不同之处是:routingKey 的匹配⽅式不同,Routing 模式是相等匹配,topics 模式是通配符匹配.

在 topic 类型的交换机在匹配规则上,有些要求:

  1. RoutingKey是⼀系列由点( . )分隔的单词,⽐如" stock.usd.nyse "," nyse.vmw ", " quick.orange.rabbit "

  2. BindingKey 和 RoutingKey ⼀样,也是点( . )分割的字符串.

  3. Binding Key中可以存在两种特殊字符串,⽤于模糊匹配

* 表⽰⼀个单词,如 m ,mq

# 表⽰多个单词(0-N个)⽐如

• Binding Key为"d.a.b"会同时路由到 Q1 和 Q2

• Binding Key 为"d.a.f" 会路由到Q1

• Binding Key 为"c.e.f" 会路由到Q2

• Binding Key 为"d.b.f" 会被丢弃,或者返回给⽣产者(需要设置 mandatory 参数)

适合场景:需要灵活匹配和过滤消息的场景

6.RPC(RPC通信)

在 RPC 通信的过程中,没有⽣产者和消费者,⽐较像咱们 RPC 远程调⽤,⼤概就是通过两个队列实现了⼀个可回调的过程.

  1. 客户端发送消息到⼀个指定的队列,并在消息属性中设置 replyTo 字段,这个字段指定了⼀个回调队列,⽤于接收服务端的响应.

  2. 服务端接收到请求后,处理请求并发送响应消息到 replyTo 指定的回调队列

  3. 客户端在回调队列上等待响应消息.⼀旦收到响应,客户端会检查消息的 correlationId属性,以确保它是所期望的响应.

7.Publisher Confirms(发布确认)

Publisher Confirms 模式是 RabbitMQ 提供的⼀种确保消息可靠发送到 RabbitMQ 服务器的机制。在这种模式下,⽣产者可以等待 RabbitMQ 服务器的确认,以确保消息已经被服务器接收并处理.

  1. ⽣产者将 Channel 设置为 confirm 模式(通过调⽤ channel.confirmSelect()完成)后,发布的每⼀条消息都会获得⼀个唯⼀的ID,⽣产者可以将这些序列号与消息关联起来,以便跟踪消息的状态.

  2. 当消息被 RabbitMQ 服务器接收并处理后,服务器会异步地向⽣产者发送⼀个确认(ACK)给⽣产者 (包含消息的唯⼀ID),表明消息已经送达.通过 Publisher Confirms 模式,⽣产者可以确保消息被 RabbitMQ 服务器成功接收,从⽽避免消息丢失的问题.

消息丢失问题

作为消息中间件,都会⾯临消息丢失的问题.消息丢失⼤概分为三种情况:

  1. ⽣产者问题.因为应⽤程序故障,⽹络抖动等各种原因,⽣产者没有成功向 broker 发送消息.

  2. 消息中间件⾃⾝问题.⽣产者成功发送给了Broker,但是 Broker 没有把消息保存好,导致消息丢失.

  3. 消费者问题.Broker 发送消息到消费者,消费者在消费消息时,因为没有处理好,导致 broker 将消费失败的消息从队列中删除了.

RabbitMQ 也对上述问题给出了相应的解决⽅案.问题 2 可以通过持久化机制.问题 3 可以采⽤消息应答机制.针对问题1,可以采⽤发布确认( Publisher Confirms )机制实现.

适⽤场景:对数据安全性要求较⾼的场景.比如⾦融交易,订单处理.

原理

⽣产者将信道设置成 **confirm(确认)**模式,⼀旦信道进⼊ confirm 模式,所有在该信道上⾯发布的消息都会被指派⼀个唯⼀的ID(从1开始),⼀旦消息被投递到所有匹配的队列之后,RabbitMQ 就会发送⼀个确认给⽣产者(包含消息的唯⼀ID)

这就使得⽣产者知道消息已经正确到达⽬的队列了,如果消息和队列是可持久化的,那么确认消息会在将消息写⼊磁盘之后发出.broker 回传给⽣产者的确认消息中 deliveryTag 包含了确认消息的序号,此外 **broker 也可以设置 channel.basicAck⽅法中的 multiple 参数,**表⽰到这个序号之前的所有消息都已经得到了处理.

发送⽅确认机制最⼤的好处在于它是异步的,⽣产者可以同时发布消息和等待信道返回确认消息.

  1. 当消息最终得到确认之后,⽣产者可以通过回调⽅法来处理该确认消息.

  2. 如果 RabbitMQ 因为⾃⾝内部错误导致消息丢失,就会发送⼀条 nack(Basic.Nack) 命令,⽣产者同样 可以在回调⽅法中处理该 nack 命令

实现思路

异步 confirm ⽅法的编程实现最为复杂. Channel 接⼝提供了⼀个⽅法 addConfirmListener. 这个⽅法可以添加 ConfirmListener 回调接⼝. ConfirmListener 接⼝中包含两个⽅法:

handleAck(long deliveryTag, boolean multiple) 和 handleNack(long deliveryTag, boolean multiple) ,分别对应处理 RabbitMQ 发送给⽣产者的 ack(成功处理) 和 nack(未成功处理)

deliveryTag 表⽰发送消息的序号.multiple表⽰是否批量确认.我们需要为每⼀个 Channel 维护⼀个已发送消息的序号集合.当收到 RabbitMQ 的 confirm 回调时,从集合中删除对应的消息.当Channel 开启 confirm 模式后,channel 上发送消息都会附带⼀个从 1 开始递增的 deliveryTag 序号.我们可以使⽤ SortedSet 的有序性来维护这个已发消息的集合.

  1. 当收到 ack时,从序列中删除该消息的序号.如果为批量确认消息,表⽰⼩于等于当前序号 deliveryTag 的消息都收到了,则清除对应集合

  2. 当收到 nack时,处理逻辑类似,不过需要结合具体的业务情况,进⾏消息重发等操作.

3种消息确认模式的对比

可以看到异步确认模式的效率远超于另外的两种消息确认模式。

相关推荐
用户8307196840821 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者2 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者4 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧5 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖5 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农5 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者5 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端
业精于勤_荒于稀5 天前
物流订单系统99.99%可用性全链路容灾体系落地操作手册
分布式
Ronin3055 天前
信道管理模块和异步线程模块
开发语言·c++·rabbitmq·异步线程·信道管理
Asher05095 天前
Hadoop核心技术与实战指南
大数据·hadoop·分布式