RabbitMQ简介
1.什么是MQ
MQ全称为Message Queue-消息队列,是一种应用程序对应用程序的消息通信,一端只管往队列不断发布信息,另一端只管往队列中读取消息,发布者不需要关心读取消息的谁,读取消息者不需要关心发布消息的是谁,各干各的互不干扰。(简单理解就是两个应用之间的数据传输)
2.为什么使用MQ
2.1 解耦
引入MQ后,不需要关心发布者及消费者之间的关系,这两者不需要彼此联系,减少系统之间的直接依赖。
2.2 异步
对于数据量大或者处理耗时长的操作,可以引入MQ 实现异步通信,减少客户端的等待,提升响应速度。
2.3 削峰
对于会出现瞬间的流量峰值的系统,可以引入MQ 实现流量削峰,达到保护应用和数据库的目的。
3.各消息中间件的比较
四大主流MQ(kafka、ActiveMQ、RabbitMQ、RocketMQ)
|
ActiveMQ |
RabbitMQ |
RocketMQ |
kafka |
|
|
吞吐量 |
万级 |
万级 |
十万级 |
十万级 |
|
时效性 |
ms级 |
微妙级 这是RabbitMQ的一大特点,延迟是最低的 |
ms级 |
ms级 |
|
特性 |
单机吞吐量万级,时效性 ms 级,可用性高
官方社区现在对 ActiveMQ 5.x 维护越来越少,高吞吐量场景较少使用。 |
由于 erlang 语言的高并发特性,性能较好,MQ 功能比较完备,健壮、稳定、易用,社区活跃度高;更新频率相当高
商业版需要收费,学习成本较高 |
单机吞吐量十万级,可用性非常高,分布式架构,消息可以做到 0 丢失,MQ 功能较为完善
支持的客户端语言不多,目前是 java 及 c++,其中 c++不成熟;社区活跃度一般。 |
性能卓越,吞吐量高。在大数据领域的实时计算以及日志采集被大规模使用
消费失败不支持重试,社区更新较慢; |
|
应用场景 |
ActiveMQ支持任何消息传递用例的能力和灵活性,比较适合小型吞吐量比较小的公司进行使用。 |
结合 erlang 语言本身的并发优势,性能好时效性微秒级,社区活跃度也比较高,如果你的数据量没有那么大,中小型公司优先选择功能比较完备的 RabbitMQ。 |
天生为金融互联网领域而生,适用于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰。 |
Kafka 主要特点是追求高吞吐量,一开始的目的就是用于日志收集和传输,适合产生大量数据的互联网服务的数据收集业务。 |
4.消息发送类型(基于RabbitMQ说明)
4.1 简单模式

4.1.1 概念
生产者和消费者在发送和接收消息时,只需要指定队列名称,而不需要指定交换机。(单发送单接收)
4.1.2 使用场景
简单的发送与接收,没有特别的处理。
4.1.3 隐患
消息的消费者(consumer) 监听 消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除。
消息可能没有被消费者正确处理,就已经从队列中消失了,造成消息的丢失。
这里可以设置成手动的ack,但如果设置成手动ack,处理完后要及时发送ack消息给队列,否则会造成内存溢出。
4.1.4 代码例

手动确认 代码简要说明:
开启手动确认

消费者:

4.2 队列模式

4.2.1 概念
一个生产者将消息发给多个消费者,在多个消费者之间分配消息,类似轮询发送消息,每个消息都只发给一个消费者。(单发送多接收)
4.2.2 使用场景
一个发送端,多个接收端,如分布式的任务派发。特别适合在集群环境中做异步处理,能最大程序发挥每一台服务器的性能。在高并发情况下,队列里面的消息很容易产生积压,此模式可以扩容消费者进行负载均衡处理消息。
4.2.3 隐患
C1、C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息
高并发情况下,默认会产生某一个消息被多个消费者共同使用,所以在处理消息之前要对消息进行加锁及判断该消息是否被处理, 保证一条消息只能被一个消费者使用
4.2.4 代码例

4.3 发布订阅模式(扇形交换机 Fanout)

4.3.1 概念
指定交换机 不指定路由,将消息发送给多个队列(发送一条消息,绑定的队列都能接收到消息)
4.3.2 使用场景
发布/订阅模式中,交换机将无差别的将所有消息送入与之绑定的队列,所有消费者拿到的消息完全相同。
中国气象局提供“天气预报”送入交换机,网易、新浪、百度、搜狐等门户接入通过队列绑定到该交换机,自动获取气象局推送的气象数据。
4.3.3 代码例

