-
为什么要选择使用MQ?
通过MQ可将系统解耦,实现不同的系统之间通信;
异步处理;
流量削峰。解耦:
场景:系统A生产完数据后需要调用系统B,系统C以及系统E的接口。当新增一个系统D时,需要在系统A中新增调用代码,系统E去除时,也要在系统A中删除调用接口代码。系统严重耦合。
系统A还需要考虑其他系统是否挂掉,重发消息等问题。
使用MQ的场景如下图:
系统A不需要考虑谁需要这条消息,系统解耦。异步处理:
场景: 当用户注册成功后,邮箱、手机等需要收到注册成功的消息。可能短信调用接口需要200ms,邮箱接口需要200ms,其他系统接口需要500ms,总时间累加后,系统变慢,用户体验较差。
使用MQ:通过MQ异步发送短信邮件。系统响应速度变快。
流量削峰
场景:秒杀系统,并发请求量过大,假设每秒5000个请求,系统可能问题不大,mysql却抗不住,可能直接导致mysql死机,系统崩溃。
加入MQ后,系统将用户请求进入MQ,然后每秒取出2000个,系统不会崩溃。不过可能会导致消息积压。
-
使用MQ会出现的问题。
1). 可能会出现数据丢失。
生产者丢失数据,通过MQ提供的事务,或者在生产者开启confirm 模式,每次推送数据时,MQ会回传ack消息,则数据推送成功。
MQ宕机发生数据丢失,开启数据持久化来解决,有可能数据还未持久化,MQ宕掉后,则会发生这一小部分数据丢失。
消费端丢失数据,消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,使用ack机制解决。2). 可能会出现重复消费。
重复消费有不同的层次,当update/delete/select 操作,应该都是幂等操作,可以允许重复消费。
但是insert不是幂等操作,重复消费则会insert多次数据,导致数据重复。
但也必须要分场景,例如 转账的场景中,update不是幂等的操作。重复消费场景:
系统A -> MQ -> 系统B
加入提交数据至MQ没有异常,系统B能够拉取到数据,当系统B拉取消息成功后,并且将数据落地成功,消费成功,此时的系统B刚好down掉,则没有返回ack给MQ,MQ不知道该消息被正确的消费了。系统B恢复正常后,重新拉取数据,则发生重复消费。
3). 如何避免重复消费 实现exactly once 需要根据业务来决定。
方案一:
Kafka中,每个partition里每个group都维护了一个offset 将 group信息 和 offset 信息 与数据同时落地到数据库当中,
当consumer down掉后,不从Kafka中获取offset,而是从数据库当中获取最后一条offset+1进行消费。
也就是将offset从Kafka维护变成了本地维护,实现exactly once。
方案二:
MQ中存储全局唯一ID,生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。根据业务场景分析,如果重复消费是幂等的,则可以恰好不解决。
MQ常见问题
最新推荐文章于 2024-05-07 16:44:54 发布