1, 什么是mq
a: mq 就是消息队列, 是基础数据结构的 ”先进先出“ 的一种数据结构,
一般用来解决 , 解耦、异步消息、 流量削峰,等问题,高可用、可伸缩和最终一致性架构。
1, 解耦 : 一个业务需要多个模块共同实现,或者一条消息有读个系统对应处理,只需要在住业务完成以后,发送一条mq, 其余模块消费mq 消息,即可实现业务,降低模块之间的耦合
异步: 主要业务执行结束后,从属业务通过mq 异步处理, 减少业务的响应时间,提高用户体验。
削峰: 高并发下,业务异步处理,提供高峰期业务处理额能力,避免瘫痪。
(这也是mq 三个特性)
2, mq 是怎么实现消息传递的?
a: 生产者产生消息并把输出的数据放在队列中,用队列机制来实现消息传递,消费者可以把指定的队列拉去消息,或者订阅队列,或者mq 服务端推送消费者。
3 ,为什么要用mq ?
a: 这个问题很关键,面试关的意图就是想知道,你真实项目中,是否用到了mq ,举出业务场景,解决了什么问题,不用这种mq 会有什么麻烦,类似常用的场景还有哪些?
我举个例子,我们有个业务用到阿里的隐私号服务,隐私号电话接通挂断以后会生产电话记录录音文件等信息,阿里提供里回调地址和订阅两种方式,我们收到推送电话记录但是,其中有一个录音文件地址,收到后并未生成(其实这应该阿里的一个bug )但是我们接到推送了会做一系列业务操作和入库处理,由于没有第一时间收到录音文件,我们使用了mq 先通话记录的callid 和 地址放到mq 中10分钟,
AMQ_SCHEDULED_DELAY 这里用力activemq 的 属性,broker 会延迟设定时间投递,消费者消费时候如果还未生产文件,则延时20分钟投递,... 这里就利用到了mq 的异步,和解耦。
削峰: 假设双十一,秒杀这种场景,到某个时候,瞬间数据库,访问量上来,mysql数据库的访问效率是 2k/s 个, 现在来了五万个 直接崩溃,这里直接使用mq 将访问消息放到队列中, mysql 每次取2k/s 消费, 。。。 就可以避免击穿, 但是当mq 中消息堆积了也不行,可以考虑分布式,多节点处理。
mq 的四大消费问题 ? 消息不丢失, 消息积压, 消费顺序性
rabbitMq ,
1,生存之把消息发送打mq serve 的过程丢失
从生产者发送消息的角度,提供了一个confirm 消息确认机制,生产者发送消息到server 以后,如果消息处理成功, server端会返回一个ack 消息,客户端可以根据消息的处理结果决定是否要做消息的重新发送,从而确保消息一定到达rabbit server 上。
2,rabbitmq server 收到消息后在持久化之前宕机,数据未到达队列导致数据丢失
在发布消息时候,可以设置消息持久化属性,使其在rabbit mq 服务器宕机后仍然保存在磁盘上,这样即时服务宕机消息仍会保存看病冲洗服务后回复,使用事务来确保消息的持久化和发送的原子性,开启事务后,mq 会等待消息完全写入磁盘才确认发布成功
3, 队列中的数据还未被消费就宕机,独立的数据消息丢失
创建丢列有属性可以设置持久化,这样在mq 宕机时,未消费的消息也会将被持久化到磁盘,回复到队列中。
4, 消费端收到消息还没来及处理宕机,导致mq serve 认为这个消息已经签收
把消息的自动确认机制改成手动,也就是消费端只有手动调用消息确认方法才表示消息已经签收。
Mq 百万消息持续积压
消息积压的原因生产者的消息生产速度大于消费者速度,遇到这个问题的时候,需要排查具体的原因再提出解决问题方案。
1, 流量变大,
采用异步处理,或者时采用懒性队列扩大交换机和消费者之间的消息积压空间,正常队列把消息放到内存中,可利用空间较小,惰性队列接收到消息后直接存入到磁盘,。
2,消费者崩了, 消息堆积不消费
重启服务
rabbit mq 消息重复消费问题
消息去重: 在消费者端,接收到的消息进行去重操作,可以通过维护一个消息id 的集合,或者使用为唯一表示查数据库,来判断小是否消费,消费类不重复消费,
消息取机制,可以确保消息正常消费,消费玩,手动向mq发送消息,告知mq 该消息已经消费成功,mq 会将消息标记已确认,然后删除消息队列消息。
rabbit mq 消息的消费顺序问题
业务中可能会存在读个消息需要顺序处理的情况, 比如生成订单和扣库存,一定是先生成订单后扣库存,但是我们都是集群部署, 一个队列就会有多个消费者,?
本身并不能直接保证消息的消费顺序,因为其基于amqp 协议, 它使用多个消费者在多个线程上并行消费,但是可以采取一下方式:
1, 单消费者对单队列, 可以给rabbtimq 创建多个 队列, 每个消费者只消费一个队列,这样同一个订单号的消息就只会被同一个消费者顺序消费。
2,使用多个队列和分区: 可以将相同类型的消息发送到多个队列,并使用分区建 routingKey 决定消息要发送到那个队列,然后在
消费者端,针对每个队列都是用单个消费者来保证消息的消费顺序。
3,在消费者内部排序