RabbitMQ简单介绍

什么是消息队列

消息队列是一种在应用程序之间传递消息的通信模式。它提供了一种异步的、可靠的方式来处理分布式系统中的消息传递。在消息队列中,消息发送者(Producer)将消息发送到队列(Queue)中,而消息接收者(Consumer)则从队列中获取消息进行处理。消息队列作为中间件,解耦了消息的发送者和接收者,使它们可以独立地进行操作。

消息队列通常应用场景

  1. 异步任务处理:将耗时的任务或业务逻辑作为消息发送到队列中,在后台异步处理,提高系统的响应速度和并发处理能力。
  2. 解耦系统组件:不同的系统组件之间通过消息队列进行通信,实现解耦,使得系统的各个组件可以独立地进行扩展、修改和替换,提高系统的灵活性。
  3. 系统解耦和削峰填谷:将请求发送到消息队列中,由另一个系统或服务来处理请求,减轻系统的负载压力,实现削峰填谷。
  4. 日志收集和处理:将系统产生的日志消息发送到消息队列中,再由消费者进行处理、分析和存储,方便日志的集中管理和实时监控。
  5. 事件驱动架构:通过消息队列来实现系统的事件驱动架构,不同的系统组件可以通过消息的发布和订阅机制进行解耦和通信。
  6. 消息广播和通知:将消息广播到多个订阅者,实现实时通知、广播和推送功能,例如实时聊天系统、新闻订阅等。
  7. 分布式事务:通过消息队列来实现分布式事务的最终一致性,确保不同系统之间的数据一致性。
  8. 应用解耦和系统集成:将不同的应用程序之间通过消息队列进行集成,实现数据的传递和共享。

RabbitMQ简介

RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue 高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法。常用于在分布式系统中存储、转发消息,从而实现系统之间的解耦,支持多种客户端,包括Python、Ruby、.NET、Java等。RabbitMQ官方地址:http://www.rabbitmq.com

RabbitMQ工作原理

RabbitMQ结构图

组成部分说明

  1. Producer(消息生产者):Producer是消息的发送者,它将消息发送到RabbitMQ中的交换机(Exchange)。Producer可以将消息发送到特定的交换机,并指定一个路由键(Routing Key)来标识消息的路由规则。
  2. Exchange(交换机):Exchange是消息的接收和分发中心。Producer将消息发送到交换机,交换机根据指定的路由键将消息路由到一个或多个绑定的队列中。
  • Direct Exchange(直连交换机):根据消息的路由键与绑定的队列进行精确匹配。
  • Topic Exchange(主题交换机):根据消息的路由键与绑定的队列进行模式匹配,支持通配符的路由键。
  • Fanout Exchange(扇形交换机):将消息广播给所有绑定的队列,忽略路由键。
  1. Queue(队列):Queue是消息的存储地点。它是RabbitMQ中的核心组件,用于存储待处理的消息。消息发送到队列后,等待消费者(Consumer)从队列中获取并处理消息。
  2. Binding(绑定):绑定是交换机和队列之间的关联关系。它定义了交换机如何将消息路由到特定的队列。绑定包括交换机名称、队列名称和可选的路由键。
  3. Consumer(消息消费者):Consumer是消息的接收者,它从队列中获取消息并进行处理。当有消息到达队列时,RabbitMQ将消息发送给一个或多个消费者进行处理。
  4. Connect(连接):Connect是Producer和Consumer与RabbitMQ之间建立的网络连接。每个应用程序都可以建立一个或多个Connect,用于与RabbitMQ进行通信。
  5. Channel(通道):Channel是建立在Connection上的虚拟连接。Producer和Consumer使用Channel来进行消息的发送和接收。通过使用多个Channel,可以实现并行处理多个消息的能力。
  6. Virtual Host(虚拟主机):Virtual Host是逻辑上的概念,用于对RabbitMQ进行逻辑分区。每个Virtual Host拥有自己的独立的交换机、队列、绑定等资源,实现了逻辑上的隔离。
  7. Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue

