RabbitMQ

MQ的作用:

(1)流量削峰:比如双十一会出现瞬间大流量请求,这些请求又不能直接丢弃,则可考虑将请求按照先后顺序存入MQ,然后再按顺序进行处理;

(2)消息异步处理:比如用户注册的场景,一个用户注册之后,可能还涉及到用户的积分信息初始化,但是这个信息不影响用户注册的完成,所以积分信息的初始化可通过MQ异步完成;

(3)系统解耦:一个商城,可分为用户模块、订单模块、支付模块等,各模块之间的通信可通过MQ完成;

使用MQ带来的挑战:

(1)系统复杂性提升;

(2)学习成本;

(3)系统可用性降低:MQ通信可能出现网络问题等;

RabbitMQ

rabbit 工作模型

(1)producer 生产者

(2)Exchange 交换机,不存储消息,只存储消息和队列之间的绑定关系

1)direct 直连:使用明确的绑定键,适用于业务目的明确的场景;

basicPublish(“direct_exchange”,"BingKey",“msg”); //将消息发送到指定交换机

2)Topic 主题:

使用支持通配符的绑定键;适用于根据业务主题过滤消息的场景;

* : 有且只有一个单词

# : 有0个或者多个

basicPublish(“topic_exchange”,"TOPIC.BingKey",“msg”); //将消息发送到指定交换机

绑定关系: *.BingKey  以BingKey结尾,且前面只有一个单词;

3)Fanout 广播

无需绑定键。适用于通用类业务消息;

(3)queue 队列 :存放消息

(4)channel 信道: 存放消息通信的连接,防止每次发送消息都需要重新建立连接;

(5)consumer 消费者

 

高阶应用:

(1)如何实现订单的延迟关闭?

1)先存储到数据库,用定时任务扫描;

使用定时任务每分钟扫描半小时之前且状态为未付款的订单;存在问题:如果订单量过大,一个线程处理起来会产生延时;

2)死信队列

利用消息的过期时间(TTL),将过期的消息发送到死信交换机,再绑定到死信队列,由对应的消费者进行消费;

过期时间的设置方式:a、直接设置消息的过期时间;b、设置队列的过期时间;c、使用rabbitMq插件;

插件:rabbitmq-delayed-message-exchange 可以创建具有延迟投递功能的交换机;

由生产者发送消息的时候指定broker延迟发送给消费者的时间;

 

消息什么时候会变成死信消息:

(1)消息到达过期时间任未被消费;

(2)消费者拒绝了消息,且未设置重回的队列;

(3)队列达到最大长度,先入队的消息会进入死信交换机(DLX);

 

问题:

(1)服务端消息存满了怎么办?

服务端流控:

1)队列长度设置:x-max-length x-max-length-byte

2) 内存控制:

3)磁盘控制

 

消息的可靠投递:

(1)首先在代码里面,是先操作数据库,再发送消息,避免因为数据库回滚导致的数据不一致;

(2)如果在消息发送过程中,出现了消息丢失或重复怎么办呢?

RabbitMQ在设计的时候提供了很多保证消息可靠投递的机制;但是可靠性和性能两者不可兼得,需要在使用的时候加以选择;

根据RabbitMQ的工作模型,消息可靠投递的保证可从以下几个方面进行:

(1)生产者发送消息到Broker(消息服务器)的可靠性;

(2)消息从Exchange路由到Queue的可靠性(无法路由到正确的队列);

(3)消息在Queue中存储的可靠性;

(4)消费者订阅Queue并消费消息的可靠性;

对应解决方案:

(1)服务端确认机制

在生产者发送消息给RabbitMQ服务端的时候,服务端会给出应答。

应答模式:

1)Transaction事务模式

在生产者创建channel的时候将信道设置成事务模式,然后就可以发布消息给RabbitMQ了。如果生产者的channel.txCommit();方法调用成功,说明事务提交成功,消息一定成功到达了RabbitMQ中;

缺点:消息的发送是阻塞的,一条消息没有发送完毕,不能发送下一条;

2)Confirm确认模式

a、普通确认模式

生产者通过channel.confirmSelect();将信道设置为Confirm模式,一旦消息被投递到交换机以后,RabbitMQ服务端会发送一个确认(Basic.ACK)给生产者;

缺点:如果批量确认100条消息,前面99条都成功了,最后一条失败了,那么这100条都需要重新发送;

b、异步确认模式

一边发送一边确认的模式;

添加一个ConfirmLister,并用SortedSet来维护未被确认的消息;

(2)无法正确路由的消息处理:

