15如何解决消息重复,保证消息顺序问题

自信和希望是青年的特权。

——大仲马

引言

我在《12.项目中为什么要使用消息队列》中列举了两个使用消息队列的例子。

(1)收银系统,确认收款成功,通过MQ通知给物流系统发货。

(2)消费积分,用户每消费一笔给用户增加一定积分,京东豆,信用卡积分,2020年如果还没倒闭的电商平台中,可以100%的确定订单系统和积分/奖励系统不是耦合在一起的。

这些都是很典型的使用消息队列的场景。

那么问题来了,想象一下,积分系统收到同一个用户同一个订单两条相同的消息会怎样?积分会被加两遍吗?针对这个问题,面试官又开始一轮三连问,你还能扛得过去吗?

这不是“面试造火箭,工作拧螺丝”,消息重复,消息积压这类问题是你入职后工作中真真切切会遇到的,不是面试官故意刁难你。

1.面试官:那你有考虑过消息重复问题怎么解决吗?

问题分析:

还是拿上面的例子分析,积分系统收到同一个用户同一个订单两条相同的消息会怎样,先不管因为什么原因消息发了两次,积分会被加两遍吗?

产品经理说: 那肯定不行呀,花100块给100个积分,积分没有买一送一服务。

订单系统RD说: 我这边没办法100%保证积分广播只发一次,万一出个bug同一笔消费积分,消息可能发了几百次也不好说。

我:

产品说不行,订单RD说他不保证消息不重复,Kafka架构RD也说无法保证消息不重复,那怎么办?我是负责积分系统的,针对消息重复问题,我会针对积分累计接口做**“幂等”**设计,这个问题,首先我们应该从上游就做消息去重处理,但是我们不能100%相信上游系统一定可靠,我是消息消费端,只有我这边做了幂等设计才能完全避免这种和钱相关的bug,毕竟如果依赖上游,真的出了用户消费100元最后加了100w积分,这锅重要还是我们背。

我可以根据用户订单号或者流水号做强幂等,每成功操作一次加积分就记录下来,即使消息重负了,我只要判断同一个订单号已经操作加分了,后续我们就不会再做任何操作了。

随手写了一段伪代码给面试官:

//没收到给用户消费通知,先判断这个orderId时候已经有加过积分的历史记录,如果没有操作过,则增加。如果已经操作过,直接返回不做任何处理。
List<UserPointHistory> lists = userPointDao.queryHistory(orderId);
if(CollectionUtils.isNotEmpty(lists)){//1.加100分。userPoint.add(pointCount,orderId);//2.保存增加记录userPoint.addHistory(orderId);
}else{log.info("该订单已经操作过积分操作")return null;
}

Tip:如果幂等还不明白可以看我写的《谈谈怎么理解接口幂等设计,项目中如何保证接口幂等》,上面的代码加积分和保存增加记录要保证事务性,如果你不知道ACID千万别给自己挖坑,被面试官逮住ACID一顿问。

面试官:这个问题相对不难,有解决思路问题就不大了。

2.面试官:在多集群消息架构中,如果消费端要求接收到的消息是有序的,怎么解决消息顺序消费问题?

问题分析:

这个问题什么意思呢,比如一个消息Producer发送顺序是1 2 3,那Consumer接收到的消息也是 1 2 3 ,这就比较为难工程师了,但是还是有办法的,想要实现消息有序就要牺牲点什么东西 ---- 性能/可靠性。

我:

这个问题从三个角度考虑:

  1. Producer:让生产端同步发送消息,消息1确定发送成功后再发送消息2,不能异步,保证消息顺序入队。
  2. 服务端:Producer -> MQ Server -> Consumer 一对一关系,一对一服务,这肯定能保证消息是按照顺序消费的,那么问题来了:
    1. Producer -> MQ Server -> Consumer任意一个环节出现问题,那肯定整个链路都阻塞了。
    2. 单通道模型性能成为瓶颈。
  3. topic不分区:意思就是让同一个topic主题都入一个队列,在分布式环境下如果同一个topic进入多个分区,那多个分区之间肯定无法保证消息顺序了。
  4. Consumer:保证消费端是串行消费,禁止使用多线程。