生产者发送消息流程

  1. 建立连接:生产者首先与 RabbitMQ 建立连接。连接包含 RabbitMQ 服务器的地址、端口和认证凭据等信息。

  2. 创建通道:在建立连接后,生产者必须创建一个通道(Channel)。通道是建立在连接上的虚拟连接,用于进行消息的发送和接收。通过通道,可以实现并发处理多个消息。

  3. 声明交换机:生产者需要声明要发送消息的交换机(Exchange)。交换机负责接收消息,并根据指定的路由键将消息路由到一个或多个绑定的队列。

  4. 声明队列(可选):如果生产者发送的消息需要直接发送到特定的队列,而不经过交换机的路由规则,那么生产者需要声明要发送消息的队列。如果队列不存在,RabbitMQ将自动创建该队列。

  5. 发布消息:生产者使用通道的 basicPublish 方法来发布消息。在发布消息时,需要指定以下参数:

    • 交换机名称:消息将被发送到的交换机。
    • 路由键(Routing Key):用于将消息路由到特定的队列。
    • 消息内容:要发送的实际消息数据。
  6. 关闭通道和连接:在完成消息发送后,生产者应该关闭通道和连接,释放资源。

消费者接收消息流程

  1. 建立连接:消费者首先与 RabbitMQ 建立连接。连接包含 RabbitMQ 服务器的地址、端口和认证凭据等信息。

  2. 创建通道:在建立连接后,消费者必须创建一个通道(Channel)。通道是建立在连接上的虚拟连接,用于进行消息的发送和接收。通过通道,可以实现并发处理多个消息。

  3. 声明队列:消费者需要声明要接收消息的队列。如果队列不存在,RabbitMQ将自动创建该队列。

  4. 绑定队列和交换机:消费者将队列绑定到特定的交换机上,以便从交换机接收消息。绑定需要指定交换机名称、队列名称和可选的路由键。

  5. 消息消费:消费者使用通道的 basicConsume 方法来开始消费消息。在消费消息时,需要指定以下参数:

    • 队列名称:要消费的队列。
    • 消费回调函数:当消费者接收到消息时,会调用该回调函数进行处理。
  6. 消费者通过订阅队列并注册回调函数,当有消息到达队列时,RabbitMQ会将消息发送给消费者进行处理。

  7. 处理消息:消费者在收到消息后,通过回调函数对消息进行处理。处理可以包括解析消息内容、执行特定的业务逻辑等操作。

  8. 消息确认(可选):消费者可以选择确认消息的接收,以确保消息已经成功处理。确认可以通过调用通道的 basicAck 方法来实现。

  9. 关闭通道和连接:在完成消息处理后,消费者应该关闭通道和连接,释放资源。

六种消息模型

基本消息模型

基本消息模型示意图:

  • P:生产者,就是发送消息的应用程序
  • C:消费者:就是接收消息的应用程序,它会一直等待消息的到来
  • queue:消息队列,图中红色长条部分,可以缓存消息;生产者向队列中投递消息,消费者从队列中获取出消息。

work消息模型

工作队列或者竞争消费者模示意图:

work queues与基本消息模型对比,多了一个消费者,两个消费者共同消费同一个队列中的消息,但是一个消息只能被一个消费者获取,两者是竞争关系

P:生产者:发送消息的应用程序

C1:消费者1:接收消息并且完成相应的任务,假设完成速度较慢(耗时10s)

C2:消费者2:接收消息并且完成相应的任务,假设完成速度较快(耗时2s)

这时生产者发送了5条消息,C1消费了1条,C2消费了4条,体现了能者多劳的关系,现实中对应机器设备处理任务的速度快慢。

Publish/subscribe模型

交换机类型:Fanout,也称为广播

Publish/subscribe模型示意图 :

P:生产者:发送消息的应用程序

X:交换机:与队列进行绑定

Queue:消息队列,图中红色长条部分,可以缓存消息;生产者向队列中投递消息,消费者从队列中获取出消息

C1:消费者1:接收消息并且完成相应的任务

C2:消费者2:接收消息并且完成相应的任务

与前面两种模式不同

生产者与交换机(Exchange)进行绑定,不再与队列(Queue)直接绑定

生产者发送消息到交换机(Exchange),不再直接发送到队列(Queue)

这是生产者发送一条消息,消费者1、消费者2都能接收到消息,就跟广播一样,播放音乐大家都能听到

Routing 路由模型

交换机类型:direct

Routing模型示意图:

P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。

X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列

C1:消费者1,接收到所在队列指定了routing key 为 error 的消息

C2:消费者2,接收到所在队列指定了routing key 为 info、error、warning 的消息

这时生产者发送消息,交换机会根据routing key发送到特定的队列中,不同的routing key可以绑定到相同的队列中。

