消息队列MQ的理解和学习

一、MQ有什么用?有哪些具体的使用场景?

MQ全称MessageQueue, 消息队列。队列是一种FIFO先进先出的数据结构。消息由生产者发送到MQ进行排队,然后由消费者对消息进行处理。QQ、微信 就是典型的MQ场景。
MQ的作用主要有三个方面:
1、异步:
例子:快递。快递员->快递站<-客户(快递员把快递放到快递站,客户什么时候都去快递站拿快递,效率就提高了)
作用:异步能提高系统的响应速度和吞吐量。
2、解耦:
例子:《Thinking in java》-> 编辑社(把书给编辑社翻译);下单之后,其他服务来处理(发起支付、扣库存、发起营销活动、下快递单)
作用:服务之间进行解耦,可以减少服务之间的影响,提高系统的稳定性和可扩展性。另外,解耦之后可以实现数据分发。生产者发送一个消息后,可以由多个消费者来处理。
3、削峰:
例子:长江涨水->三峡大坝;秒杀。
作用:以稳定的系统资源应对突发的流量冲击。
MQ的缺点:
1、系统可用性降低:一旦MQ宕机,整个业务就会产生影响,需要考虑MQ的高可用。
2、系统的复杂度提高:引入MQ之后,数据链路就会变得很复杂。如何保证消息不丢失?消息不会重复调用?怎么保证消息的顺序性?
3、数据一致性:A系统发消息,需要由B、C两个系统一同处理。如果B系统处理成功、C系统处理失败,这就会造成数据一致性的问题。

二、如何进行产品选型?

kafka3.0的基本使用
Kafka
优点:吞吐量非常大,性能非常好,集群高可用。
缺点:会丟数据,功能比较单一。
使用场景:日志分析、大数据采集

RabbitMQ使用教程(超详细)
RabbitMQ
优点:消息可靠性高,功能全面。
缺点:吞吐量比较低,消息积累会严重影响性能。erlang语言不好定制。
使用场景:小规模场景。

RocketMQ从零到学会使用
RocketMQ
优点:高吞吐、高性能、高可用,功能非常全面。
缺点:开源版功能不如云上商业版。官方文档和周边生态还不够成熟。客户端只支持java。
使用场景:几乎是全场景

三、如何保证消息不丢失?

1.哪些环节会造成丢失?

主要是跨网络的一些场景,①生产者调用MQ(向MQ发消息);②消息从主节点同步消息到从节点的时候;③消息··从内存往硬盘存储时;④MQ转发消息到消费者;
在这里插入图片描述
2.怎么防止消息丢失?

2.1生产者发送消息不丢失
Kafka:消息发送+回调
RocketMQ:消息发送+回调;事务消息机制。
以下是事务回调机制(P代表生产者 ,C代表消费者):
在这里插入图片描述
①P向MQ发送half消息;(目的:确定MQ服务正常)
②MQ向P发送half消息响应;(确认MQ服务正常之后,P往本地插入事务)
③P向MQ发送具体消息,并带本地事务状态;
④进行判断:如果状态=成功,则给消费者处理;如果状态=失败则丢弃消息。如果状态=未知,则执行5
⑤如果MQ就会向P发起回查;(检查事务是否执行成功)
⑥P就会检查本地事务的执行状态,返回本地事务状态
⑦检查次数为15次

RabbitMQ:①消息发送+回调;②手动事务:channel.txSelect()开启事务,channel.txCommito提交事务,channell.txRollback()回滚事务。这种方式对channel是会产生阻塞的,造成吞吐量下降。③Publisher Confirm。整个处理流程跟RocketMQ的事务消息,基本是一样的。

2.2MQ主从消息同步不丢失

