MQ入门基础知识
1. 什么是MQ
MQ全称为Message Queue,即消息队列。
从字面上理解是存储消息的容器,向容器中存消息的称为生产者,从容器中取消息的称为消费者。
从深层次理解是跨进程、异步的通信机制、用于上下游传递消息的。
2. MQ的使用场景
2.1 削锋
在秒杀活动中,活动开始的一瞬间会有大量的用户请求到达服务器,若不做处理,服务器会被瞬间击垮,此时可以使用MQ进行削锋处理,流程如下图:
(1). 设置MQ队列的长度,将用户请求放入MQ中,当队列已满时,则直接抛弃用户请求或跳转到错误页面。
(2). 秒杀业务处理系统从MQ中获取用户请求进行处理。
2.2 异步
在电商系统中,用户下单后首先会在订单系统中新增一条订单记录,在库存系统中锁定库存,最后在支付系统中完成支付。若三个操作是同步的,那么整个电商系统的吞吐量会很低,如下图所示:
订单系统、库存系统、支付系统各消耗100ms,整个用户下单会消耗300ms。
若使用MQ将库存系统的锁定库存和支付系统的支付进行异步处理,将会大大减少用户下单的耗时,如下图所示:
定单系统消耗100ms,将订单信息放入MQ中消耗10ms,整个用户下单消耗110ms,相比于同步的300ms,大大降低了下单耗时。但是需要考虑数据一致性问题。
2.3 解耦
假设电商系统由5个子系统组成,分别为订单系统、库存系统、支付系统、积分系统、优惠卷系统,若想要实现随意的新增或删除子系统,那么子系统之间必须要解耦。此时可以使用MQ进行系统之间的异步解耦。如下图所示:
(1). 用户下单,在订单系统中新增订单记录。
(2). 将订单信消息发布到MQ中。
(3). 库存系统、支付系统、积分系统、优惠卷系统订阅MQ的订单消息。
(4). 用户下单结束。
此时接到需求变更,电商系统中废弃优惠卷系统,只需要优惠卷系统取消订阅订单消息的就可以实现。
3. 系统引入MQ需要考虑的问题
3.1 数据一致性
在电商系统中,引入了MQ做系统间的异步解耦,但是需要考虑库存系统锁定库存失败之后的数据一致性问题,一般使用分布式事务来保证数据的最终一致性。
3.3 消息的丢失(消息的可靠性传输)
系统引入了MQ之后,必须要考虑消息的可靠性传输问题,也就是消息的丢失,一般消息的丢失会发生在三个阶段,生产者发布消息时、消息存储在MQ中,消费者消费消息时。下面分别说一下在这三个阶段中怎么保证消息不丢失。
3.3.1 生产者丢失消息
(1). 出现的原因
生产者投递消息到MQ中时,由于网络原因导致投递失败,此时若没有处理,就会造成消息丢失。
(2). 解决办法
(a). 事务
MQ的生产者在投递消息时,开启事务(channel.txSelect),若投递失败,生产者会收到异常信息,此时可以回滚事务(channel.txRollback),然后重新投递消息,若投递成功,就提交事务(channel.txCommit),但是事务一旦加上,就会大大的降低MQ的吞吐量。
(b). confirm机制
MQ的生产者在投递消息时,开启confirm机制,消息投递成功或失败都会通知生产者,当投递失败时,重新投递。
3.3.2 MQ丢失消息
(1). 出现的原因
消息投递到MQ,若发生MQ服务器断电重启,此时会造成MQ中消息全部丢失。
(2). 解决办法
开启MQ持久化功能,RabbitMq必须同时开启queue、交换机、消息的持久化才能真正做到消息不丢失。
3.3.3 消费者丢失消息
(1). 出现的原因
消费者从MQ中拿到消息,在消费消息的过程中,失败了,此时会造成消息的丢失。
(2). 解决办法
RabbitMQ有俩种应答模式,自动应答(消费者拿到消息后,自动应答MQ,删除消息)和手动应答(消费者拿到后,处理完,手动应答MQ,删除消息),若想要避免消费者丢失消息,消费者可以开启手动应答模式,消费者消费消息成功后,手动的应答MQ,让MQ删除已消费的消息。
3.2 消息的重复消费
(1). 出现的原因
消费者从MQ中获取消息,消费成功之后,手动应答MQ时,由于网络的原因失败了,导致MQ中已消费的消息未删除,由此会出现消息的重复消费问题。
(2). 解决办法
消费者实现幂等性(多次消费同一个消息,结果不变),常用的方法是在生产者发布消息时,为每一个消息生成唯一ID,消费者在消费完消息之后,保存消息的ID,每次消费消息时,判断该消息是否已被消费,若消费了,就直接抛弃该消息。
3.4 消费者顺序消费消息
(1). 出现的原因
首先说一下,MQ是一种异步通信的机制,说到异步,那么顺序消费就有问题,MQ在设计之初,就没有考虑过顺序消费的问题。只是我们在使用MQ时,会出现这样需求。
(1). 解决办法
一个生产者将消息按顺序投递到一个队列中,一个消费者按顺序从该队列中取出消息消费。生产者、队列、消费者三者一对一就可以实现按顺序消费消息。