1. 为什么使用MQ?

1.1 同步调用

一次用户请求可能会按顺序同步调用多个系统接口,必须所有接口都返回了,才能得到真正执行结果。 总耗时长,在网络环境差的情况下,可能出现接口超时问题

1.2 耦合性高

直接调用一个系统的业务可能涉及间接调用多个子系统的业务。 如果请求时任何一个子系统出现异常,整个请求都会异常,系统不稳定

1.3 请求在某个时刻骤增

在秒杀、双十一等特殊期间用户突增,同一时刻大量请求涌向服务器,可能导致服务器响应变慢或者直接宕机。

2. MQ是如何解决传统开发中的问题的?

2.1 异步调用

为避免响应时间过长,不一定非要等到所有接口都返回之后再返回请求结果。 在调用部分接口之后,已经得到可以响应给用户的结果,这时可以向MQ中生产消息并直接返回结果,其他还未调用的接口会监听并消费MQ中的消息,独立完成剩下的业务。

2.2 解耦

直接调用的系统作为生产者,处理好自己的业务逻辑并向MQ中生产消息之后即可返回结果,其他间接涉及的子系统会监听并消费MQ中的消息,独立完成业务。这样各系统都只依赖于MQ而不会彼此产生依赖。

2.3 削峰

以秒杀场景为例:订单系统自己也可以分为生产者(新增订单)和消费者(订单入库),当生产者收到请求之后直接将其发送到MQ中,消费者会根据自己的速度处理请求,多余的请求会暂时放到MQ中之后处理。

3. MQ会带来哪些新的问题? 如何解决?

3.1 重复消费问题

为什么会出现重复消费?

生产者生产了重复消息消费者确认失败或超时业务系统主动发起重试

如何解决? 不论是生产者还是消费者导致的重复消息,都可以在消费者处进行解决。 要求消费者在处理业务时,做幂等设计。高并发下保证接口的幂等性 推荐做法:增加一张消息表message,主键是消息的id。在消费者处理业务之前先根据每个消息的id查询该消息是否处理过,如果已经处理过则直接返回,否则继续处理。

3.2 数据一致性

如果生产消息成功而消费消息失败时,可能出现数据库中数据不一致的情况 如何解决? 增加重试机制

同步重试:如果消费消息失败,立刻重试3-5次,如果还是失败则写到重试表中。异步重试:如果消费消息失败,立刻写到重试表中,有个定时任务会专门定时重试。重发消息:如果消费消息失败,由该消费者给同一个topic发一条消息,之后又会消费到那条消息实现重试。

3.3 消息丢失

为什么会出现消息丢失?

生产者发送消息时由于网络问题导致发送到MQ失败MQ服务器持久化时,磁盘出现异常消费者刚读取消息并确认,但还未处理完业务时,服务被重启

生产者、MQ、消费者都可能导致消息丢失问题

如何解决? 增加一张消息表message,生产者发完消息之后该表中会增加一条记录,字段status为待确认。消费者读取消息之后该表中更新这条记录,字段status为已确认。有个任务会周期性检查message表,如果还有状态是待确认的记录,则认为该消息已丢失,重发消息。

3.4 消息顺序

有些业务流程需要按顺序完成,比如下单 → 支付 → 确认收货。如果消费消息乱序,将会导致系统错误

在kafka中,同一个partition可以保证顺序,但是不同partition不能保证顺序。消费者是多线程消费时,不能保证顺序如果中间某条消息出现异常,不能保证最终顺序

如何解决? 生产者可以根据某个编号将消息路由到对应的partition 例如:订单业务中,生产者可以根据订单id将消息发送到不同的partition中,同一订单id的消息会发送到同一个partition中

3.5 消息堆积

如果消费者消费速度长期小于生产者速度,会导致消息堆积,某个业务较长时间之后才能真正完成,影响部分用户的体验 如何解决?

如果消息不需要保证顺序,可以读取消息之后利用多线程处理业务。如果消息需要保证顺序,可以读取消息之后,将消息按照顺序分发到多个队列中,每个队列用单线程处理

3.6 系统复杂度提升

虽然MQ可以降低系统之间的耦合性,但同时需要额外关注MQ服务。(学习MQ机制,部署MQ服务器)

参考链接

推荐链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: