分布式数据库 30 讲
王磊
光大银行首席数据架构师
29144 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 34 讲
结束语 (1讲)
分布式数据库 30 讲
15
15
1.0x
00:00/00:00
登录|注册

10 | 原子性:如何打破事务高延迟的魔咒?

思考题
优化方法
事务延迟估算
2PC协议
分布式事务优化

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

你好,我是王磊,你也可以叫我 Ivan。
通过上一讲的学习,你已经知道使用两阶段提交协议(2PC)可以保证分布式事务的原子性,但是,2PC 的性能始终是一个绕不过去的坎儿。
那么,它到底有多慢呢?
我们来看一组具体数据。2013 年的 MySQL 技术大会上(Percona Live MySQL C&E 2013),Randy Wigginton 等人在一场名为“Distributed Transactions in MySQL”的演讲中公布了一组 XA 事务与单机事务的对比数据。XA 协议是 2PC 在数据库领域的具体实现,而 MySQL(InnoDB 存储引擎)正好就支持 XA 协议。我把这组数据转换为下面的折线图,这样看起来会更加直观些。
其中,横坐标是并发线程数量,纵坐标是事务延迟,以毫秒为单位;蓝色的折线表示单机事务,红色的折线式表示跨两个节点的 XA 事务。我们可以清晰地看到,无论并发数量如何,XA 事务的延迟时间总是在单机事务的 10 倍以上。
这绝对是一个巨大的性能差距,所以这个演讲最终的建议是“不要使用分布式事务”。
很明显,今天,任何计划使用分布式数据库的企业,都不可能接受 10 倍于单体数据库的事务延迟。如果仍旧存在这样大的差距,那分布式数据库也必然是无法生存的,所以它们一定是做了某些优化。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