RocketMQ:①在普通集群中可以配置主从同步,同步同步、异步同步。异步同步效率更高,但是有丢消息的风险(MQ往C发的时候)。同步同步就不会丢消息;普通集群:确定好master节点和seter节点,P往主节点发消息,主节点同步消息到从节点。
②Dledger集群-两阶段提交:跟kafaka集群有点相似,会经常选举master节点,至少有三个节点 。
当P向mq发消息,主节点会给P一个响应,同时给其他节点发起同步,异步同步,并且记录一个状态=uncommited,当大多数节点都同步了,就把状态改为commited。
在这里插入图片描述

RabbitMQ:
普通集群:消息是分散存储的,节点之间不会主动进行消息同步,是有可能丢失消息的。
镜像集群:镜像集群会在节点之间主动进行数据同步,这样数据安全性得到提高。
节点的erlang.cookie 一样就是同一个集群。
Kafka:本来就容易丢消息,通常都是用在允许消息少量丢失的场景。acks跟同步同步和异步同步一样,可以配0、1、all。acks只要master节点同步了就返回状态,还是所有节点都同步了就返回状态,还是异步直接返回状态。

2.3 MQ消息存盘不丢失

RocketMQ:同步刷盘和异步刷盘,可以直接配置,异步刷盘效率更高,但是有可能丢消息。同步刷盘消息安全性更高,但是效率会降低
RabbitMQ:将队列配置成持久化队列。3.x版本新增了一个Quorum类型的队列,会采用Raft办议来进行消息同步,跟RocketMQ的两阶段提交类似,大多数节点同步了就同步了。可以看出来RabbitMQ很多地方都在借鉴RocketMQ。
Kafka:acks

2.4 MQ消费者消费消息不丢失

RocketMQ:使用默认的方式消费就行,
RabbitMQ: 把autoCommit关掉->手动提交offset
Kafka: 改为手动提交offset

四、如何保证消息消费的幂等性?防止消费者重复消费消息

消费者重复消费的场景:当mq向消费者发送消息,消费者收到消息了会返回一个请求。如果没有收到消息就会重复推送消息,也可能向另外集群里面的消费者推送。①网络超时,导致mq重复发消息,消费者消费多次消息;②本地事务的执行时长比mq的长。

所有MQ产品并没有提供主动解决幂等性的机制,需要由消费者自行控制。
RocketMQ:给每个消息分配了个MessagelD。这个MessagelD就可以作为消费者判断幂等的依据。MessagelD不能保证全局唯一,这种方式不太建议。
最好的方式就是自己带一个有业务标识的1D,来进行幂等判断。比如订单OrderId;
或者用redis生产id统一ID分配。

五、如何保证消息的顺序?

全局有序和局部有序:MQ只需要保证局部有序,不需要保证全局有序。
RocketMQ的实现:
producer.send(msg,new MessageQueueSelector())生产者在发消息时注入一个选择队列的工具,把这个消息发到固定的队列上面;
consumer.registerMessageListener(new MessageListenerOrderly())在消费者注册一个有顺序的消费监听.
一个MQ场景下,因为MQ本来就是先进先出的,本来就是顺序的。
在分布式场景下,在Topic下要做好协查调度,有多个队列就无法保证消息的顺序性了。默认情况下,消息发送不到同一个队列上面,因为采取的轮询机制,这些消息放在不同的队列。MessageQueueSelector可以保证所有消息按顺序放到同一个队列上面。
在消费者端,默认是随意并发的拿消息,每次拿32个消息,如果队列里面有很多消息,被不同消费者拿走了,就不能保证他们的顺序性了。只能把这个队列的所有消息都锁住,一次性把所有消息拿给同一个消费者。
总结:生产者把一组有序的消息放到同一个队列当中,而消费者一次消费整个队列当中的消息,从而保证消息的顺序。
在这里插入图片描述
RocketMQ中有完整的设计,但是RabbitMQ和Kafka并没有完整的设计,需要自己进行设计。
RabbitMQ:要保证目标exchange只对应一个队列。并且一个队列只对应一个消费者。(影响性能)
Kafka:生产者通过定制partition分配规则,将消息分配到同一个partition。 Topic下只对应一个消费者。

六、如何保证消息的高效读写?

