摘要:分布式事务与云原生技术有很强的关联,可以帮助云原生应用程序实现高效的分布式事务处理。
本文分享自华为云社区《理解和学习事务,让你更好地融入云原生时代》,作者: breakDawn。
随着云原生的概念越来越火,服务的架构应该如何发展和演进,成为很多程序员关心的话题。大名鼎鼎的《深入理解java虚拟机》一书作者于21年推出了新作《凤凰架构》,从这本书中可以看到当前时下很多最新的技术或者理念。
因此本文以及后续都将持续沉淀发布这本书的学习笔记和思考,也欢迎购买该书进行详细学习,或者关注后续的学习笔记内容发布,了解精华内容和总结思考。
事务有四个经典的特性ACID:
这四个特性ACID中, C其实是目的, AID是手段。只靠内部(单数据源)可以用AID实现C,但是外部(多数据源)的情况下没法用AID保证C。
本地事务是一种最基础的事务解决方案,适用单个服务使用单个数据源的场景。(注意,对于MyISAM来说,代码层面调用的rollback其实是空操作,引擎内置了事务处理,不需要代码调用rollback)本地事务的实现原理来自ARIES(基于语义的恢复与隔离算法)。
本地事务中, 写入磁盘的过程可能不是原子的,是会崩溃的。因此要考虑2个异常情况:
解决方式:
引入commit log, 即将事务对数据的修改先写入commit log,写入成功代表事务成功,写入完成后再写磁盘,如果中途崩溃了就重新写入,等同于熟知的redo-log!
这也是为什么redo-log中是针对某个物理块的修改,目的就是能正确重新,不用考虑我写到哪个位置了,直接全部重刷即可。
但是这样性能太慢,希望能在事务提交完成前提前写入磁盘,但是提前写的话可能会非原子。这时候就可以引入 undolog, 即触发回滚时,可以讲已操作的数据进行undo回滚操作。这也是为什么undo-log记录的是一条条不可重复执行的语句。
文中还提了2个特征:
隔离性主要就是依赖 数据库锁和数据库隔离级别实现。书中用作者自己的话简述了一遍从可串行化 到可重复读到读已提交到读未提交的演变过程和实现原理, 也提了以下MVCC等内容。
看完后感觉和我这篇文章讲的内容基本对的上:将数据库9种锁、3种读、4种隔离级别一次性串联起来,用15张图呈现背后数据库事务背后的并发原理
里面有几句比较重要的话:
这里的全局事务指的是 单个服务 使用多个数据源。核心在于是单个服务,不涉及多服务之间的关联, 视角只有单服务。
XA接口是双向的,能在一个事务管理器和多个资源管理器之间形成通信桥梁,协调多个数据源的一致动作,实现全局事务的统一提交和回滚。Java基于XA接口衍生出的API叫做JTA(javax.transaction.TrancsactionManager和 XAResource)。
注意对于全局事务,调用XA的应用者是可以不需要额外处理的,XA会协助做好以下全局事务的响应操作。
准备阶段
数据源将需要做的事务操作记录在redolog中,完成了持久化,并仍旧持有锁,保持隔离性
提交阶段
协调者收到了所有数据源的回应后, 给所有数据源发送commit指令,如果有任一失败或者超时,则发送abort回滚指令。
2PC的缺点:
为了解决上面的单点问题和 准备阶段的性能问题,引入3PC协议。将准备阶段扩展为:
CanCommit询问阶段
这个阶段就是为了确认各机器是否还是正常的,如果经过确认都是正常负载的状态,再下发事务操作,这样就能避免被网络超时、不良负载拖累的风险。
PreCommit预提交阶段
和之前一样,下发事务后各数据源写入重做日志。
DoCommit阶段
这个过程有一个优化, 如果协调者挂了, 数据源迟迟无法收到,就会默认进行事务提交(注意并非默认回滚),3PC仍然存在网络问题导致的一致性问题。
书里说这个不常用,不写了,类似于提供共享的数据连接给不同进程使用,使用同一个事务逻辑
科学家证明CAP只能同时满足2个
BASE指 基本可用性 + 柔性事务 + 最终一致性, 或者叫做最大努力交付
实现原理是引入一个消息队列,当某个事务动作发生异常时, 在轮询阶段不断重试,直到成功。
要求满足幂等性,可靠性事件队列只要第一步完成了,后续就没有失败回滚的概念,只许成功,不许失败。
TCC用于解决BASE中无法解决的隔离性问题,因为BASE不允许失败,一定会执行,如果涉及了超售等问题将无法解决。
和2PC很类似,但TCC是在用户应用代码层面实现的,业务侵入性很高, 而2PC是基础设施层面提供的。
TCC中的缺点在于 try阶段和cancel阶段依赖用户代码实现,但如果你的业务不支持这种操作就麻烦了,比如扣款动作是某个银行做的, 他不支持预扣款的功能。
SAGA会把事务拆成很多个小事务T,按顺序执行, 并根据情况给事务T失败时选择是继续重试T, 还是用补偿事务C来替代重试
这样像银行无法预扣款也无法撤销转账的问题,可以改成自己系统来做中间者做转账操作。也要引入SAGAlog机制避免长串事务执行过程中崩溃。
其实学习本文时,更重要的是思考为什么要学习这么多的事务概念和原理。在云原生时代。
像华为云提供的很多数据库类型的云服务也都支持了分布式事务的能力,例如
华为云RDS分布式事务:
基于2PC原理实现的MSDTC分布式事务协调器
华为云DDM事务模型:
这里面的分布式事务模块基于 MySQL XA 协议实现,XA 协议是对 2PC(Two Phase Commit) 事务模型的一种实现。
华为云DWS分布式事务:
基于强一致性的CSN事务机制,使用GaussDB分布式框架下的一个组件GTM以及从中获取到的CSN值来处理事务。
毕竟云原生应用程序通常由多个微服务组成,因此需要在微服务之间进行通信,并保证事务的一致性。在这种情况下,就需要一种适用业务场景的分布式事务解决方案。比如TCC可以在微服务之间实现分布式事务的ACID特性,而且相对于其他方案,TCC更轻量级,对性能影响更小,但其他方案也有各自的适应场景。
因此,分布式事务与云原生技术有很强的关联,可以帮助云原生应用程序实现高效的分布式事务处理。当使用某个关系型数据库产品时,关注他们的分布式事务处理能力并分析是否适合自己当前的业务场景,是非常重要的,也是本书该章节值得学习的一个理由。