消息丢失,消息重复消费,消息顺序消费等问题是我们使用 MQ 时不得不考虑的一个问题,下面我结合实际的业务来和你分享一下解决方案。
比如我们使用 Kakfa 时,以下场景都会发生消息丢失:
- producer -> broker (生产者生产消息)
- broker -> broker (集群环境,broker 同步给其他 broker)
- broker -> consumer (消费者消费消息)
解决方案也很简单,设置 acks(消息确认机制) retries(重试机制) factor(设置 partition 数量)…
一般来说,最常见的消息丢失场景就是: consumer 消费消息。
要保证 consumer 消费消息时不丢失消息,必须使用 手动提交 ack
我们业务是这样实现的:
要解决消息重复消费,也就是要实现 幂等(幂等就是:多次请求,但结果保持不变,举一个例子你就明白了: 在 http 中,你发送同一个 get 请求,无论发送多少次,返回结果都是一样的
)
回到我们的业务场景上,我以处理订单消息为例:
- 幂等Key 由我们的 订单Id + 订单状态组成(一笔订单的状态只会处理一次)
- 在处理之前,我们首先会去 Redis 查询是否存在这个 Key 如果存在,说明我们已经处理过了,直接丢掉; 如果不存在,说明没处理过,继续往下处理;
- 最终的逻辑是:将处理过的数据存到 DB上,再把 幂等Key 存到 Redis 上
显然一般场景下 Redis 是无法保证幂等的
所以 Redis只是一个 前置处理,最终的幂等性依赖 DB 的 唯一Key(订单Id+订单状态)
总的来说就是:通过 Redis 做 前置处理,DB 唯一索引做 最终保证实现 幂等性
消息的顺序性很好理解,还是以订单处理为例
订单的状态有:支付、确认收货、完成等等,而订单下还有计费、退款的消息报
理论上来说:支付的消息肯定要比退款的消息先到。
但是程序处理的过程就不一定了,所以我们处理消息顺序消费的流程如下:
- 宽表:创建一张宽表,唯一索引是 订单Id,将订单的 每个状态拆分为一个列,当消息来了,只更新对应的字段就好,消息只会存在短暂的状态不一致问题,但是最终状态是一致的
- 消息补偿机制
- 把相同的 userID/orderId 发送到相同的 partition(因为一个 consumer 消费一个 partition)
Original: https://www.cnblogs.com/Fzeng/p/16102422.html
Author: 小冯同学c
Title: 实际业务处理 Kafka 消息丢失、重复消费和顺序消费的问题
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/592981/
转载文章受原作者版权保护。转载请注明原作者出处!