a、消息回发

让服务端回发给生产者;

b、消息路由到备份交换机

(3)消息在队列中存储的可靠性

如果没有消费者,队列一直存储在数据库中,如果RabbitMQ的服务或者硬件异常,可能会导致内存中的数据丢失,所以需要把消息和元数据(队列、交换机、绑定关系)保存到磁盘;

(4)消息投递到消费者

消费者消息确认机制:自动或手动地发送ACK给服务端;

 

正常情况下,消费者收到消息后给服务端一个ACK,但是生产者是不知道的,这是符合解耦的思想的。

但如果特殊场景下需要保证一致性,生产者需要知道消费者有没有成功消费:

1)消费者收到消息,处理完成后,调用生产者的API;

2)消费者收到消息,处理完成后,发送一条响应给生产者;

这种消费者回调的机制,也有可能出现API调用失败或者响应失败的情况,那么可以设置一个补偿机制;

约定响应超时时间,如果没有回复则认为消费失败,则进行重发;

 

消息幂等性

如果生产者正常,消息也正常消费,只是调用回调API或者响应的时候失败,导致重复发送消息的情况怎么解决?

消息重复可能的原因:

1)生产者问题,生产者发送消息到broker的时候,开启了cofirm模式但未收到确认,消费者重复投递;

2)消费者消费消息的时候未发送ACK,导致消息重复消费;

由于生产者并不知道业务上什么样的消息才算重复,因为只能在消费端进行控制。

消费端可以针对每条消息生成业务ID,通过日志或者消息落库来判断重复;

 

消息的最终一致性

人为进行干预,保证数据的最终一致性;比如银行系统的对账和冲账

消息的顺序性

一个队列对应多个消费者时,由于消费者消费消息的速度不一样,不能保证消息的顺序性,因此一般情况下,将不同的业务消息存放到不同的队列。

 

RabbitMQ集群与高可用

RabbitMQ如何支持集群?

rabbitmq通过erlang.cookie来验证身份,需要在所有节点上保持一致;

服务的端口:5672 UI的端口:15672 集群的端口:25672

需要注意的是,RabbitMQ集群无法搭建在广域网上,需要在同一个机房。

RabbitMQ节点的类型:

1)磁盘节点

将元数据(队列名字、交换机类型和名字、绑定关系、Vhost等信息)保存在磁盘;默认为磁盘节点;

集群中至少需要一个磁盘节点,否则服务宕机的时候无法恢复数据;

2)内存节点

内存节点会将磁盘节点的地址存放在磁盘(否则重启之后无法恢复数据)。如果是持久化的消息,会同时存放在内存和磁盘;

一般情况,我们的应用连接内存节点(读写快),用磁盘节点备份数据;

RabbitMQ集群模式

1)普通集群

普通集群模式下,节点之间只会同步元数据(交换机、队列、绑定关系、Vhost);

每个节点上存储不同的消息,如果一个节点操作不在自己服务器上的消息,此时会进行消息的转发。

存在问题:如果节点挂了,那么对应的数据也就全部丢失,无法实现高可用。

2)镜像集群

消息内容会在节点间进行同步,系统可用性更高,但是会消耗系统性能。

 

常见面试题

1、RabbitMQ消息快速积压怎么处理?

出现积压的原因:

1)没有消费者消费消息;

2)生产者产生消息速度过快,消费者消费能力跟不上;

3)消费者消费消息以后没有给Broker发送ACK,导致队头消息不出队,后续消息不能消费;

解决途径:

(1)如果出现生产者不断重复发送消息的情况,需要立即停掉;

(2)Broker:

a、broker磁盘存储受限,升级硬件;

b、如果无法升级硬件,可以通过磁盘和内存限制控制堆积的消息数(当内存或磁盘超过配置的阈值时,Broker会暂停读取发布消息的客户端的连接);

c、对消息设置过期属性;

d、如果消息不重要,可以直接丢弃;写一个程序消费消息,然后直接丢弃;

(3)消费者

a、增加消费者个数,或者多线程消费;

b、如果是因为队头的消息没有ACK导致的,可以重启消费者,重新消费,然后发送ACK;

c、消费者代码问题,则修复程序;

2、Channel和Vhost的作用是什么?

Channel:减少TCP资源消耗,也是最重要的编程接口;

Vhost:提高硬件资源利用率,实现资源隔离;

3、RabbitMQ的路由方式有哪些?分别适合于什么样的场景?

4、无法被路由的消息去了哪里?

5、消息什么时候会变成死信消息?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值