MQ有什么用?有哪些场景?
MQ(MessageQueue)消息队列。队列(FIFO)先进先出的数据结构,消息由生产者发送到MQ,后由消费者对消息进行处理。QQ,微信就是MQ场景。
MQ作用:
- 异步。快递员 -> 菜鸟驿站 <-客户。作用:提高响应速度和吞吐量。
- 解耦。java -> MQ ->Python。作用:服务间解耦,减少服务间影响,提高系统的稳定性和可扩展性。可一对多处理消息
- 削峰填谷。瞬间流量 -> MQ -> 闲时处理。作用:以稳定系统对突发的流量冲击。
MQ缺点:
- 系统可用性降低,MQ宕机整个业务产生影响。
- .系统的复杂度提高,引入MQ后,数据链路变得复杂。要保证消息不丢失,不重复调用,消息顺序性。
- 数据一致性,A系统发消息,需要B,C统一处理,B成功,C失败会造成数据一致性问题。
如何进行产品选型?
Kafka:吞吐量非常大,性能好,集群高可用。缺点:会丢失据,功能单一。场景:数据量大,丢失不影响。如日记,大数据采集
RabbitMQ:可靠性高,功能全面。缺点:吞吐量较低,消息积累影响性能。erlang语言不好优化。场景:小规模
RocketMQ:高吞吐,高性能,高可用,功能全面。缺点:开源版不如商业版。生态不成熟,只支持java。场景:几乎全场景。
如何保证消息不丢失?
- 那个环节会造成消息丢失
跨网络时会造成消息丢失
1.1 生产者发消息
1.2 主从同步
1.3 硬盘同步消息
1.4 消费者接收消息 - 怎么防止消息丢失
2.1 生产者消息不丢失
kafka中消息发送+回调。
RocketMQ:消息发送+回调+事务。
RabbitMQ:消息发送+回调+手动事务(channel.txSelect()开启事务,channel.txCommit()提交事务,channel.txRollback()回滚事务)channel会阻塞,造成吞吐量下降。3.0升级为Publisher Confirm,整个处理流程通RocketMQ的事务消息。
2.2 MQ主从同步不丢失
RocketMQ:
普通集群:同步同步(MQ主表同步分表后分表返回确认消息,会丢消息),异步同步(主表获取到数据直接发返回确认消息,不会丢消息)。
Dledger集群-两阶段提交:先在候选节点中选出master,设置为uncommited,等多数slave节点同步到消息设置master状态为commited状态
RabbitMQ:
普通集群:消息分散存储,节点不会主动进行消息同步,会丢失消息。
镜像集群:镜像集群会在节点之间主动同步数据。
Kafka:
允许消息少量丢失,acks:0,1,all 同上面的同步同步,同步异步。
2.3 MQ消息存盘不丢失
RocketMQ:同步刷盘和异步刷盘(会丢失)。
RabbitMQ:将队列配置成持久化队列。3.x版本新增Quorum队列会采用raft协议进行消息同步。
2.4 MQ消费者消费消息不丢失
RocketMQ:使用默认的同步方式消费,不采用异步先返回offset方式消费。
RabbitMQ:autoCommit - 手动提交offset
Kafka:手动提交offset
如何保证消息消费的幂等性
就是防止消费者重复消费。所有MQ并没有提供主动解决幂等性的机制,需要由消费者自行控制。
RocketMQ:给每个消息分配了MessageId,作为消费者判断幂等性的依据。最好使用带有业务标识的id替换。
如何保证消息的顺序
全局有序和局部有序:MQ只需要保证局部有序(微信聊天),不需要保证全局有序(整个微信)。
生产者把一组有序的消息放在同一个队列中,而消费者一次消费整个队列中的消息。
RocketMQ中有完整设计,RabbitMQ和Kafka没有,需自己实现。
RabbitMQ:要保证目标exchange只对应一个队列,并且一个队列只对应一个消费者。
Kafka:生产者通过定制partition分配规则,将消息分配到同一个partition。Topic下只对应一个消费者。
如何保证消息的高效读写
Kafka和RocketMQ都是通过零拷贝实现。传统文件复制从(硬件-内核空间-用户空间-内核空间-硬件)需要四次拷贝。
Java对零拷贝进行了封装,mmap方式通过MappedByteBuffer对象进行操作,而transfer通过FileChannel进行操作。
mmap适合较小的文件,通常文件不超过1.5G~2G之间。Transfer没有文件大小限制。
RocketMQ:使用mmap方式对他的文件进行读写。commotLog,1G。
Kafka:他的index日志文件通过mmap方式读写,其他日志文件中,并没有使用零拷贝方式。使用transfile方式将硬盘数据加载到网卡。
如何使用MQ保证分布式事务的最终一致性。
分布式事务:业务相关的多个操作,保证他们同时成功或失败。
强一致性:任何时候多个操作都是对齐的。
最终一致性:多个操作最终结果时对齐的。
MQ中要保护事务的最终一致性,需要:
- 生产者要保证100%消息投递。 - 事务消息机制
- 消费者要保证幂等消费。 - 唯一id+业务自己实现
分布式MQ的三种语义:
at least once:消费者至少消费一次
at most once:生产者最多发送一次
exactly once:正确处理一次。Rocket并不能保证exactly once,商业版支持。kafka最新版提供了demo。RabbitMQ不支持。
如何设计一个MQ
- 实现单机的blockQueue队列数据结构。队列可伸缩扩展。
- 将单机队列扩展为分布式队列,将队列分布在不同的节点。就涉及到集群管理,kafka用zookeeper。
- 基于Topic定制消息路由选择策略。默认轮询发送到不同队列中,RocketMQ使用MessageSelector顺序发送至同一个队列。为保证消息消费偏移量(消费进度)则需要和消费者之间形成多对一的关系。一个队列由一个消费者消费可保证消息先进先出是有保障的(同机房同网络优先)。
- 消费消息时如果一个消费者对应多个队列,则并发多线程的获取消息,如果为保证顺序,则先把队列锁住依次消费。
- 消费者路由策略
- 实现高效的网络通信。 -Netty Http
- 规划日志文件,实现文件高效读写。 -零拷贝,顺序写。服务重启后快速还原现场。
- 定制高级功能。 死信队列,延迟队列,事务消息。