Topics 通配符模型

交换机类型:topics

Topics模型示意图:

P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。

X:Exchange(交换机),Exchange类型为Topic Exchange,接收生产者的消息,然后把消息递交给与通配符routing key匹配(跟正则匹配差不多)的队列

C1:消费者1,接收到Q1队列的消息

C2:消费者2,接收到Q2队列的消息

这时生产者将消息发给broker,由交换机根据通配符routingkey来转发消息到指定的队列,每个消费者监听自己的

队列。

Routingkey一般都是有一个或者多个单词组成的,多个单词之间是以"."作为分割,例如:inform.order

通配符规则:

#:匹配一个或多个词

*:匹配1个词

举例:

inform.#:能够匹配inform.user.name 或者 audit.order

audit.*:只能匹配audit.order

保证消息的稳定性

消息持久化

RabbitMQ的消息默认存在内存中的,一旦服务器意外挂掉,消息就会丢失

消息持久化需做到三点

  • Exchange设置持久化
  • Queue设置持久化
  • Message持久化发送:发送消息设置发送模式deliveryMode=2,代表持久化消息

ACK确认机制

多个消费者同时收取消息,收取消息到一半,突然某个消费者挂掉,要保证此条消息不丢失,就需要acknowledgement机制,就是消费者消费完要通知服务端,服务端才将数据删除

这样就解决了,及时一个消费者出了问题,没有同步消息给服务端,还有其他的消费端去消费,保证了消息不丢的case。

设置集群镜像模式

我们先来介绍下RabbitMQ三种部署模式:

1)单节点模式:最简单的情况,非集群模式,节点挂了,消息就不能用了。业务可能瘫痪,只能等待。

2)普通模式:默认的集群模式,某个节点挂了,该节点上的消息不能用,有影响的业务瘫痪,只能等待节点恢复重启可用(必须持久化消息情况下)。

3)镜像模式:把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案

为什么设置镜像模式集群,因为队列的内容仅仅存在某一个节点上面,不会存在所有节点上面,所有节点仅仅存放消息结构和元数据。下面自己画了一张图介绍普通集群丢失消息情况

消息补偿机制

持久化的消息,保存到硬盘过程中,当前队列节点挂了,存储节点硬盘又坏了,消息丢了,怎么办?

产线网络环境太复杂,所以不知数太多,消息补偿机制需要建立在消息要写入DB日志,发送日志,接受日志,两者的状态必须记录。

然后根据DB日志记录check 消息发送消费是否成功,不成功,进行消息补偿措施,重新发送消息处理。

如何实现延迟队列

RabbitMQ本身没有延迟队列,需要靠TTL和DLX模拟出延迟的效果

TTL(Time To Live)

RabbitMQ可以针对Queue和Message设置 x-message-tt,来控制消息的生存时间,如果超时,则消息变为dead letter

RabbitMQ针对队列中的消息过期时间有两种方法可以设置。

A: 通过队列属性设置,队列中所有消息都有相同的过期时间。

B: 对消息进行单独设置,每条消息TTL可以不同。

如果同时使用,则消息的过期时间以两者之间TTL较小的那个数值为准。消息在队列的生存时间一旦超过设置的TTL值,就成为dead letter

DLX (Dead-Letter-Exchange)

RabbitMQ的Queue可以配置x-dead-letter-exchange 和x-dead-letter-routing-key(可选)两个参数,如果队列内出现了dead letter,则按照这两个参数重新路由。

x-dead-letter-exchange:出现dead letter之后将dead letter重新发送到指定exchange

x-dead-letter-routing-key:指定routing-key发送

队列出现dead letter的情况有:

  • 消息或者队列的TTL过期
  • 队列达到最大长度
  • 消息被消费端拒绝(basic.reject or basic.nack)并且requeue=false

利用DLX,当消息在一个队列中变成死信后,它能被重新publish到另一个Exchange。这时候消息就可以重新被消费。

相关推荐
弗拉唐9 分钟前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi7741 分钟前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3431 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀1 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20201 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深1 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
shuangrenlong2 小时前
slice介绍slice查看器
java·ubuntu
牧竹子2 小时前
对原jar包解压后修改原class文件后重新打包为jar
java·jar
数据小爬虫@2 小时前
如何利用java爬虫获得淘宝商品评论
java·开发语言·爬虫