消息丢失,消息重复消费,消息顺序消费等问题是我们使用 MQ 时不得不考虑的一个问题,下面我结合实际的业务来和你分享一下解决方案。
比如我们使用 Kakfa 时,以下场景都会发生消息丢失:
解决方案也很简单,设置acks(消息确认机制)retries(重试机制)factor(设置 partition 数量)...
一般来说,最常见的消息丢失场景就是:consumer 消费消息。
要保证consumer 消费消息时不丢失消息,必须使用手动提交 ack
我们业务是这样实现的:
要解决消息重复消费,也就是要实现幂等(幂等就是:多次请求,但结果保持不变,举一个例子你就明白了:在 http 中,你发送同一个 get 请求,无论发送多少次,返回结果都是一样的
)
回到我们的业务场景上,我以处理订单消息为例:
幂等Key 由我们的订单Id +订单状态组成(一笔订单的状态只会处理一次)
在处理之前,我们首先会去Redis 查询是否存在这个Key
如果存在,说明我们已经处理过了,直接丢掉;
如果不存在,说明没处理过,继续往下处理;
最终的逻辑是:将处理过的数据存到DB上,再把幂等Key 存到Redis 上
显然一般场景下 Redis 是无法保证幂等的
所以Redis只是一个前置处理,最终的幂等性依赖DB 的唯一Key(订单Id+订单状态)
总的来说就是:通过 Redis 做前置处理,DB 唯一索引做最终保证实现幂等性
消息的顺序性很好理解,还是以订单处理为例
订单的状态有:支付、确认收货、完成等等,而订单下还有计费、退款的消息报
理论上来说:支付的消息肯定要比退款的消息先到。
但是程序处理的过程就不一定了,所以我们处理消息顺序消费的流程如下: