什么是消息中间件?
MQ全称为Message Queue,消息队列是应用程序和应用程序之间的通信方法。
消息队列的应用场景
MQ的优势
服务解耦
使用MQ后,消息通过中间件转发,消费者从MQ中取消息,如果库存系统出现异常,等库存系统自我修复后再去MQ中取消息,不会影响其他系统。添加新系统也是去MQ中取,不用修改订单系统的代码。
异步处理
使用MQ,一个订单只需要25ms,提升用户体验和系统的吞吐量(QPS:单位时间内处理请求的数目)
流量削峰
- 消息被MQ保存起来了,然后系统就可以按照自己的消费能力来消费,比如每秒1000个数据,这样慢慢写入数据库,这样就不会卡死数据库了。
可以起到一个缓冲的作用,防止短时间内大量请求导致数据库宕机系统崩溃,将数据发先发送至消息队列压积,然后拉去一定数量的数据进行处理,防止请求峰值时期大量的请求直接发送到数据库导致系统崩溃。
MQ的劣势
- 系统可用性降低
系统引入的外部依赖越多,系统稳定性越差。一旦 MQ 宕机,就会对业务造成影响。如何保证MQ的高可用?
- 集群部署:通过将多个 RabbitMQ 节点组成一个集群,实现数据的自动复制和故障转移,从而提高可用性。
- 镜像队列:RabbitMQ 支持镜像队列(Mirrored Queue),可以将队列的消息复制到多个节点上,从而保证在某个节点宕机的情况下,仍然能够正常处理消息。
- 负载均衡:通过在 MQ 客户端和服务器之间引入负载均衡器,将请求分配到多个 MQ 节点上,从而提高系统的可用性和性能。
- 容灾备份:对于重要的 MQ 数据,可以进行容灾备份,将数据备份到多个地方,确保在某个地方发生灾难性事件的情况下,仍然能够快速地恢复数据。
- 系统复杂度提高
MQ 的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过 MQ 进行异步调用。如何保证消息没有被重复消费?怎么处理消息丢失情况?怎么保证消息传递的顺序性?
-
消息重复消费的问题:可以通过以下两种方式来避免消息重复消费:
- 消息幂等性(幂等性:无论你重复请求多少次,得到的结果都是一样的):在消费者端,对于相同的消息,无论消费多少次都只会产生一次业务效果,即不会引起重复处理的问题。可以通过在消息体中添加唯一的消息 ID 或者在业务逻辑中进行幂等性处理等方式来实现。
- 消费者端去重:可以根据消息 ID 进行去重,消费者端可以通过维护一个已经处理过的消息列表来避免重复消费。当消费者接收到消息后,首先检查该消息是否已经在列表中出现过,如果是,则直接忽略该消息。
-
消息丢失的问题:消息丢失的主要原因是消息在传递过程中出现了错误,例如网络故障、节点宕机等。为了避免消息丢失,可以采用以下两种方式:
- 消息持久化:在 RabbitMQ 中,可以将消息设置为持久化,确保即使 MQ 宕机,消息也不会丢失。同时,在消费端,需要使用 ACK 机制,确保消息已经被正确消费,避免消息丢失。
-
消息传递顺序的问题:由于 RabbitMQ 是异步处理消息的,因此无法保证消息的传递顺序。如果需要保证消息的顺序性,可以采用以下两种方式:
- 单一队列:将所有需要按顺序处理的消息都发送到同一个队列中,由同一个消费者消费,可以通过设置队列的消费者数为 1,可以确保消息按照生产者的顺序被处理。
- 有序队列:有序队列是 RabbitMQ 的一个插件,可以确保按照特定的顺序处理消息。在使用有序队列时,需要为每个队列分配一个序号,消息按照序号依次处理。
- 一致性问题
A 系统处理完业务,通过 MQ 给B、C、D三个系统发消息数据,如果 B 系统、C 系统处理成功,D 系统处理
失败。如何保证消息数据处理的一致性。
使用mq中只能保证最终一致性。
最终一致性是指在一定时间内,系统最终会达到一致的状态,但在此期间可能存在一段时间的不一致。 消息队列(MQ)本身并不能保证数据一致性,因为它们是异步传递消息的。异步传递意味着发送方将消息发送到队列中,而接收方将在稍后的时间点收到并处理该消息。在这个过程中,发送方和接收方之间的数据可能会发生不一致的情况,例如发送方在消息发送之后立即崩溃,而接收方还没有来得及处理该消息。