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服务器)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/75094.html