零拷贝:kafka和RocketMQ都是通过零拷贝技术来优化文件读写。
传统文件复制方式:需要对文件在内存中进行四次拷贝。

在这里插入图片描述
零拷贝的两种实现方式:Mmap和transfile
在这里插入图片描述在Java当中对零拷贝进行了封装,Mmap方式通过 MappedByteBuffer对象进行操作,而transfile通过File Channel来进行操作.

在这里插入图片描述
Mmap适合比较小的文件,通常文件大小不要超过1.5G~2G之间。
Transfile没有文件大小限制。
RocketMQ当中使用Mmap方式来对他的文件进行读写。commitlog. 1G
在Kafka当中,他的index日志文件也是通过mmap的方式来读写的。在其他日志文件当中,并没有使用零拷贝的方式。Kafka使用transfile方式将硬盘数据加载到网卡。

七、使用MQ如何保证分布式事务的最终一致性?

分布式事务:业务相关的多个操作,保证他们同时成功或者同时失败。比如用户下单了,支付和下物流单都要执行成功。
最终一致性:与之对应的就是强一致性。强一致性:电脑操作硬盘,两个页面操作同一个txt文件,都要一致,操作完就改变。

MQ中要保护事务的最终一致性,就需要做到两点
1、生产者要保证100%的消息投递。 事务消息机制
2、消费者这一端需要保证幂等消费。唯一ID+ 业务自己实现幂等
分布式MQ的三种语义:
at least once 最少消费一次
at most once 最好实现,只发送一次
exactly once 刚刚好一次
RocketMQ :并不能保证exactly once。商业版本当中提供了exactly once的实现机制。
kafka:在最新版本的源码当中,提供了exactly once的demo。
RabbitMQ: erlang天生就成为了一种屏障。

八、让你设计一个MQ,你会如何设计? 两个误区: 1、放飞自我,漫无边际。2、 纠结技术细节。

好的方式: 1、 从整体到细节, 从业务场景到技术实现。2、 以现有产品为基础。以RocketMQ为模型

答题思路: MQ作用、 项目大概的样子。
消息由生产者发送到MQ进行排队,然后由消费者对消息进行处理。
1、实现一个单机的先进先出的队列数据结构,然后有一个message,封装了一些字段。 高效、可扩展。消息队列的大小要灵活的伸缩,当消息很多的时候,这个队列要扩容,当消息少的时候,要收缩。
2、将单机队列扩展成为分布式队列。- 分布式集群管理
实现:kfaka用zeekper做集群管理,RocketMQ用NameServer 。
3、基于Topic定制消息路由策略。-发送者路由策略,消费者与队列对应关系,消费者路由策略、顺序消息机制。
生产者发送到topic,当有多个消息要发送时,默认采用轮询机制发送,肯定要定制进行路由选择(Rocketmq有MessageQueueSelector);
怎么将队列的消息发送到消费者,消费者有多个分组, 考虑队列和消费者的对应关系。为了记录消费进度,队列对消费者形成多对一的关系,这样队列的先进先出是由保障的。怎么样构建关系呢?同机房优先策略、均衡分布策略,如果队列和消费者在一个机房,优先建立关系。
怎么去消费消息,如果一个消费者对应多个队列,怎么去拿消息?
一种是采用并发的方式,有两个队列,就用两个线程,一个线程去消费一个队列。为了保证消息链路不被撑破,我们需要对消息的大小进行限制,32个,每一批只拿32个。
怎么保证消息的顺序?需要把指定队列锁住,直到消费完,再消费下一个队列。
4、实现高效的网络通信。- Netty Http

5、规划日志文件,实现文件高效读写。-零拷贝,顺序写。规划日志文件,就是服务重启后, 快速还原运行现场。
RocketMQ当中使用Mmap方式来对他的文件进行读写。commitlog. 1G index日志
6、定制高级功能,死信队列、延迟队列、事务消息等等。- 贴合实际,随意发挥。|
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱喝皮蛋瘦肉粥的小饶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值