【面试】如何保障消息100%投递成功?如何保证消息幂等性?


【面试】如何保障消息100%投递成功?如何保证消息幂等性?

一、前言

我们小伙伴应该都听说够消息中间件MQ,如:RabbitMQ,RocketMQ,Kafka等。引入中间件的好处可以起到抗高并发,削峰,业务解耦的作用。

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

如上图:

(1)订单服务投递消息给MQ中间件 (2)物流服务监听MQ中间件消息,从而进行消费

我们这篇文章讨论一下,如何保障订单服务把消息成功投递给MQ中间件,以RabbitMQ举例。

二、分析问题

小伙伴们对此会有些疑问,订单服务发起消息服务,返回成功不就成功了吗?如下面的伪代码:

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

上面代码中,一般发送消息就是这么写的,小伙伴们觉得有什么问题吗?

下边说一个场景,如果MQ服务器突然宕机了会出现什么情况?是不是我们订单服务发过去的消息全部没有了吗?是的,一般MQ中间件为了提高系统的吞吐量会把消息保存在内存中,如果不作其他处理,MQ服务器一旦宕机,消息将全部丢失。这个是业务不允许的,造成很大的影响。

三、持久化

有经验的小伙伴会说,我知道一个方法就是把消息持久化,RabbitMQ中发消息的时候会有个durable参数可以设置,设置为true,就会持久化。

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

这样的话MQ服务器即使宕机,重启后磁盘文件中有消息的存储,这样就不会丢失了吧。是的这样就一定概率的保障了消息不丢失。

但还会有个场景,就是消息刚刚保存到MQ内存中,但还没有来得及更新到磁盘文件中,突然宕机了。(我靠,这个时间这么短,也会出现,概率太低了吧),这个场景在持续的大量消息投递的过程中,会很常见。

那怎么办?我们如何作才能保障一定会持久化到磁盘上面呢?

四、confirm机制

上面问题出现在,没有人告诉我们持久化是否成功。好在很多MQ有回调通知的特性,RabbitMQ就有confirm机制来通知我们是否持久化成功?

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

confirm机制的原理:

(1)消息生产者把消息发送给MQ,如果接收成功,MQ会返回一个ack消息给生产者;

(2)如果消息接收不成功,MQ会返回一个nack消息给生产者;

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

上面的伪代码,有两个处理消息方式,就是ack回调和nack回调。

这样是不是就可以保障100%消息不丢失了呢?

我们看一下confirm的机制,试想一下,如果我们生产者每发一条消息,都要MQ持久化到磁盘中,然后再发起ack或nack的回调。这样的话是不是我们MQ的吞吐量很不高,因为每次都要把消息持久化到磁盘中。写入磁盘这个动作是很慢的。这个在高并发场景下是不能够接受的,吞吐量太低了。

所以MQ持久化磁盘真实的实现,是通过异步调用处理的,他是有一定的机制,如:等到有几千条消息的时候,会一次性的刷盘到磁盘上面。而不是每来一条消息,就刷盘一次。

所以comfirm机制其实是一个异步监听的机制,是为了保证系统的高吞吐量,这样就导致了还是不能够100%保障消息不丢失,因为即使加上了confirm机制,消息在MQ内存中还没有刷盘到磁盘就宕机了,还是没法处理。

说了这么多,还是没法确保,那怎么办呢???

五、消息提前持久化 + 定时任务

其实本质的原因是无法确定是否持久化?那我们是不是可以自己让消息持久化呢?答案是可以的,我们的方案再一步的演化。

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

上图流程:

(1)订单服务生产者再投递消息之前,先把消息持久化到Redis或DB中,建议Redis,高性能。消息的状态为发送中。

(2)confirm机制监听消息是否发送成功?如ack成功消息,删除Redis中此消息。

(3)如果nack不成功的消息,这个可以根据自身的业务选择是否重发此消息。也可以删除此消息,由自己的业务决定。

(4)这边加了个定时任务,来拉取隔一定时间了,消息状态还是为发送中的,这个状态就表明,订单服务是没有收到ack成功消息。

(5)定时任务会作补偿性的投递消息。这个时候如果MQ回调ack成功接收了,再把Redis中此消息删除。

这样的机制其实就是一个补偿机制,我不管MQ有没有真正的接收到,只要我的Redis中的消息状态也是为【发送中】,就表示此消息没有正确成功投递。再启动定时任务去监控,发起补偿投递。

当然定时任务那边我们还可以加上一个补偿的次数,如果大于3次,还是没有收到ack消息,那就直接把消息的状态设置为【失败】,由人工去排查到底是为什么?

