经典面试题 | 消息被重复消费,怎么避免?有什么好的解决方案?
IT牧场
共 8304字,需浏览 17分钟
· 2021-09-21
点击下方“IT牧场”,选择“设为星标”
消息中间件是分布式系统常用的组件,无论是异步化、解耦、削峰等都有广泛的应用价值。
# 简单的消息去重解决方案
insert into t_order values .....
update t_inv set count = count-1 where good_id = 'good123';
select * from t_order where order_no = 'order123'
if(order != null) {
return ;//消息重复,直接返回
}
# 并发重复消息
select * from t_order where order_no = 'order123'
if(order != null) {
return ;//消息重复,直接返回
}
select * from t_order where order_no = 'THIS_ORDER_NO' for update //开启事务
if(order.status != null) {
return ;//消息重复,直接返回
}
# Exactly Once
Exactly-Once 是指发送到消息系统的消息只能被消费端处理且仅处理一次,即使生产端重试消息发送导致某消息重复投递,该消息在消费端也只被消费一次。
# 基于关系数据库事务插入消息表
update t_order
set status =
'SUCCESS' where order_no=
'order123';
1.开启事务
2.插入消息表(处理好主键冲突的问题)
3.更新订单表(原消费逻辑)
4.提交事务
https://help.aliyun.com/document_detail/102777.html
# 更复杂的业务场景
检查库存(RPC) 锁库存(RPC) 开启事务,插入订单表(MySQL) 调用某些其他下游服务(RPC) 更新订单状态 commit 事务(MySQL)
库存系统消费A:检查库存并做锁库存,发送消息B给订单服务 订单系统消费消息B:插入订单表(MySQL),发送消息C给自己(下游系统)消费 下游系统消费消息C:处理部分逻辑,发送消息D给订单系统 订单系统消费消息D:更新订单状态
# 更通用的解决方案
问题一:消息已经消费成功了,第二条消息将被直接幂等处理掉(消费成功)。 问题二:并发场景下的消息,依旧能满足不会出现消息重复,即穿透幂等挡板的问题。 问题三:支持上游业务生产者重发的业务重复的消息幂等问题。
在并发场景下我们依赖于消息状态是做并发控制使得第 2 条消息重复的消息会不断延迟消费,即重试。
1.性能上损耗更低 2.上面我们讲到的超时时间可以直接利用Redis本身的ttl实现
# show me code
https://github.com/Jaskey/RocketMQDedupListener ,
//利用Redis做幂等表
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("TEST-APP1");
consumer.subscribe("TEST-TOPIC", "*");
String appName = consumer.getConsumerGroup();// 大部分情况下可直接使用consumer group名
StringRedisTemplate stringRedisTemplate = null;// 这里省略获取StringRedisTemplate的过程
DedupConfig dedupConfig = DedupConfig.enableDedupConsumeConfig(appName, stringRedisTemplate);
DedupConcurrentListener messageListener = new SampleListener(dedupConfig);
consumer.registerMessageListener(messageListener);
consumer.start();
# 这种实现是否一劳永逸?
步骤1:检查库存(RPC) 步骤2:锁库存(RPC) 步骤3:开启事务,插入订单表(MySQL) 步骤4:调用某些其他下游服务(RPC) 步骤5:更新订单状态 步骤6:commit 事务(MySQL)
# 本实现方式的价值?
1.各种由于Broker、负载均衡等原因导致的消息重投递的重复问题 2.各种上游生产者导致的业务级别消息重复问题 3.重复消息并发消费的控制窗口问题,就算重复,重复也不可能同一时间进入消费逻辑
# 一些其他的消息去重的建议
#1.消息消费失败做好回滚处理。如果消息消费失败本身是带回滚机制的,那么消息重试自然就没有副作用了。 #2.消费者做好优雅退出处理。这是为了尽可能避免消息消费到一半程序退出导致的消息重试。 #3.一些无法做到幂等的操作,至少要做到终止消费并告警。例如锁库存的操作,如果统一的业务流水锁成功了一次库存,再触发锁库存,如果做不到幂等的处理,至少要做到消息消费触发异常(例如主键冲突导致消费异常等)
干货分享
最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!
•001:《Java并发与高并发解决方案》学习笔记;•002:《深入JVM内核——原理、诊断与优化》学习笔记;•003:《Java面试宝典》•004:《Docker开源书》•005:《Kubernetes开源书》•006:《DDD速成(领域驱动设计速成)》•007:全部•008:加技术群讨论
加个关注不迷路
喜欢就点个"在看"呗^_^
评论
了解加密货币到加密货币的互换
1、什么是加密货币互换?加密货币到加密货币的互换是指以现行市场汇率将一种加密货币直接兑换为另一种加密货币。与需要法定货币存款和较长流程的传统交易所不同,加密货币到加密货币的互换可以无缝地促进交换。掉期在提高加密货币的流动性和效率方面发挥着重要作用。该功能使用户能够将他们的加密货币与钱包中的其他代币进
区块链头条
0
李彦宏:开源大模型不如闭源,后者会持续领先;周鸿祎:“开源不如闭源” 的言论是胡说八道
架构师大咖
架构师大咖,打造有价值的架构师交流平台。分享架构师干货、教程、课程、资讯。架构师大咖,每日推送。
公众号该公众号已被封禁0、李彦宏:开源大模型不如闭源,后者会持续领先当今
源码共读
0
【第129期】程序员的新宠:三款终端工具,让你告别Xshell!
概述 WindTerm:跨平台的SSH利器 首先介绍的是WindTerm,这是一款使用C语言开发的跨平台SSH客户端。它不仅完全免费,而且没有商业使用的限制。WindTerm支持SSH v2、Telnet、Raw Tcp等协议,而且性能出色,甚至超过了FinalShell和Electerm。功能
前端微服务
0
字节员工:35岁以后被裁员的,后来都走了哪条路?现在2-2,要不要利用最后一年拼命上个岸。
架构师大咖
架构师大咖,打造有价值的架构师交流平台。分享架构师干货、教程、课程、资讯。架构师大咖,每日推送。
公众号该公众号已被封禁在当今竞争激烈的职场环境中,年龄并不总是一个决定性
源码共读
0
美国司法部重判币安创始人CZ,他到底做错了什么?
注:4月24日,美国司法部表示币安创始人兼前首席执行官赵长鹏应在监狱服刑三年(36个月),根据给出的理由显示,美国司法部律师认为赵长鹏帮助币安违反联邦制裁和洗钱法,并称其必须付出更大的代价,所以应该提高刑期。就在审判前,CZ在写给负责此案件的法官理查德· A · 琼斯的一封信中,为自己的「错误决定」
区块链头条
3
【送书福利】《Java面试八股文:高频面试题与求职攻略一本通》
先来唠唠最近粉丝面试回来跟我聊天,基本上都提到一个点,在面试过程中八股文占比很高(八股文70%、项目20%、10%算法)除了一些搞算法突出的厂除外。其实现在很多厂八股都是逐渐深入的方式来问,所以大家在学习的过程中,针对一些重点的内容,最好深入去学习,不然还是比较难应对这种追问式的问题。最近刚好从一位
Java后端技术
0
上班的时候,有一群摸鱼搭子非常重要...
上班的时候,有一群摸鱼搭子非常重要!一到上班时间,他们就从四面八方涌进群里冒泡...从八卦聊到股市、从职场聊到乌X兰局势,偶尔还会复读、相亲、battle...然后,下午6点钟准时消失不见...所以你要不要加入我们一起摸鱼?我们有北京、上海、深圳、广州、杭州、武汉、成都、南京等8个城市的摸鱼群,还有
产品经理日记
0
周四002 瑞超:同样落寞的境遇——北雪平vs埃尔夫斯堡
上赛季最终排名联赛第9的北雪平本赛季伊始表现不佳,4轮战罢他们仅以1胜1平2负的战绩排在倒数第三,这支历史上曾夺得13次联赛冠军、6次杯赛冠军老牌劲旅,正如英格兰赛场上的一众百年俱乐部,在低谷中不断探索着出路。球队主教练安德烈亚斯·阿尔姆曾是AIK索尔纳及赫根队的主教练,他于今年年初刚刚拿起球队教鞭
产品与体验
0