深入浅出分布式技术原理
陈现麟
伴鱼技术中台负责人,前小米工程师
21241 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 39 讲
深入浅出分布式技术原理
15
15
1.0x
00:00/00:00
登录|注册

08|重试幂等:让程序 Exactly-once 很难吗?

2PC机制
幂等消息发送接口
事务保证原子性
唯一ID去重
非幂等操作改写
控制重试间隔
限制重试次数
重新执行任务
删除任务状态
重放消息
故障时系统回滚
定期系统快照
事务保证原子性
唯一ID去重
重试策略
故障前后请求处理不确定性
消息丢失
无界时延
异步网络
新的挑战
本地调用与远程调用
分布式锁
如何实现幂等的消息发送接口?
外部系统幂等性
幂等性保障
重试策略
整体重做
分布式快照加状态回滚
至少一次消息传递加消息幂等性
远端服务故障
网络不可靠
推荐阅读
思考题
Exactly-once 的挑战
保证 Exactly-once 的方法
分布式系统挑战
Exactly-once 问题总结

该思维导图由 AI 生成,仅供参考

你好,我是陈现麟。
通过学习“分布式锁”的内容,你已经了解了如何实现一个分布式锁服务,并且知道了在分布式锁的场景下,我们应该如何在正确性、高可用和高性能之间做取舍。那么对于分布式场景下,实例或服务之间的协调问题,我们就心中有数了,你可以根据业务场景,做出最合适的选择,我们又一起往前走了一大步。
但是,在极客时间的开发过程中,你又面临了一个新的问题。在通过 RPC 远程调用极客时间的课程购买接口的过程中,你可能是这样处理 RPC 的响应结果的,先是将“请求超时”的响应结果解释为“课程购买失败”,返回给用户,可是这会影响到用户的正常购买,导致一部分用户放弃。
后来,为了尽可能让用户购买成功,你对“请求超时”响应的请求进行了重试,发现用户的购买成功率确实提高了,但是却有少量的用户反馈说,他只点击了 1 次购买,页面却出现了 2 笔支付成功的订单。
这确实是一个两难的问题,要么让一部分用户放弃购买,要么让少量的用户重复购买,难道没有一个好的办法吗?这里我们可以先来分析一下这个问题的根本原因,在请求的响应结果为“请求超时”的时候,我们不知道这个请求是否已经被远端的服务执行了,进一步来说就是请求的消息,是否精确一次发送到远端服务的问题,即 Exactly-once
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

