(2)数据一致性问题
如果mq的消费者业务处理异常的话,就会出现数据一致性问题 。
比如:一个完整的业务流程是,下单成功之后,送100个积分 。下单写库了,但是消息消费者在送积分的时候失败了,就会造成数据不一致的情况,即该业务流程的部分数据写库了,另外一部分没有写库 。
如果下单和送积分在同一个事务中,要么同时成功,要么同时失败,是不会出现数据一致性问题的 。
但由于跨系统调用,为了性能考虑,一般不会使用强一致性的方案,而改成达成最终一致性即可 。
(3)消息丢失问题:
哪些场景会出现消息丢失问题呢?
消息生产者发生消息时,由于网络原因,发生到mq失败了 。
mq服务器持久化时,磁盘出现异常
kafka和rocketmq的offset被回调时,略过了很多消息 。
消息消费者刚读取消息,已经ack确认了,但业务还没处理完,服务就被重启了 。
导致消息丢失问题的原因挺多的,生产者、mq服务器、消费者 都有可能产生问题,我在这里就不一一列举了 。最终的结果会导致消费者无法正确的处理消息,而导致数据不一致的情况 。
(4)消息顺序问题
有些业务数据是有状态的,比如订单有:下单、支付、完成、退货等状态,如果订单数据作为消息体,就会涉及顺序问题了 。如果消费者收到同一个订单的两条消息,第一条消息的状态是下单,第二条消息的状态是支付,这是没问题的 。但如果第一条消息的状态是支付,第二条消息的状态是下单就会有问题了,没有下单就先支付了?
消息顺序问题是一个非常棘手的问题,比如:
kafka同一个partition中能保证顺序,但是不同的partition无法保证顺序 。
rabbitmq的同一个queue能够保证顺序,但是如果多个消费者同一个queue也会有顺序问题 。
如果消费者使用多线程消费消息,也无法保证顺序 。
如果消费消息时同一个订单的多条消息中,中间的一条消息出现异常情况,顺序将会被打乱 。
还有如果生产者发送到mq中的路由规则,跟消费者不一样,也无法保证顺序 。
(5)消息堆积问题
如果消息消费者读取消息的速度,能够跟上消息生产者的节奏,那么整套mq机制就能发挥最大作用 。但是很多时候,由于某些批处理,或者其他原因,导致消息消费的速度小于生产的速度 。这样会直接导致消息堆积问题,从而影响业务功能 。
这里以下单开通会员为例,如果消息出现堆积,会导致用户下单之后,很久之后才能变成会员,这种情况肯定会引起大量用户投诉 。
(6)系统复杂度提升
这里说的系统复杂度和系统耦合性是不一样的,比如以前只有:系统A、系统B和系统C 这三个系统,现在引入mq之后,你除了需要关注前面三个系统之外,还需要关注mq服务,需要关注的点越多,系统的复杂度越高 。
mq的机制需要:生产者、mq服务器、消费者 。
有一定的学习成本,需要额外部署mq服务器,而且有些mq比如:rocketmq,功能非常强大,用法有点复杂,如果使用不好,会出现很多问题 。有些问题,不像接口调用那么容易排查,从而导致系统的复杂度提升了 。
如何解决?
1,重复消费问题的解决:
不管是由于生产者产生的重复消息,还是由于消费者导致的重复消息,我们都可以在消费者中这个问题 。
这就要求消费者在做业务处理时,要做幂等设计;
在这里我推荐增加一张消费消息表,来解决mq的这类问题 。消费消息表中,使用messageId做唯一索引,在处理业务逻辑之前,先根据messageId查询一下该消息有没有处理过,如果已经处理过了则直接返回成功,如果没有处理过,则继续做业务处理 。
2,数据一致性的解决:
数据一致性分为:
强一致性
弱一致性
最终一致性
而mq为了性能考虑使用的是最终一致性,那么必定会出现数据不一致的问题 。这类问题大概率是因为消费者读取消息后,业务逻辑处理失败导致的,这时候可以增加重试机制 。
重试分为:同步重试 和 异步重试 。
有些消息量比较小的业务场景,可以采用同步重试,在消费消息时如果处理失败,立刻重试3-5次,如何还是失败,则写入到记录表中 。但如果消息量比较大,则不建议使用这种方式,因为如果出现网络异常,可能会导致大量的消息不断重试,影响消息读取速度,造成消息堆积 。
而消息量比较大的业务场景,建议采用异步重试,在消费者处理失败之后,立刻写入重试表,有个job专门定时重试 。
秒懂生活扩展阅读
- 许多|坏消息!中国有2个地方正在慢慢“下沉”,以后会永久消失?
- 微信消息提示音可以关吗怎么关
- 微信消息过多被限制接收怎么办
- 支付宝收到的消息要在哪里看
- 什么叫导语
- 河内|好消息!关乎中国和越南!|中国自驾地理
- 微信群主怎么撤回别人的消息
- 苹果手机怎么设置qq新消息通知
- qq上屏蔽此人消息对方知道吗
- 最新版微信可以撤回多久的消息