4.4 路由模式(直连交换机 Direct)

4.4.1 概念
路由(Routing)模式是在发布订阅模式基础上的变种,发布订阅模式是无条件将所有消息分发给所有消费者队列。路由模式则是 Exchange 根据 Routing Key 有条件的将数据筛选后发给消费者队列。
4.4.2 使用场景
监控日志,对于不同级别日志来说,对于 error 级别的日志信息可能是我们需要特别关注的,会被单独的消费者进行处理,此时交换机分发消息是有条件的进行分发,这个就是根据 Routing Key 进行不同的消息分发。
4.4.3 代码例

4.5 主题模式(主题交换器 Topic)

4.5.1 概念
和4.4中的路由模式类型类似 只是可以根据通配符,匹配路由键转发消息。
4.5.2 使用场景
iphone 促销活动可以接收主题为 iphone 的消息,如 iphone12、iphone13 等
在实际使用场景中, 路由模式的效率是高于主题模式,实际工作中可以使用路由模式解决的问题就尽量不要采用主题模式。
4.5.3 代码例
创建队列
两个队列test-queue和test-queue2,其中队列test-queue负责接收路由键以insert结尾的消息
其中队列test-queue2负责接收路由键以update结尾的消息。

4.6 RPC模式

4.6.1 概念
和上述不同的是,生产者可接收到消费者的返回值
MQ 本质上都是异步通讯的,作为生产者将消息送达消息队列后,他的任务就完成了。至于消费者什么时候消费的,生产者是不关心的。所以这种模式在实际工作中不怎么用。
4.6.2 使用场景
对于消息可靠性要求较高,比如订单支付 钱包扣款,需要等待消费者返回数据,再进行处理。
4.6.3 代码例

5.总结
5.1 交换机类型
上面的 订阅发布模式、路由模式以及主题模式使用到了不同的交换机,分别是:
-
扇形交换机 Fanout
-
直连交换机 Direct
-
主题交换器 Topic
5.1.1 扇形交换机 Fanout
扇形交换机没有路由键的概念,只需将队列绑定在交换机上,发送到交换机上的消息会转发到交换机所以绑定的队列里面,类似广播,只要打开收音机都能接收到广播消息。扇形交换机应用于发布订阅模式。
5.1.2 直连交换机 Direct
直连交换机被应用在路由模式下,该交换机需要通过特定的routingKey来绑定队列,交换机只有接收到了匹配的routingKey才会将消息转发到对应的队列中,否则就不会转发消息。
5.1.3 主题交换器 Topic
主题模式是将路由键根据一个主题进行分类,和直连模式不同的是,直连模式绑定特定的路由键,而主题模式使用通配符绑定路由键,绑定键有两种:* 表示可以匹配仅一个,#表示可以匹配零个或多个。
5.2 MQ存在的问题有哪些?
5.2.1 消息丢失
各种原因,网络问题,mq故障等,需要保证可靠性传输
解决:消费者手动确认
5.2.2 消息重复
对于重复消费,我们需要改造业务处理逻辑,使得在重复消息的情况下也不会影响最终的结果。
对于要处理的消息,要确认是否已经处理过。常规通过唯一标识符,来区分是否处理过。
-
如果一个业务是只读业务,或者是更新的业务,那么多次读取或者多次更新相同的数据基本上都没什么问题。
-
如果业务需要插入数据,但是插入的数据中有唯一key能够区分(比如订单编号或流水号),那么业务逻辑就可以变成在插入前先查询这个唯一key是否在数据库中,如果存在说明此前已经成功消费了这条消息,不再消费,否则就是没有成功消费,继续消费。
-
通过数据库的方式来防止重复消费的都属于“强校验”类型,会一定程度上影响数据库性能,通常涉及到金钱的都需要强校验,如果不需要强校验,那么使用Redis来代替也行,比如消费者消费时将id或者唯一标识作为key存入Redis,消费者消费时先判断是否存在id。
上面的都是通用的办法,但处理重复消费的问题,始终要根据具体业务来考虑自己的解决办法。(本地数据库表或Redis缓存消费成功的业务标识,每次处理前先进行校验,保证幂等。)
5.2.3 消息堆积
队列中消息不能被及时的消费,导致大量堆积在队列里面
解决:提高消费者的处理能力(队列模式 扩容消费者),增加MQ的服务器资源,cpu、内存、磁盘,提高mq处理能力。
6.参照资料
https://developer.aliyun.com/article/769883
https://developer.aliyun.com/article/759354
https://developer.aliyun.com/article/1102487
本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/f8b4ad8ccf.html




