Message Queue(消息 队列),从字⾯上理解:⾸先它是⼀个
队列。遵循FIFO 先进先出的数据结构———队列。消息队列就是所谓的存放消息的队列。
消息队列解决的不是存放消息的队列的⽬的,解决的是通信问题。
一、应用场景
1.1、流量削峰
举个例子,如果订单系统最多能处理一万次订单,这个处理能力应付正常时段的下单时绰绰有余,正 常时段我们下单一秒后就能返回结果。但是在高峰期,如果有两万次下单操作系统是处理不了的,只能限 制订单超过一万后不允许用户下单。使用消息队列做缓冲,我们可以取消这个限制,把一秒内下的订单分 散成一段时间来处理,这时有些用户可能在下单十几秒后才能收到下单成功的操作,但是比不能下单的体 验要好。
1.2、应用解耦 异步调用
1.2.1、传统模式下
如图所示:对于 创建订单、扣减库存、加积分、优惠券、这些操作
- 传统模式下只能 同步操作 耗时会比较长,而且整个过程会受网络波动的影响,并且可能某次调用失败后整个调用链路都会收到影响
1.2.2、消息队列方式
使⽤异步的通信⽅式对模块间的调⽤进⾏解耦,可以快速的提升系统的吞吐量。上游执⾏完消息的发送业务后⽴即获得结果,下游多个服务订阅到消息后各⾃消费。
通过消息队列,屏蔽底层的通信协议,使得解藕和并⾏消费得以实现。
二、介绍
市⾯上⽐较⽕爆的⼏款MQ:ActiveMQ,RocketMQ,Kafka,RabbitMQ。
语⾔的⽀持:ActiveMQ,RocketMQ只⽀持Java语⾔,Kafka可以⽀持多们语⾔,RabbitMQ⽀持多种语⾔。
效率⽅⾯:ActiveMQ,RocketMQ,Kafka效率都是毫秒级别,RabbitMQ是微秒级别的。
消息丢失,消息重复问题:RabbitMQ针对消息的持久化,和重复问题都有比较成熟的解决方案。
RabbitMQ严格的遵循AMQP协议,高级消息队列协议,帮助我们在进程之间传递异步消息。
RabbitMQ官网:rabbitmq.com/
三、安装
官方安装方式:rabbitmq.com/download.ht…
方式安装选其一即可
3.1、docker方式安装
# latest RabbitMQ 3.11
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.11-management
3.2、docker-compose方式安装
3.2.1、编写docker-compose.yml
version: "3.1"
services:
rabbitmq:
image: daocloud.io/library/rabbitmq:management
restart: always
container_name: rabbitmq
ports:
- 5672:5672
- 15672:15672
volumes:
- ./data:/var/lib/rabbitmq
3.2.2、运行
# 在docker-compose.yml文件所在的目录下执行,以后台方式运行
docker compose up -d
3.3、开放15672端口
防火墙开放端口:juejin.cn/post/715943…
# 开放15672端口
firewall-cmd --zone=public --add-port=15672/tcp --permanent
# 更新配置信息(这样就不需要重启防火墙了)
firewall-cmd --reload
3.4、访问测试
http://192.168.68.68:15672/
账号密码:guest
四、RabbitMQ架构
4.1、简单架构图
- Publisher - ⽣产者:发布消息到RabbitMQ中的Exchange
- Consumer - 消费者:监听RabbitMQ中的Queue中的消息
- Exchange - 交换机:和⽣产者建⽴连接并接收⽣产者的消息
- Queue - 队列:Exchange会将消息分发到指定的Queue,Queue和消费者进⾏交互
- Routes - 路由:交换机以什么样的策略将消息发布到Queue
4.2、虚拟主机
五、RabbitMQ队列模式
5.1、简单队列模式
- 生产者:使用默认的交换机,可以直接创建队列,
- 消费者:只有一个消费者来处理消息
5.2、work队列模式(WorkQueues)
一个消息只能被处理一次,不允许重复消费,采用轮询的方式分发消息
- 生产者:使用默认的交换机,可以直接创建队列,
- 消费者:可以有一个或多个消费者,轮训接收消息
弊端:当多个消费者消费同一个队列时,如果某个消费者消费能力弱(耗时较长)时,其他消费者会等待这个消费者消费完毕后才能进行消费
5.3、发布订阅模式(Publish/Subscribe)
该模式下消费者都有自己的队列,比如 生产者 生产100条消息,那么所有的消费者都可从队列中拿到100条消息。举个例子,公众号中,号主发布一篇文章,所有的关注者都会收到消息。
5.3.1、交换机(Exchange)
发布订阅模式 引入了交换机的概念,他一方面,用来接收生产者发送的消息。另一方面,知道如何处理消息,例如传递给某个特别的队列、提交给所有队列、或者将消息丢弃。到底如何操作,取决于Exchange的类型。常见的 Exchange 有以下三种类型:
- Fanout:广播 ,将消息交给所有绑定到交换机的队列
- Direct:定向 ,把消息交给符合指定
routing key的队列 - Topic:通配符 ,把消息交给符合
routing pattern(路由模式)的队列
交换机只用于消息的转发,不具备存储消息的能力,因此队列需要和交换机需要和队列做绑定,否则就收不到消息。如果没有符合路由规则的队列,那么消息会丢失!
5.4、路由工作模式(Routing)
一个交换机可以绑定一个或多个 Routing Key
5.5、主题模式(Topics)
通配符模式
四、消息的可靠投递
在使用RabbitMQ的时候,作为消息发送方 希望杜绝任何消息丢失或者投递失败场景 。RabbitMQ为我们提供了 两种方式用来控制消息的投递可靠性模式
- confirm确认模式
- return退回模式
rabbitmg整个消息投递的路径为:
Producer ---> Exchange ---> Queue ---> Consumer
Producer将消息发送到指定Exchange,Exchange收到消息后再将消息通过RoutingKey的方式路由的Queue队列暂存消息,Consumer监听队列,拿到对应的消息数据
在整个投递过程中任何一个环节都有可能投递失败:
- 消息从 producer 到 exchange 则会返回一个 confirmCallback 。
- 消息从 exchange–>queue 投递失败则会返回一个 returnCallback 。
- ACK 消费者收到消息后确认
- 自动确认acknowledge=“none”:当消费者接收到消息的时候,就会自动给到RabbitMQ一个回执,告诉MQ我已经收到消息了,不在乎消费者接收到消息之后业务处理的成功与否。
- 手动确认acknowledge=“manual”:当消费者收到消息后,不会立刻告诉RabbitMQ已经收到消息了,而是等待业务处理成功后,通过调用代码的方式手动向MQ确认消息已经收到。当业务处理失败,就可以做一些重试机制,甚至让MQ重新向消费者发送消息都是可以的。
- 根据异常情况确认acknowledge=“auto”:该方式是通过抛出异常的类型,来做响应的处理(如重发、确认等)。这种方式比较麻烦,一般不用。
五、TTL
- TTL全称Time To Live(存活时间/过期时间)。
- 当消息到达存活时间后,还没有被消费,会被自动清除。
- RabbitMQ可以对消息设置过期时间,也可以对整个队列(Queue)设置过期时间。
六、死信队列 Dead Letter Exchange(死信交换机)
死信队列,英文缩写:DX。Dead Letter Exchange(死信交换机),当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机就是死信交换机。
队列绑定死信交换机:
给队列设置参数:x-dead-letter--exchange 死信交换机名称 和 x-dead-letter-routing-key 死信交换机绑定的RoutingKey
死信队列实现方式:
1、声明正常的队列(boot_queue)和交换机(boot_exchange)
2、声明死信队列(boot_queue_dlx)和死信交换机(boot_exchange_dlx)
3、正常队列绑定死信交换机
需设置两个参数:
x-dead-letter-exchange:死信交换机名称
x-dead-letter-routing-key:发送给死信交换机的 routingkey