这样的话方案就比较完美了,保障了100%的消息不丢失(当然不包含磁盘也坏了,可以做主从方案)。

不过这样的方案,就会有可能发送多次相同的消息,很有可能MQ已经收到了消息,就是ack消息回调时出现网络故障,没有让生产者收到。

那就要要求消费者一定在消费的时候保障幂等性!

六、幂等含义

我们先了解一下什么叫幂等?在分布式应用中,幂等是非常重要的,也就是相同条件下对一个业务的操作,不管操作多少次,结果都是一样。

6.1、为什么要有幂等这种场景?

为什么要有幂等这种场景?因为在大的系统中,都是分布式部署,如:订单业务 和 库存业务有可能都是独立部署的,都是单独的服务。用户下订单,会调用到订单服务和库存服务。

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

因为分布式部署,很有可能在调用库存服务时,因为网络等原因,订单服务调用失败,但其实库存服务已经处理完成,只是返回给订单服务处理结果时出现了异常。这个时候一般系统会作补偿方案,也就是订单服务再此放起库存服务的调用,库存减1。

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

这样就出现了问题,其实上一次调用已经减了1,只是订单服务没有收到处理结果。现在又调用一次,又要减1,这样就不符合业务了,多扣了。

幂等这个概念就是,不管库存服务在相同条件下调用几次,处理结果都一样。这样才能保证补偿方案的可行性。

6.2、乐观锁方案

借鉴数据库的乐观锁机制,如:

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

根据version版本,也就是在操作库存前先获取当前商品的version版本号,然后操作的时候带上此version号。我们梳理下,我们第一次操作库存时,得到version为1,调用库存服务version变成了2;但返回给订单服务出现了问题,订单服务又一次发起调用库存服务,当订单服务传如的version还是1,再执行上面的sql语句时,就不会执行;因为version已经变为2了,where条件就不成立。这样就保证了不管调用几次,只会真正的处理一次。

6.3、唯一ID + 指纹码

原理就是利用数据库主键去重,业务完成后插入主键标识

【面试】如何保障消息100%投递成功?如何保证消息幂等性?

唯一ID就是业务表的唯一的主键,如商品ID

指纹码就是为了区别每次正常操作的码,每次操作时生成指纹码;可以用时间戳+业务编号的方式。

上面的sql语句:

返回如果为0 表示没有操作过,那业务操作后就可以insert into t_check(唯一ID+指纹码)

返回如果大于0 表示操作过,就直接返回

好处:实现简单

坏处:高并发下数据库瓶颈

解决方案:根据ID进行分库分表进行算法路由

6.4、Redis原子操作

利用redis的原子操作,做个操作完成的标记。这个性能就比较好。但会遇到一些问题。

第一:我们是否需要把业务结果进行数据落库,如果落库,关键解决的问题时数据库和redis操作如何做到原子性?

这个意思就是库存减1了,但redis进行操作完成标记时,失败了怎么办?也就是一定要保证落库和redis 要么一起成功,要么一起失败

第二:如果不进行落库,那么都存储到缓存中,如何设置定时同步策略?

这个意思就是库存减1,不落库,直接先操作redis操作完成标记,然后由另外的同步服务进行库存落库,这个就是增加了系统复杂性,而且同步策略如何设置

以上就是【面试】如何保障消息100%投递成功?如何保证消息幂等性?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/893674.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月28日 16:11:33
下一篇 2025年11月28日 16:16:23

