1.为什么要用消息队列
解耦、异步、削峰
- A系统调用B系统、C系统,传统的调用是直接调用,但是当B系统说我不需要你提供数据了,这时候A需要改代码,C系统说我不需要某个字段了,这时候A也要改代码,如果又多了一个D系统,A又要写代码。为了实现解耦,引入消息队列,A将产生的数据丢到消息队列中,哪个系统需要 哪个系统就去取;
- A系统调用B系统,B系统由于某个需要调用第三方接口超时,导致A系统响应速度慢,而B系统的好坏又不会影响业务逻辑,所以可以改为A异步调用B,A将消息丢到消息队列中,B系统订阅消息,实现A的快速响应;
- 当大量流量请求到系统A时,由于数据库的处理能力有限,造成数据库连接异常。使用消息队列,大量请求先丢到消息队列中,系统A使用按批拉数据的方式,批量处理数据,生产中,高峰期短暂的消息积压是允许的。
2.使用消息队列有什么缺点
- 系统复杂性增加:加了消息队列,需要保证消息不会重复消费,需要保证消息的可靠性,需要保证消息队列的高可用
- 系统的可用性降低:如果消息队列挂了,那么系统也会受到影响
3.为什么选用RocketMQ;RocketMQ和ActiveMQ的区别
RocketMQ模型简单、接口易用,在阿里大规模使用,社区活跃,单机吞吐量10万级,可用性非常高,消息理论上不会丢失;
- ActiveMQ严格遵循JMS规范,可持久化到内存、文件、数据库,可用性高主要是主从,多语言支持,消失丢失率低;
- RocketMQ持久化到磁盘文件,可用性非常高,支持分布式,只支持Java,消息理论上不会丢失;
4.RocketMQ是怎么保证系统高可用的?
- 多Master部署,防止单点故障;
- 主从结构,消息冗余,防止消息丢失;
5.MQ能否保证消息必达,即消息的可靠性?
为了降低消息丢失的概率,MQ需要进行超时和重传
(1) MQ-client-sender 发送消息给MQ-server
(2) MQ-server接收到消息后,发送 ACK消息给发送方
(3) MQ-client-sender 接收到 ACK消息后,则 消息已经投递成功
如果上述 2 消息丢失或者超时,MQ-client-sender 内的 timer 会重发消息,直到收到 ACK消息,如果重试N次后还未收到,则回调发送失败。需要注意的是,这个过程中 MQ-server 可能会收到同一条消息的多次重发。
对每条消息,MQ系统内部必须生成一个inner-msg-id,作为去重和幂等的依据,这个内部消息ID的特性是:
- 全局唯一
- MQ生成,具备业务无关性,对消息发送方和消息接收方屏蔽
(4) MQ-server 将消息发送给 MQ-client-receiver
(5) MQ-client-receiver 得到消息处理业务逻辑
(6) MQ-client-receiver 回复 ACK消息给 MQ-server
(7) MQ-server收到 ACK消息,将已消费的消息删除
如果上述 6 消息丢失或者超时,MQ-server 内的 timer 会重发消息,直到 MQ-server 收到ACK消息 并且 将已消费的消息删除,这个过程也可能会重发多次,MQ-client-receiver 也可能会收到同一条消息的多次重发。
需要强调的是,MQ-client-receiver 回ACK给 MQ-server,是消息消费业务方的主动调用行为,不能由 MQ-client-sender 自动发起,因为MQ系统不知道消费方什么时候真正消费成功。
为了保证业务幂等性,业务消息体中,必须有一个biz-id,作为去重和幂等的依据,这个业务ID的特性是:
- 对于同一个业务场景,全局唯一
- 由业务消息发送方生成,业务相关,对MQ透明
- 由业务消息消费方负责判重,以保证幂等
最常见的业务ID有:支付ID,订单ID,帖子ID等。
欢迎关注我的公众号~ 搜索公众号: 码咖 或者 扫描下方二维码: