1.为啥要用mq?优点是啥?
-
异步通讯 ,帮助我们微服务的解耦,降低我们业务场景的复杂度
-
整个耦合执行效率解耦后 执行效率变高
-
吞吐量高, 但是消费者能力不足时,可能会造成消息堆积
-
流量削峰, 拿时间换空间
-
mq代码层面执行发送消息服务 执行效率是很高的
2.怎么保证消息发送到了mq?又如何保证消费者接收到消息?(如何保证消息不丢失?)
-
生产者保证消息发送到mq, 开启confirm确认模式
-
消息的生产者 通过channel的confirm模式 进行消息的发送
-
发送到queue当中后,queue要给消息的生产者一个ack回告
-
消息的生产者收到ack之后,才确认消息发送到我们的消息队列
-
如果mq开启了持久化,消息会在持久化之后给消息的生产者一个ack回告
-
-
消费者保证接收消息
-
消费者从队列当中接收到消息
-
消费者默认情况是自动进行消息的回告,回告队列消息已确认
-
队列收到回告,删除被消费消息
-
将自动回告修改为手动回告,放在处理消息之后
-
3.消息队列里的消息丢了怎么办?怎么解决?消费者消息丢失怎么办?
-
消息的发送者没有收到队列的回告 消息持久化的回告 消息的发送者在一定内未收到 会重新发送消息
-
mq内部 会给消息的发送者发送的每条消息定义一个唯一的msg_id 就是为了防止消息的重复发送
-
消费者
-
消费者在收到消息且自动进行消息确认的回告,还未进行消息的处理,当前消费者宕机,可能会造成消息丢失,因为在给队列回告时,队列已经将消息给删除了
-
取消消息确认的自动回告,在我们的消费逻辑执行完成之后,再进行手动回告,队列再进行消息的删除
-
4.有了解过消息幂等吗?作用是啥?如何做消息幂等?(重复消费怎么做?)
-
对于重复消息,我们仅处理一次。这个过程就是保证消息幂等。
-
场景:消息的消费逻辑是进行库存的扣减,如果重复消费,会造成超卖/负卖。
-
例子:工单 定义消息的唯一标识(bizId)
-
工单编号+状态+时间 100_1_2022-12-03
-
-
消息的发送者和消息的消费者 需定义一个业务上的唯一id
-
消息的发送者发送的消息的时候 协议中 是要带你们定义的唯一标识
-
消费者在解析时,进行唯一id的去重执行 (执行过的消息再次接收时进行丢弃)
-
建议采用redis进行 唯一id的存储 在每次消费的时候 去redis查询一下 是否存在相同的id
-
如果有 消费者把消息丢弃掉(return掉)
-
如果没有 才正常执行 执行完 将唯一消息id 存储在redis中
-
-
5.RabbitMq的工作模式(消息模型)有哪些?
-
简单队列(simple Queue)
-
工作队列(work Queue)
-
基于交换机的发布订阅模式
-
Fanout(广播)
-
Direct(路由)
-
Topic(通配符)
-
6.消息持久化的条件有了解吗?(如何做消息的持久化?)
-
声明队列必须设置持久化 durable 设置为 true
-
消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)
-
消息已经到达持久化交换器
-
消息已经到达持久化队列
7.死信队列有了解过吗,项目中如何使用?一般作用什么场景?
-
什么消息会被投递到死信队列?
-
你得配置了死信队列(普通队列),死信队列下绑定了对应的死信消费者
-
消息被拒绝
-
消息TTL过期
-
队列达到最大长度
-
-
延迟消息场景,延迟队列
-
即消息进入队列后不会立即被消费,只有到达指定时间后,才会被消费
-
-
使用场景
-
订单在十分钟之内未支付则自动取消
-
用户注册成功后,如果三天内没有登陆则进行短信提醒
-
用户发起退款,如果24h内没有得到处理则通知相关客服人员/直接退款
-
预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议(飞书,钉钉,企业微信)
-
8.消息积压怎么处理?
-
当消费者消费消息的速率<生产者生产消息的速率时,会造成消息积压
-
如果上述问题长时间存在,会存在消息溢出的问题
-
-
可以增强消费者消费能力来缓解
-
通过代码层面的优化来提高单台消费者的消费能力
-
使用多线程来消费消息
-
-
通过增加消费者数量,来提升消费者能力,多加几台消费者服务器
-
成本增加
-
-
-
可以在消息的生产者之前,进行消息的限流,防止消息积压
-
可能导致调用方服务失败,或者影响调用方正常的系统逻辑(改变调用策略)
-
-
可以手动去释放mq压力
-
通过手动方式去将积压的消息 给丢弃掉
-
需要记录丢弃的消息 在消息非积压时 将丢弃的消息 重新投递到队列当中
-
消息延迟了 比正常情况下 时间要久
-
保证消息的最终一致性
-
-
增加队列存储能力
-
弹性扩容
-
镜像集群模式
-
9.mq是如何去做的负载均衡?
-
producer发送消息的负载均衡:默认会轮询向Topic的所有queue发送消息,以达到消息平均落到不 同的queue上;而由于queue可以落在不同的broker上,就可以发到不同broker上
-
consumer订阅消息的负载均衡:假设有5个队列,两个消费者,则第一个消费者消费3个队列,第二 个则消费2个队列,以达到平均消费的效果。而需要注意的是,当consumer的数量大于队列的数量的 话,多出来的队列不会去消费数据,因此建议consumer的数量小于或者等于 queue的数量,避免不必要的浪费
-
如何保证消息的最终一致性?(如何保证消息的事务?)
-
生产者发送一条消息,最终是达到预期的效果
-
导致最终消息不一致
-
生产者丢失消息, 消息队列丢失消息,消费者丢失消息
-
生产者发消息,指定confirm模式,未来,队列会给生产者一个ack回告,以此来保证生产者和消息队列的消息一致性
-
消息队列声明为持久化
-
消费者在消费的时候,由于宕机/异常/重复消费,也有可能导致消息不一致
-
宕机:
-
补发消息
-
需要你手动去重新发一下消息
-
-
消息自动回告变更为手动回告
-
-
异常:
-
取消消息确认的自动回告,在我们的消费逻辑执行完成之后,再进行手动回告,队列再进行消息的删除
-
先定义 异常的影响范围
-
如果你负责的是非常核心的业务,排查是否是因为最近发布导致的 如果是这种情况 回滚到上个代码版本重新发布
-
如果是非核心业务,看看日志,分析定位一下bug的位置,修改bug,测试,上线
-
-
-
重复消费
-
保证我们消息幂等,防止消息重复消费
-
-
-
-
10.队列中的消息能无限制的存储吗? (消息存满了怎么办?)
-
扩容&&镜像集群
-
提高消费者的消费能力,降低生产者生产消息的速率,手动回收一些消息,等闲时再将消息投递到我们的队列当中
-
可以认为是无限制,因为限制取决于机器的内存,但是消息过多会导致处理效率的下降。会将多余的消息存入到磁盘当中,等队列当中有空余的内存,再将消息投递回来,进行消费
11.怎么保证高可用?rabbitmq的集群模式有了解吗?
-
单机模式(工作场上没有)
-
本地搭建一个mq的demo
-
-
普通集群模式(工作场上可能有)
-
只有一个队列是存储消息,其他的节点仅仅提供接收消息的服务,提升mq的吞吐量
-
-
镜像集群模式
-
单机模式与普通集群模式无法满足高可用,镜像集群模式指定多个节点复制 queue 中的消息做到高可用,但消息之间的同步网络性能开销较大
-
12.你们mq目前tps大概多少?这么大tps你消息队列能存的住吗?如果存不了怎么办?
-
测试场景下,50 以内
-
搭建镜像集群
-
磁盘
13.有没有踩过mq什么坑?(做项目的时候有没有遇到过什么难点?)
-
消息丢失
-
由于异常导致消息丢了 但是队列里面消息也删除了 因为你进行了消息确认的自动回告
-
将自动回告改成了手动回告,在我们代码里面,业务处理完成之后,写了一段代码去手动确认消息消费,这样就能保证我们的消息在消费者中是不丢失的。
-
setReturnsCallBack(); 消费者消息确认机制
-
setConfirmCallBack(); 生产者消息确认机制
-
-
try{"消费者逻辑"}catch{"重试"}finally{"验证最终结果是否符合预期,报警"}
-
try{"库存减1"}catch{"库存减1"}finally{"查询数据库库存是否减1,如不符合预期,报警"}
-
-
-