相关推荐

  • 以太坊现货与永续合约背后的套利博弈

    以太坊价格飙升背后是机构利用资金费率进行套利,而非仅由散户热情驱动。1. 散户加杠杆做多ETH,导致杠杆多头头寸远超现货买盘;2. 机构作为对手方,通过Delta中性策略做空永续合约并买入等量现货对冲风险;3. 机构核心盈利来自散户支付的资金费率溢价,自身不承担价格波动风险;4. 持续正向资金费率吸…

    2025年12月8日
    000
  • 以太坊(ETH)近30天飙升47%会不会出现快速回撤

    以太坊短期内大幅回调可能性较低,因两大因素支撑:1.ETF资金流入创新高,大量ETH被锁定减少抛压;2.宏观环境虽复杂但未构成威胁,政策倾向仍利好风险资产。然而,年底达1万美元目标较难,需ETF持续流入、质押功能升级、情绪转向风险偏好及生态广泛采用等多重因素协同推动,当前市场对此持谨慎乐观态度。 以…

    2025年12月8日
    000
  • 新手怎么挑选稳定币交易平台?币安、OKEX、火币三个交易平台分析

    对于新手选择稳定币交易平台的问题,答案如下:1. 币安适合纯粹的新手,提供精简版界面和丰富的生态系统;2. OKEX适合偏好产品创新和高效资产管理的用户,具备统一账户系统和强大的衍生品支持;3. 火币适合重视稳健运营和传统操作逻辑的用户,在亚洲市场根基深厚且安全记录良好。三家平台在稳定币种类、流动性…

    2025年12月8日
    000
  • 比特币和XRP有什么区别?哪个更值得投资?XRP未来能超越比特币吗?

    比特币与XRP的核心差异 数字资产领域存在众多创新,比特币和xrp是其中两个被广泛关注的代表。它们各自拥有独特的设计理念与功能定位,在数字经济中扮演着不同的角色。理解它们之间的差异,有助于把握这些数字资产的特点。 1、设计理念与发行机制:比特币的创建旨在成为一种去中心化的点对点电子现金系统,其发行总…

    2025年12月8日
    000
  • 稳定币干啥用的?稳定币在哪里交易?稳定币种类大全

    稳定币是一种价值稳定的数字资产,通常与美元1:1挂钩,主要用途包括价值储存、交易媒介和支付工具;其种类分为法定资产支持型(如usdt、usdc)、数字资产支持型(如dai)和算法型(如usdd);主流交易平台包括binance、ok和htx。 一、稳定币是做什么用的? 简单来说,稳定币是一种价值相对…

    2025年12月8日
    000
  • 永续合约双雄逐鹿:Bybit与Bitget交易哲学和金融机制有何不同?

    永续合约双雄逐鹿:Bybit与Bitget交易哲学和金融机制有何不同? Bybit 与 Bitget 的机制设计,并无绝对的优劣之分,但各自适配于完全不同的交易者画像与策略需求。 作为紧随 Binance 的衍生品交易所,Bybit 与 Bitget 如何在高度竞争、波动剧烈的永续合约战场中杀出重围…

    2025年12月8日
    000
  • usdt和usdc有什么区别 usdt和usdc哪个安全

    USDC比USDT更安全。1. 储备资产与透明度方面,USDC由现金和美国国债组成,每月由德勤审计并公开报告,透明度高;而USDT储备构成复杂,审计机构非顶级,透明度较低。2. 监管与合规方面,USDC由美国公司Circle发行,持有多个支付牌照,积极合规;USDT则因历史问题与监管关系紧张。 在加…

    2025年12月8日
    000
  • 币圈牛市和熊市怎么区分?新手怎么看币圈行情趋势

    在币圈,牛市通常指的是市场价格普遍上涨、投资者信心高涨的阶段,而熊市则代表市场普遍下跌、恐慌情绪蔓延的状态。了解两者的区别,是判断是否进场、持币或止损的关键。 判断牛市与熊市的常见方式: 1、比特币价格趋势:比特币被视为市场风向标,当其持续上涨并突破历史高点,往往预示牛市来临。 2、整体市值变化:观…

    2025年12月8日
    000
  • ETH和BTC 是什么?市场如何?一文看懂币圈金银币

    ETH / BTC 是什么? ETH/BTC 是以太坊价格(ETH)相对于比特币(BTC)价格的比率,代表用比特币来衡量以太坊的价值。 这个比率不仅代表着以太币相对比特币的兑换价格,更是观察市场信心、资金流向与生态演变的重要指标。 ETH/BTC:币圈金银比 以贵金属价格分析的角度,ETH / BT…

    2025年12月8日
    000
  • 投资加密货币却看不懂K线?一文教你K线要怎么看

    k 线图是交易市场中的基础工具,能够帮助我们理解加密货币价格的波动情况以及买卖力量的对比。关键在于掌握影线、开盘价、收盘价以及颜色所代表的意义。 与传统市场不同的是,加密货币市场全年无休、24 小时运作,因此其K 线图在时间逻辑和颜色表达上也有所不同。 尽管K 线图无法预测未来价格,但如果结合其他分…

    2025年12月8日 好文分享
    000
  • 稳定币、加密币、数字货币的区别

    稳定币、加密币与数字货币的核心区别在于属性与用途。1. 数字货币是广义概念,包含所有以电子形式存在的货币,如支付宝余额、游戏币等;2. 加密货币是数字货币的子集,使用区块链技术实现去中心化交易,如比特币、以太坊。 在数字资产的世界里,选择一个安全可靠的交易平台是投资成功的第一步。本文将为您梳理全球顶…

    2025年12月8日
    000
  • 比特币与莱特币的区别是什么?哪个更有潜力?莱特币会超越比特币吗?

    莱特币难以超越比特币,但可在特定领域发挥优势。1. 比特币采用SHA-256算法,莱特币使用Scrypt算法,后者初期更利于普通设备参与;2. 比特币总量2100万,区块确认约10分钟,莱特币总量8400万,确认速度约2.5分钟;3. 比特币定位为“数字黄金”,主攻价值存储,莱特币定位为“数字白银”…

    2025年12月8日
    000
  • 虚拟货币和区块链是同一个概念吗?

    刚接触币圈的用户常常会把虚拟货币和区块链混为一谈,认为它们就是一个意思。但实际上,二者虽有联系,却并不等同。 虚拟货币是基于区块链技术发行的数字资产,如比特币、以太坊等,具备可流通性、可交易性。 区块链则是一种底层技术,类似账本系统,保障了信息的透明、不可篡改,是支持虚拟货币运转的核心架构。 可以这…

    2025年12月8日
    000
  • 弗洛基·因纽的飙升:Valhalla发布点燃模因币狂热!

    floki inu因价格大幅上涨而引发热议,此次上涨主要由valhalla主网上线推动。这一模因币是否具备开创新局面的能力? Floki Inu正迅速走红!该模因币正经历显著的价格上涨,市场普遍认为Valhalla主网上线是主要推动力。我们一起来看看推动这波热潮的因素及其对FLOKI持有者的影响。 …

    2025年12月8日
    000
  • 火必VS欧意:2025年主流加密交易所功能、费率对比

    欧意在衍生品和Web3生态方面更具优势,火必则在主流现货和品牌稳健性上表现突出。1、交易功能上,欧意衍生品创新更强,流动性略优;2、费率方面,欧意对普通用户更友好,火必对大户更有利;3、生态布局上,欧意整合能力更强,火必项目质量稳定;4、安全与体验上,两者均透明可靠,欧意界面更现代。根据交易偏好选择…

    2025年12月8日
    000
  • 全球美元USDG详解:与USDT、USDC在机制和用途上的差异

    在数字资产领域,稳定币扮演着连接传统金融与加密世界的桥梁。它们旨在价格波动剧烈的数字市场中提供相对稳定的价值存储工具。usdg、usdt和usdc是市场上较为知名的几类美元稳定币,它们各自拥有不同的机制设计和应用场景。理解这些差异,对于数字资产用户至关重要。本文将深入探讨usdg的特点,并将其与us…

    2025年12月8日
    000
  • ETH和比特币区别?交易所购买以太坊教程?

    数字资产领域存在多种数字货币,其中比特币(bitcoin)和以太坊(ethereum)是广受关注的两种。它们各自拥有独特的特性和应用场景。对于希望涉足数字资产的用户来说,理解它们之间的区别以及如何在交易所购买以太坊,是进入这个领域的第一步。 购买以太坊前的准备 1. 了解基础知识 在购买以太坊之前,…

    2025年12月8日 好文分享
    000
  • 平台币是什么?和普通币种有何区别?

    平台币是由数字货币交易平台发行的加密货币,主要用于平台内的生态建设和用户权益激励。相比普通的虚拟币,平台币不仅是一种投资资产,更是连接用户和平台的重要纽带。 平台币的主要用途包括: 1. 交易手续费折扣:使用平台币支付交易手续费可享受优惠,降低交易成本; 2. 投票权和治理:部分平台币持有者可以参与…

    2025年12月8日
    000
  • 新手怎么玩比特币合约交易?和比特币现货交易有什么区别?

    不少刚进入币圈的新手会听到“现货”和“合约”两种交易方式,其中比特币合约交易因其可高倍杠杆和双向操作而备受关注,但也伴随更高风险,并不建议盲目尝试。 现货交易指的是你实际购买BTC并持有,就像买了一份资产,赚的是币价上涨后的差价;而合约交易类似于做“期货”,你可以开多(看涨)或开空(看跌),甚至使用…

    2025年12月8日
    000
  • 机构资金疯买比特币,但散户情绪却反应冷淡

    比特币(btc)的下跌趋势在短短48小时内被逆转,接连突破122,000美元的历史高点。华尔街的技术分析师与传统金融机构纷纷将目标价定在135,000美元,市场正思考这是否是见顶的信号。 分析师看涨至135K 根据Cointelegraph的报道,Fairlead Strategies创始人Kati…

    2025年12月8日
    000

发表回复

登录后才能评论
关注微信