但是这些方法都会牺牲掉系统的性能和稳定性,顺序性问题非要使用MQ来做,那也没有太好的办法了。

3.面试官:那如何做到topic不分区,能举例说明一下吗?

问题分析:

说真的,工作中要求消息顺序消费的业务场景真的挺少见的,用到的时候少,你可以不用深入研究这一块,知道方法就行,到时候真的遇到了知道从哪个方向下手。

我:

用当前比较流行的RocketMQKafka举例。

  • RocketMQ:RocketMQ提供了MessageQueueSelector队列选择机制,我们可以把 Topic 用Hash取模法,相同Topic的Hash值肯定是一样的,让同一个 Topic 同一个队列中,再使用同步发送,这样就能保证消息在一个分区有序了。
  • Kafka: Kafka可以把 max.in.flight.requests.per.connection 参数设置成1,这样就可以保证同一个topic在同一个分区内了。

Tip:

Topic就是一个字符串,给同一类消息取个名字加以区分,如:topic.com.xxx.order.orderId,大多数用户都可以通过message key来定义,因为同一个key的message可以保证只发送到同一个partition,比如说key是user id,table row id等等。

总结

关于消息重复和消息顺序消费问题解决思路比较简单,都是一些小技巧,虽然内容比较枯燥,但是我已经尽力说得通俗易懂。

如果用两句话概括这一接的内容:

  1. 如何保证消息重复问题:消费端接口幂等。
  2. 如何保证消息顺序消费问题:让同一个消息不分区,且单线程。

当然面试的时候你可别这么干巴巴两句话,那显得你太没水平了,面试最理想的效果就是无论多简单的问题你都能滔滔不绝让面试官无话可说