分布式数据库的事务原子性一直是一个挑战,传统的两阶段提交协议(2PC)虽然能保证原子性,但性能一直是一个问题。研究表明,跨两个节点的XA事务的延迟时间总是单机事务的10倍以上,这种性能差距对于企业使用分布式数据库是无法接受的。因此,分布式数据库必须进行优化以打破高延迟的魔咒。 文章介绍了2PC协议的事务延迟估算,指出整个2PC的事务延迟由准备阶段和提交阶段组成。在讨论优化方法时,提到了缓存写提交(Buffering Writes until Commit)的方式,TiDB的事务处理中采用了这种方式,能够压缩第一阶段的延迟,将整个事务延迟缩短至大约一轮共识算法的时间。 然而,缓存写提交也存在一些缺点,如在某些业务场景下可能成为瓶颈,以及对于事务竞争的处理方式与传统的First Write Win有所不同。因此,读者需要在实际应用中权衡利弊。 文章还介绍了CockroachDB采用的Pipeline方式,能够缩短准备阶段的延迟,将整体事务延迟降至一轮共识算法的时间。另外,并行提交(Parallel Commits)也是一种优化手段,可以进一步压缩整体延迟至一轮共识算法的开销。 通过分析事务延迟的计算和优化方法,本文为读者提供了关于分布式数据库事务原子性和性能优化的深入了解,为读者在实际应用中做出决策提供了有益的参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《分布式数据库 30 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(22)

  • 最新
  • 精选
  • OliviaHu
    目前听下来,感觉分布式系统的主要优化方法就是攒批+异步(事后补偿)。

    作者回复: 我觉得叫事后补偿有点不准确,异步线程并不会改变事务的状态,只是追溯出来并落盘。所以叫事后追溯可能更准确些。

    2020-08-31
    2
    17
  • 春风
    老师,如果在异步commit之前,客户端又发起查询,查到的数据是怎样的

    作者回复: 这个处理方式和Percolator类似,如果异步线程还没来得及处理,读取操作也要承担异步线程的工作,确认事务状态,从而判断读取哪个版本的数据。

    2020-08-31
    4
    17
  • 星之柱
    并行提交这块看的不是很明白,是指prepare阶段即写数据,又将标记设置为staging吗,然后再读的时候来校验staging是否是大多数?

    作者回复: 事务状态置为staging,是表示事务已经开始但状态未知,而后在所有写入执行完毕后,事务的状态是明确的。但是,如果此时更新事务状态会带来一轮多副本写入的开销,增加延迟。所以,协调者直接向调用方返回事务处理的结果,再由异步线程来更新持久化的事务状态。这个更新过程,不需要考虑多副本的问题,因为所有写入操作都已经完成了多副本的一致性投票。只是要确认每个写入都成功,则可以判定事务成功,否则事务失败。

    2020-11-04
    10
  • 平风造雨
    如果客户端没有在一定的时间内得到所有意向写的反馈(不知道反馈是成功还是失败),要如何处理?

    作者回复: 这个问题其实和2PC的优化没有直接关系了,经典2PC也面临这个问题,参与者没有反馈怎么办。这时有两种策略,一是努力成功型,重发指令,也许就还能成功;二是撤销,直接向所有节点发送回滚指令。

    2020-09-02
    7
  • 南国
    老师,我的上一条留言有点小小的问题,就是应该是第二阶段的优化,也就是并行提交可能考虑到了BASE,因为异步提交后,不做其他措施的话可能出现数据不一致的问题,不知道对于并行提交上一条留言说法还对不对。 还有老师,在Pipeline中事务状态的落盘操作理解为准备阶段每一个写操作的落盘,事务状态的确定理解为每一个写操作的确定,还是不同事务之间状态的确定同步完成呢?这里感觉有脑子有点乱。

    作者回复: 并行提交不是BASE,仍然强一致的。因为,负责发起Pipeline写入的线程是明确知道这些写入都成功了,注意,这个成功是说事务涉及的每个Raft组都写入成功了,那么此时线程可以判定事务已经提交成功了。但是,如果接下来它写盘记录事务的最新状态,就会带来新一轮共识算法开销,而不写盘也不会影响事务状态,所以它直接返回客户端,使得延迟更短。

    2020-09-01
    6
  • 有铭
    如果异步线程没有任何补偿和回滚操作,那它在check状态时如果发现状态有异常时不做处理吗

    作者回复: 事务参与者达成一致状态(成功或失败)主要是同步线程的工作。比如,当网络故障无法获得返回时,同步线程可以根据倾向性选择重试或回滚。不排除网络始终有问题,同步线程无法确定状态,但换作异步线程也同样面临这个问题,没有差异化的处理手段。所以我觉得异步线程的主要职能就是回溯,而不是对状态做实质性干预(包括补偿或回滚),如果真的有这么严重的网络问题,导致所有参与者都无法通讯,那么还是要人工介入解决。

    2020-09-04
    3
  • 南国
    第二种优化方法感觉就比较贴近于BASE了,因为效率放弃强一致性而选择最终一致性,这个最终一致性是系统角度的一致性,可以采取像zk一样的方法支持用户角度强一致性,也就是读前先写得到最新的事务号,读取节点被同步前阻塞就可以了;或者就直接维护一个较弱的一致性模型,当然这都是异步线程做的事情了。到头来还是效率和一致性的取舍,所以感觉不同的系统中这个异步线程的实现就至关重要了

    作者回复: 这个说法不对,异步化的只是事务状态的落盘操作,而事务状态的确认仍然是同步完成的。再体会体会:)

    2020-09-01
    2
    3
  • wy
    并行提交那个思路有点像悲观锁切换到乐观锁的思路。prepare阶段就像加锁阶段,以往的做法是先prepare,锁住资源再commit,而优化的手段就像乐观锁,先并行执行,有冲突再返回错误

    作者回复: 我觉得还是有些区别的。并行提交下,在事务执行过程中,协调者节点对参与者节点的状态判断和处理逻辑并没有发生变化。只是对落盘记录的方式做了调整,让两次落盘引发的投票过程可以同时发生,并相应的增加了事后对事务状态追溯的逻辑。而乐观锁和悲观群则在处理逻辑上有明显的变化。你想想是不是这样:)

    2021-01-12
    1
  • 花晨少年
    缓存写提交的耗时为什么不是一轮共识的时间呢,而是两轮呢?不是提交时把多个写操作和提交操作一起并行执行吗?

    作者回复: 你好,第二轮共识的时间是用来处理事务commit状态落盘。在确认所有写成功后,再次通讯写入事务状态。

    2021-06-14
  • Jenvid
    目前看下来,感觉分布式系统的主要优化方法就是攒批+异步(事后补偿)。

    作者回复: 嗯,也可以这么讲。但异步的具体设计方法还是很巧妙的,也体现了不同产品的水准差异。

    2021-04-15
收起评论
显示
设置
留言
22
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部