分布式系统中的Exactly-once问题一直是一个难题。本文深入讨论了为什么不能保证Exactly-once、如何保证Exactly-once以及Exactly-once的挑战。在分布式系统中,网络故障和远端服务故障是导致消息传递无法保证Exactly-once的主要原因。为了解决这一问题,文章介绍了三种主要的实现方式:至少一次消息传递加消息幂等性、分布式快照加状态回滚以及整体重做。其中,至少一次消息传递加消息幂等性是最适用于在线业务架构系统的方式。然而,这种方式也面临着一些挑战。文章深入浅出地解释了这些挑战,为读者提供了全面的了解。通过本文的阐述,读者可以对分布式系统中的Exactly-once问题有一个清晰的认识,为解决类似问题提供了有益的参考。文章还讨论了分布式系统场景下的重试和幂等的相关问题,总结了保证Exactly-once的三种方式以及在分布式系统中确保Exactly-once面临的挑战。整体而言,本文为读者提供了深入的技术讨论,帮助他们更好地理解和解决分布式系统中的Exactly-once问题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入浅出分布式技术原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(11)

  • 最新
  • 精选
  • 松鼠鱼
    思考题:在 IM 系统中,我们如何实现幂等的消息发送接口? 以Kafka为例,生产者发送消息的时候会带上 ProducerId 和 SequenceNumber,相同批次(batch)的消息 SequenceNumber 是一样的,重复发送时不会被 broker 接受。 同时,开启幂等会默认 acks = -1,也就是一批消息被成功写入需要分区的所有同步副本都接收到才算数,以此确保不丢消息。在这个基础上加上幂等,二者共同保证精确一次。 以上虽然只能确保单次会话、单分区的幂等,但一般情况下,业务上我们会确保某一种类的消息固定发往某一分区(比如根据某个 key 值做哈希取余),而且在消费者端也可以做去重检查,因此问题不大。 如果需要全局的、跨越会话的幂等(精确一次),还是要开事务。

    作者回复: 非常赞!

    2022-02-14
    10
  • Geek2014
    老师你好,想咨询一下 内部的2pc机制怎么实现额,感觉有点语焉不详额 然后我们在当前请求的内部通过 2PC 的机制,确保该请求的内部状态修改逻辑

    作者回复: 在课程事务(二)的原子性中有详细的介绍。

    2022-03-23
    3
  • 处女座♍️
    现在手里的项目正好是基于netty实现的IM即时消息项目,消息头中存了消息id(基于会话层面的递增id),客户端进入会话后会在分布式缓存中建立会话快照(session),session中会存放接收到的最大id,当服务端接收到消息后会比较当前id和session中的id,如果小于等于视为重复消息丢弃。当然这是个客服系统,可以容忍出现细微误差

    作者回复: 赞,最好的系统设计都是贴合业务特点的。

    2022-03-17
    3
  • Geek_192757
    请问老师,外部系统2PC方式具体要怎么做?

    作者回复: 2pc 是保证多个操作的原子性的,用来确保在通过去重保证接口幂等的时候,去重和其他的操作整体是一个原子操作。这里以 IM 的发送消息接口为例介绍,IM 对发送消息接口支持 2PC 协议需要提供下面 3 个接口: Prepare 接口:用来确定当前的消息是否可以发送,如果可以发送,写好 undo 和redo 日志等操作 commit 接口:真正发送消息的操作 rollback 接口:回滚消息的操作 然后由 2PC 的协调者整体来执行协调工作。 在后面的课程“事务(二):原子性,对应用层提供的完美抽象”会有更详细的解释。

    2022-02-15
    2
    3
  • lz404
    如果使用另外的存储比方说redis记录幂等,是不是二者之间就很难一致,可能出现没重试或者多重试

    作者回复: 是的,可以通过 2PC 来保证 redis记录幂的操作和其他的操作是原子的。 不过很多业务场景下,是能容易小概率的不一致的,那么就可以直接通过 redis 记录就行。 我们在做架构设计的时候,一定要对架构设计的边界或者问题有清晰的认识,然后在基于业务情况做 trade-off 。

    2022-02-17
    1
  • 李二木
    前端每次请求会在Header中带一个时间戳。有些接口要求幂等(可以理解为防止重复提交)。每次请求,都会把时间戳作为一个唯一标识来验证接口是不是重复提交。这样的方案可行吗?

    作者回复: 思路是对的,不过时间戳是可能会重复的,不能做唯一标识。

    2022-02-14
    3
    1
  • blentle
    老师能否提供类似的案例补充说明一下

    作者回复: 你好,blentle,是怎么样的形式呢?

    2022-02-16
  • peter
    请教老师四个问题: Q1:怎么标记请求已经处理完成? Q2:“写处理结果”和“写入数据库”,是两个不同的操作吗? Q3:全局唯一ID一般怎么产生? Q4:关于重试幂等,能否举一两个具体的例子?互联网实践的例子。

    作者回复: Q1:“标记请求已经处理”,可以直接在数据库中记录已经处理的请求ID,有新的请求来的时候,先查一下数据库,如果ID存在,则说明已经处理完成。 Q2:如果处理结果都是写入数据库的,就是一个操作 Q3:可以通过分布式ID生成器,或者使用uuid也可以 Q4:课程中的提到的支付场景中,就会经常使用。另外,有的时候,我们的系统和在调用第三方服务后,如果第三方服务是通过异步回调来给我们结果的,那么第三方服务一般都是最少一次的方式来回调,我们来通过幂等来保证正确性。

    2022-02-14
    2
  • javaadu
    如果能有一些常见中间件的应用案例列举会更好
    2022-06-18
    1
  • Jack_1024
    有没有GitHub具体事例代码呀?大佬
    2022-04-24
    1
收起评论
显示
设置
留言
11
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部