面试精讲之面试考点及大厂真题 - 分布式专栏 15 如何解决消息重复,保证消息顺序问题相关推荐

  1. 面试精讲之面试考点及大厂真题 - 分布式专栏 13项目中为什么要使用消息队列

    13项目中为什么要使用消息队列 学习从来无捷径,循序渐进登高峰. -- 高永祚 引言 上个章节把Redis夺命连环问掰扯完,面试还没有结束,消息队列同样是面试中必问的,分布式构建三把斧:缓存+异步+数 ...

  2. 面试精讲之面试考点及大厂真题 - 分布式专栏 17 ElasticSearch解决大数据量检索难题

    17 ElasticSearch解决大数据量检索难题 理想的书籍是智慧的钥匙. --列夫·托尔斯泰 引言 如果你的项目里有超过千万上亿级别的数据,且数据日增量较大需要高性能检索时,如订单数据,你该怎么 ...

  3. 面试精讲之面试考点及大厂真题 - 分布式专栏 01 开篇词:我是怎样带你通过大厂面试

    01 开篇词:我是怎样带你通过大厂面试 自信和希望是青年的特权. --大仲马 学习编程是一场修行,要经历从 0 到 1,普通人从自己的错误中学习,聪明人从别人的错误中学习. 授人以鱼不如授人以鱼杆儿, ...

  4. 面试精讲之面试考点及大厂真题 - 分布式专栏 14 全面了解Kafka的使用与特性

    14全面了解Kafka的使用与特性 每个人都是自己命运的主宰. --斯蒂尔斯 引言 (图片来源:https://medium.com/) 上一小节说了消息队列的使用,那么面试官也会顺着MQ话题展开讨论 ...

  5. 面试精讲之面试考点及大厂真题 - 分布式专栏 07 说一说什么是正向代理,反向代理

    07 说一说什么是正向代理,反向代理 世界上最快乐的事,莫过于为理想而奋斗. --苏格拉底 引言 05小节面完了RPC相关的一系列问题,面试官确定我对分布式架构的理论知识和服务间通讯框架(RPC) 确 ...

  6. 面试精讲之面试考点及大厂真题 - 分布式专栏 06 详细说下CAP分别代表什么含义吗

    06详细说下CAP分别代表什么含义吗 合理安排时间,就等于节约时间. --培根 引言 上一节讲面试中被问到分布式系统概念相关的,讲完了分布式系统的概念,优点缺点和 RPC 后,我以为这个问题就到此结束 ...

  7. 面试精讲之面试考点及大厂真题 - 分布式专栏 04 谈谈你对分布式的理解,为什么引入分布式?

    04谈谈你对分布式的理解,为什么引入分布式? 引言 刚刚毕业第一份工作,没接触过分布式微服务相关的知识,后来换工作才了解到这些,面试官看了我简历里写了分布式相关,就开始揪住这个问题问,虽然一知半解地说 ...

  8. 面试精讲之面试考点及大厂真题 - 分布式专栏 03 阿里华为资深HR面试套路全揭晓

    03 阿里华为资深HR面试套路全揭晓 HR 面试套路大全 如果你技术面试过了,进入最后一轮 HR 谈薪资,先别高兴太早,千万不要轻视 HR.BAT 大公司,HR 有一票否决权,即使你技术 OK,领导也 ...

  9. 面试精讲之面试考点及大厂真题 - 分布式专栏 23 分布式系统下分布式锁的实现

    23 分布式系统下分布式锁的实现 困难只能吓倒懦夫懒汉,而胜利永远属于敢于等科学高峰的人. --茅以升 引言 锁是开发过程中十分常见的工具,你一定不陌生,悲观锁,乐观锁,排它锁,公平锁,非公平锁等等, ...

最新文章

  1. 关于HttpClient上传中文乱码的解决办法
  2. 调用Remoting的两种激活方式和以及因此而产生的三种.net Remoting对象
  3. linux fortran 内存不足,内存不够不用怕! 虚拟内存不足的十种解决办法
  4. 用java画工作流流程图,java生成流程图
  5. 嵌入式linux快速入门
  6. 小型超市管理系统(JAVA,JSP,SSH,MYSQL)
  7. 【ABC 132 E】Hopscotch Addict(最短路)
  8. 2021-08-06随记(vertical-align, 顶线、底线、中线、基线,vue原理理解)
  9. 财报向好背后,特步的持续爆发力
  10. [JZOJ4274] 终章-剑之魂
  11. resultful规范使用
  12. 民谣吉他音源 OTS Evolution Acoustic Guitar Steel Strings 2 Kontakt
  13. git 提交时报错 error: failed to push some refs to ‘https://github.com/xxx/demo.git 解决方法
  14. MATLAB中能对三角函数降幂嘛,初中数学三角函数降幂公式
  15. axure如何页面滑动时广告位上移_Axure实现滚动广告效果
  16. 计算机词汇店名,电脑店名字200例
  17. 印象笔记导出为pdf
  18. 领导提拔你,还是干掉你,从来都不是看能力!
  19. 训练赛一:bfs广搜题目 CF115B Lawnmower
  20. 图像傅里叶变换(快速傅里叶变换FFT)

热门文章

  1. 制作自定义工作流(WWF)设计器
  2. Magento教程 2:Magento 社群版安装教学!
  3. MYSQL模式匹配:REGEXP和like用法
  4. How to install Aptana Studio 3 on Ubuntu 12.04 LTS (Precise Pangolin)
  5. 人工智障学习笔记——机器学习(4)支持向量机
  6. 并查集——畅通工程(hdu1232)
  7. Linux下ACE、xml解析库开发环境搭建
  8. 【AI视野·今日Robot 机器人论文速览 第十期】Fri, 18 Jun 2021
  9. 【C/C++】异或操作巧妙实现两个数的交换操作
  10. 四窗口卖票 自己的票