RabbitMQ消费端幂等性概念及解决方案

举报
JavaEdge 发表于 2021/06/04 00:40:32 2021/06/04
【摘要】 1 什么是幂等性 用户对于同一操作发起的一次请求或者多次请求的结果是一致的。 比如数据库的乐观锁,在执行更新操作前,先去数据库查询version,然后执行更新语句,以version作为条件,如果执行更新时有其他人先更新了这张表的数据,那么这个条件就不生效了,也就不会执行操作了,通过这种乐观锁的机制来保障幂等性. 2 Con幂等性 2.1 什么是Con幂等性 消...

本文已收录在Github关注我,紧跟本系列专栏文章,咱们下篇再续!

  • 🚀 魔都架构师 | 全网30W技术追随者
  • 🔧 大厂分布式系统/数据中台实战专家
  • 🏆 主导交易系统百万级流量调优 & 车联网平台架构
  • 🧠 AIGC应用开发先行者 | 区块链落地实践者
  • 🌍 以技术驱动创新,我们的征途是改变世界!
  • 👉 实战干货:编程严选网

1 幂等性问题由来

1.1 消费成功,但未通知MQ消费成功

虽有确保消息成功消费的ACK机制,但因网络或服务问题,Consumer可能无法成功调用ack来通知broker消息已被成功消费。此时,broker认为我们未消费成功,又再次推送消息,导致重复消费。

因此,现实需考虑消息幂等问题,尤其涉及敏感操作如消费微信支付通知。

1.2 vx多次投递消息给Producer

微信可能多次向Producer发消息,这也可能导致消息幂等问题。

2 啥是幂等性?

用户对同一操作发起的一次请求或多次请求的结果一致。

如数据库乐观锁,执行更新操作前:

  • 先去数据库查询version
  • 再执行更新语句
  • 以version作条件,若执行更新时有其他人先更新该表的数据,那这条件就不生效,也就不会执行操作

通过乐观锁保障幂等性。

3 Con幂等性

3.1 定义

消费端实现幂等性,即消息永远不会消费多次,即使收到重复消息。

业务高峰期最易产生重复消费问题:当Con消费完消息后给Pro返回ack时,由于网络中断,导致Pro未收到确认信息,该消息就会被重新发送并被Con消费,但实际上该Consumer已成功消费,导致重复消费。

3.2 幂等性方案

3.2.1 唯一ID+指纹码

生成全局唯一messageld。利用DB主键去重:

SELECT COUNT(1) FROM T_ORDER 
  WHERE ID = 唯一ID
  AND IS_CONSUM = 指纹码

唯一ID:业务表的主键

指纹码:为区别每次正常操作的码,每次操作时生成指纹码。可用:

  • 时间戳+业务编号
  • 或标志位
优势

实现简单。

弊端

高并发下有数据库写入的性能瓶颈。

解决方案

根据ID进行分库分表算法路由。

小结

先根据消息生成一个全局唯一ID,再加个指纹码。指纹码不一定是系统生成,而是一些外部规则或内部业务规则去拼接,就是为保障这次操作的绝对唯一性。

ID + 指纹码拼接好的值作为数据库主键,即可去重。消费消息前,先去数据库查询这条消息的指纹码标识:

  • 不存在,就执行insert
  • 存在,代表已被消费,就不需要管了

3.2.2 利用Redis原子性

需考虑是否落库:

  • 落,数据库和缓存咋做到原子性

  • 不落,都存储到缓存,咋设置定时同步策略

这里只提Redis原子性去解决MQ幂等性重复消费问题。

MQ幂等性问题根本在于Pro未正常接收ACK,可能网络抖动、网络中断。

实现

Con消费开始时,将ID放入Redis BitMap。Pro每次生产数据时,从BitMap对应位置若不能取出ID,则生产消息发送,否则不进行消息发送。

Q:万一Con、Pro的Redis命令执行失败咋办,虽出现重复消费 && 出现Redis非正常执行命令可能性极低,可万一?

A:可在Redis命令执行失败时,将消息落库,每日用定时器,处理这种极特殊消息。

3.2.3 使用分布式锁

3.2.4 设置数据库唯一索引

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。