rocketmq怎么保证数据不会重复_聊一聊如何保证RocketMQ使用中如何保证消费幂等性...

之所以想聊一聊这个话题,是因为在刚开始使用rocketmq时,Consumer服务写的有问题的情况下,消息队列会重发,这是因为消费失败会导致消息被放入RETRY重试队列,根据用户配置的重试次数(默认16次)进行重试,这部分我们已经在之前的 RocketMQ存储机制与确认重传机制一文中讨论过,这个情况引起了我探究“什么情况下消息队里会进行重试,会不会导致重复消费?”这一问题的好奇心。

为什么会出现消息重复的问题?

对于 Producer

我们知道,RocketMQ提供了三种发送消息模式:

1、同步发送

Producer 向 broker 发送消息,阻塞当前线程等待 broker 响应 发送结果。

DefaultMQProducerImpl中设置如果超时没有响应或者发送失败,会重发。

2、异步发送

Producer 首先构建一个向 broker 发送消息的任务,把该任务提交给线程池,等执行完该任务时,回调用户自定义的回调函数,执行处理结果。

3、Oneway 发送

Oneway 方式只负责发送请求,不等待应答,Producer 只负责把请求发出去,而不处理响应结果。

上述前两种发送方式,如果成功发送到消息队列,但消息队列返回结果时出现网络问题,则会导致消息已经发送成功而生产者认为发送失败,重新发送,导致出现多条重复消息。

对于 Consumer

1、可能因为 Broker 的消息进度丢失,导致消息重复投递给 Consumer 。

2、Consumer 消费成功,但是因为网络问题/ JVM 异常崩溃,导致消息消息队列没能收到消费成功确认,以为消费失败,导致重复推送 。

注:对于大多数消息队列,考虑到性能,消费进度是异步定时同步给 Broker 。

如何解决

消费者实现幂等性,一般是在框架层统一封装或者业务层自己实现。

框架层统一封装

首先,需要有一个消息排重的唯一标识,该编号只能由 Producer 生成,例如说使用 uuid、或者其它唯一编号的算法 。

对于RocketMQ来说,Producer 在发送消息时,默认会生成消息编号( msgId ),可见org.apache.rocketmq.common.message.MessageClientExt 类。Broker 在存储消息时,会生成结合 offset 的消息编号( offsetMsgId ) 。Consumer 在消费消息失败后,将该消息发回 Broker 后,会产生新的 offsetMsgId 编号,但是 msgId 不变。

然后,就需要有一个排重的存储器,例如说:

使用关系数据库,增加一个排重表,使用消息编号作为唯一主键。

使用 KV 数据库,KEY 存储消息编号,VALUE 任一。此处,暂时不考虑 KV 数据库持久化的问题。

那么,我们要什么时候插入这条排重记录呢?

在消息消费执行业务逻辑之前,插入这条排重记录。但是,此时会有可能 JVM 异常崩溃。那么 JVM 重启后,这条消息就无法被消费了。因为,已经存在这条排重记录。

在消息消费执行业务逻辑之后,插入这条排重记录。

如果业务逻辑执行失败,显然,我们不能插入这条排重记录,因为我们后续要消费重试。

如果业务逻辑执行成功,此时,我们可以插入这条排重记录。但是,万一插入这条排重记录失败呢?那么,需要让插入记录和业务逻辑在同一个事务当中,此时,我们只能使用数据库。

业务层自己实现

方式很多,这个和 HTTP 请求实现幂等是一样的逻辑:

先查询数据库,判断数据是否已经被更新过。如果是,则直接返回消费完成,否则执行消费。

在并发量比较高的系统下,我们可以使用redis来进行幂等性判断。

正常情况下,出现重复消息的概率其实很小,如果由框架层统一封装来实现的话,肯定会对消息系统的吞吐量和高可用有影响,所以最好还是由业务层自己实现处理消息重复的问题。

我的做法

我的项目中主要是针对“任务”提交时进行幂等性判断,我的做法是在下派任务时把任务id放到redis中,然后再任务提交时从redis中删除,但如果消费事务执行失败,redis会重新把任务id添加回来作出补偿。从而完成幂等性判断。

原文:https://www.cnblogs.com/wunsiang/p/12765155.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值