【转载】阿里分布式事务框架Seata原理解析

微服务 0 1351
唐志兴(技术开发部)
唐志兴(技术开发部) LV2 关注 2022年4月28日 15:42 编辑
<p cid="n2" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">Seata框架是一个业务层的XA(两阶段提交)解决方案。在理解Seata分布式事务机制前,我们先回顾一下数据库层面的XA方案。</span></p><h1 cid="n3" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 2.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.2; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">1. MySQL XA方案</span></h1><p cid="n4" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">MySQL从5.7开始加入了分布式事务的支持。MySQL XA中拥有两种角色:</span></p><ul cid="n5" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n6" mdtype="list_item" style="position: relative;"><p cid="n7" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">RM(Resource Manager):用于直接执行本地事务的提交和回滚。在分布式集群中,一台MySQL服务器就是一个RM。</span></strong></span></p></li><li cid="n8" mdtype="list_item" style="position: relative;"><p cid="n9" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">TM(Transaction Manager):TM是分布式事务的核心管理者。事务管理器与每个RM进行通信,协调并完成分布式事务的处理。发起一个分布式事务的MySQL客户端就是一个TM。</span></strong></span></p></li></ul><p cid="n10" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">XA的两阶段提交分为Prepare阶段和Commit阶段,过程如下:</span></p><ol cid="n11" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n12" mdtype="list_item" style="position: relative;"><p cid="n13" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">阶段一为准备(prepare)阶段。即所有的RM锁住需要的资源,在本地执行这个事务(执行sql,写redo/undo log等),但不提交,然后向Transaction Manager报告已准备就绪。</span></p></li><li cid="n14" mdtype="list_item" style="position: relative;"><p cid="n15" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">阶段二为提交阶段(commit)。当Transaction Manager确认所有参与者都ready后,向所有参与者发送commit命令。</span></p></li></ol><p cid="n16" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">如下图所示:</span></p><p cid="n17" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"></p><p cid="n18" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-2b322fcc5cb6c274.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/637/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n19" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">XA.PNG</span></p><p cid="n20" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">MySQL XA拥有严重的性能问题。一个数据库的事务和多个数据库间的XA事务性能对比可发现,性能差10倍左右。另外,XA过程中会长时间的占用资源(加锁)直到两阶段提交完成才释放资源。</span></p><h1 cid="n21" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 2.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.2; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">2. Seata</span></h1><p cid="n22" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">Seata的分布式事务解决方案是业务层面的解决方案,只依赖于单台数据库的事务能力。Seata框架中一个分布式事务包含3中角色:</span></p><ul cid="n23" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n24" mdtype="list_item" style="position: relative;"><p cid="n25" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。</span></strong></span></p></li><li cid="n26" mdtype="list_item" style="position: relative;"><p cid="n27" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。</span></strong></span></p></li><li cid="n28" mdtype="list_item" style="position: relative;"><p cid="n29" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。</span></strong></span></p></li></ul><p cid="n30" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">其中,TM是一个分布式事务的发起者和终结者,TC负责维护分布式事务的运行状态,而RM则负责本地事务的运行。如下图所示:</span></p><p cid="n31" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-a1c292d157a0499d.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/770/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n32" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">Seata.PNG</span></p><p cid="n33" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">下面是一个分布式事务在Seata中的执行流程:</span></p><ol cid="n34" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n35" mdtype="list_item" style="position: relative;"><p cid="n36" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。</span></strong></span></p></li><li cid="n37" mdtype="list_item" style="position: relative;"><p cid="n38" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">XID 在微服务调用链路的上下文中传播。</span></strong></span></p></li><li cid="n39" mdtype="list_item" style="position: relative;"><p cid="n40" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">RM 向 TC 注册分支事务,接着执行这个分支事务并提交(重点:RM在第一阶段就已经执行了本地事务的提交/回滚),最后将执行结果汇报给TC。</span></strong></span></p></li><li cid="n41" mdtype="list_item" style="position: relative;"><p cid="n42" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。</span></strong></span></p></li><li cid="n43" mdtype="list_item" style="position: relative;"><p cid="n44" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="strong"><strong><span md-inline="plain">TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。</span></strong></span></p></li></ol><h2 cid="n45" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.75em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.225; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">2.1 为什么Seata在第一阶段就直接提交了分支事务?</span></h2><p cid="n46" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">Seata能够在第一阶段直接提交事务,是因为Seata框架为每一个RM维护了一张UNDO_LOG表(这张表需要客户端自行创建),其中保存了每一次本地事务的回滚数据。因此,二阶段的回滚并不依赖于本地数据库事务的回滚,而是RM直接读取这张UNDO_LOG表,并将数据库中的数据更新为UNDO_LOG中存储的历史数据。</span></p><p cid="n47" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">如果第二阶段是提交命令,那么RM事实上并不会对数据进行提交(因为一阶段已经提交了),而实发起一个异步请求删除UNDO_LOG中关于本事务的记录。</span></p><blockquote cid="n48" mdtype="blockquote" style="margin-top: 0.8em; margin-bottom: 0.8em; border-left-width: 4px; border-left-color: rgb(223, 226, 229); padding: 0px 15px; color: rgb(119, 119, 119); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><p cid="n49" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; position: relative;"><span md-inline="plain">由于Seata一阶段直接提交了本地事务,因此会造成隔离性问题,因此Seata的默认隔离级别为Read Uncommitted。然而Seata也支持Read Committed的隔离级别,我们会在下文中介绍如何实现。</span></p></blockquote><h2 cid="n50" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.75em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.225; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">2.2 Seata执行流程</span></h2><p cid="n51" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">下面是一个Seata中一个分布式事务执行的详细过程:</span></p><ol cid="n52" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n53" mdtype="list_item" style="position: relative;"><p cid="n54" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">首先TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。</span></p></li><li cid="n55" mdtype="list_item" style="position: relative;"><p cid="n56" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">XID 在微服务调用链路的上下文中传播。</span></p></li><li cid="n57" mdtype="list_item" style="position: relative;"><p cid="n58" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">RM 开始执行这个分支事务,RM首先解析这条SQL语句,生成对应的UNDO_LOG记录。下面是一条UNDO_LOG中的记录:</span></p></li></ol><p cid="n59" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"></p><pre spellcheck="false" lang="json" cid="n60" mdtype="fences" style="overflow: visible; font-family: var(--monospace); font-size: 0.9em; break-inside: avoid; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; border-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-color: rgb(231, 234, 237); border-image: initial; border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); position: relative !important;"><span role="presentation" style="padding-right: 0.1px;">{</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"branchId"</span>: <span style="color: rgb(17, 102, 68);">641789253</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"undoItems"</span>: [{</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"afterImage"</span>: {</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"rows"</span>: [{</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"fields"</span>: [{</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"name"</span>: <span style="color: rgb(170, 17, 17);">"id"</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"type"</span>: <span style="color: rgb(17, 102, 68);">4</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"value"</span>: <span style="color: rgb(17, 102, 68);">1</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"name"</span>: <span style="color: rgb(170, 17, 17);">"name"</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"type"</span>: <span style="color: rgb(17, 102, 68);">12</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"value"</span>: <span style="color: rgb(170, 17, 17);">"GTS"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"name"</span>: <span style="color: rgb(170, 17, 17);">"since"</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"type"</span>: <span style="color: rgb(17, 102, 68);">12</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"value"</span>: <span style="color: rgb(170, 17, 17);">"2014"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }]</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }],</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"tableName"</span>: <span style="color: rgb(170, 17, 17);">"product"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; },</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"beforeImage"</span>: {</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"rows"</span>: [{</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"fields"</span>: [{</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"name"</span>: <span style="color: rgb(170, 17, 17);">"id"</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"type"</span>: <span style="color: rgb(17, 102, 68);">4</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"value"</span>: <span style="color: rgb(17, 102, 68);">1</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"name"</span>: <span style="color: rgb(170, 17, 17);">"name"</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"type"</span>: <span style="color: rgb(17, 102, 68);">12</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"value"</span>: <span style="color: rgb(170, 17, 17);">"TXC"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"name"</span>: <span style="color: rgb(170, 17, 17);">"since"</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"type"</span>: <span style="color: rgb(17, 102, 68);">12</span>,</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"value"</span>: <span style="color: rgb(170, 17, 17);">"2014"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }]</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }],</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"tableName"</span>: <span style="color: rgb(170, 17, 17);">"product"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; },</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"sqlType"</span>: <span style="color: rgb(170, 17, 17);">"UPDATE"</span></span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; }],</span><br><span role="presentation" style="padding-right: 0.1px;"> &nbsp; &nbsp;<span style="color: rgb(0, 0, 0);">"xid"</span>: <span style="color: rgb(170, 17, 17);">"xid:xxx"</span></span><br><span role="presentation" style="padding-right: 0.1px;">}</span></pre><p cid="n61" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">可以看到,UNDO_LOG表中记录了分支ID,全局事务ID,以及事务执行的redo和undo数据以供二阶段恢复。</span></p><ol cid="n62" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n63" mdtype="list_item" style="position: relative;"><p cid="n64" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">RM在同一个本地事务中执行业务SQL和UNDO_LOG数据的插入。在提交这个本地事务前,RM会向TC申请关于这条记录的全局锁。如果申请不到,则说明有其他事务也在对这条记录进行操作,因此它会在一段时间内重试,重试失败则回滚本地事务,并向TC汇报本地事务执行失败。如下图所示:</span></p></li></ol><p cid="n65" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-eb31944671b34890.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/724/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n66" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">Seata执行流程.PNG</span></p><ol cid="n67" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n68" mdtype="list_item" style="position: relative;"><p cid="n69" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">RM在事务提交前,申请到了相关记录的全局锁,因此直接提交本地事务,并向TC汇报本地事务执行成功。此时全局锁并没有释放,全局锁的释放取决于二阶段是提交命令还是回滚命令。</span></p></li><li cid="n70" mdtype="list_item" style="position: relative;"><p cid="n71" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">TC根据所有的分支事务执行结果,向RM下发提交或回滚命令。</span></p></li><li cid="n72" mdtype="list_item" style="position: relative;"><p cid="n73" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">RM如果收到TC的提交命令,首先立即释放相关记录的全局锁,然后把提交请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。异步队列中的提交请求真正执行时,只是删除相应 UNDO LOG 记录而已。</span></p></li></ol><p cid="n74" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-ac0e9aef7823b904.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/851/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n75" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">提交.png</span></p><ol cid="n76" mdtype="list" style="margin-top: 0.8em; margin-bottom: 0.8em; margin-left: 0px; padding-left: 30px; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><li cid="n77" mdtype="list_item" style="position: relative;"><p cid="n78" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0.5rem; white-space: pre-wrap; position: relative;"><span md-inline="plain">RM如果收到TC的回滚命令,则会开启一个本地事务,通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。将 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理。否则,根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句并执行,然后提交本地事务达到回滚的目的,最后释放相关记录的全局锁。</span></p></li></ol><p cid="n79" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-55a64b6656f10f68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/775/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n80" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">回滚.png</span></p><h2 cid="n81" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 1.75em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.225; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">2.3 Seata隔离级别</span></h2><p cid="n82" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">Seata由于一阶段RM自动提交本地事务的原因,默认隔离级别为Read Uncommitted。如果希望隔离级别为Read Committed,那么可以使用</span><span md-inline="code" spellcheck="false"><code style="font-family: var(--monospace); vertical-align: initial; border: 1px solid rgb(231, 234, 237); background-color: rgb(243, 244, 244); padding: 0px 2px; font-size: 0.9em;">SELECT...FOR UPDATE</code></span><span md-inline="plain">语句。Seata引擎重写了</span><span md-inline="code" spellcheck="false"><code style="font-family: var(--monospace); vertical-align: initial; border: 1px solid rgb(231, 234, 237); background-color: rgb(243, 244, 244); padding: 0px 2px; font-size: 0.9em;">SELECT...FOR UPDATE</code></span><span md-inline="plain">语句执行逻辑,</span><span md-inline="code" spellcheck="false"><code style="font-family: var(--monospace); vertical-align: initial; border: 1px solid rgb(231, 234, 237); background-color: rgb(243, 244, 244); padding: 0px 2px; font-size: 0.9em;">SELECT...FOR UPDATE</code></span><span md-inline="plain"> 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 </span><span md-inline="code" spellcheck="false"><code style="font-family: var(--monospace); vertical-align: initial; border: 1px solid rgb(231, 234, 237); background-color: rgb(243, 244, 244); padding: 0px 2px; font-size: 0.9em;">SELECT...FOR UPDATE</code></span><span md-inline="plain"> 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是已提交的才返回。</span></p><p cid="n83" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-e2c56f3a431b0786.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/720/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n84" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">SELECT FOR UPDATE.PNG</span></p><p cid="n85" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。</span></p><h1 cid="n86" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 2.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.2; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">3. Seata支持的模式</span></h1><p cid="n87" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">上文中我们提到的Seata流程只是Seata支持的一种分布式事务模式,称为AT模式。它依赖于RM拥有本地数据库事务的能力,对于客户业务无侵入性。如图所示:</span></p><p cid="n88" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"></p><p cid="n89" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-26d2ee5280a41550.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/747/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n90" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">AT.PNG</span></p><p cid="n91" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">AT模式中业务逻辑不需要关注事务机制,分支与全局事务的交互过程自动进行。</span></p><p cid="n92" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">另外,Seata还支持MT模式。MT模式本质上是一种TCC方案,业务逻辑需要被拆分为 Prepare/Commit/Rollback 3 部分,形成一个 MT 分支,加入全局事务。如图所示:</span></p><p cid="n93" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"></p><p cid="n94" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-c3e2212a0584bb1f.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/747/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n95" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">MT.PNG</span></p><p cid="n96" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">MT 模式一方面是 AT 模式的补充。另外,更重要的价值在于,通过 MT 模式可以把众多非事务性资源纳入全局事务的管理中。</span></p><h1 cid="n97" mdtype="heading" style="break-after: avoid-page; break-inside: avoid; orphans: 4; font-size: 2.25em; margin-top: 1rem; margin-bottom: 1rem; position: relative; font-weight: bold; line-height: 1.2; cursor: text; border-bottom: 1px solid rgb(238, 238, 238); white-space: pre-wrap; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif;"><span md-inline="plain">4. XA和Seata AT的对比</span></h1><p cid="n98" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-582400aef9e9f85e.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/721/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n99" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">XA和Seata.PNG</span></p><blockquote cid="n100" mdtype="blockquote" style="margin-top: 0.8em; margin-bottom: 0.8em; border-left-width: 4px; border-left-color: rgb(223, 226, 229); padding: 0px 15px; color: rgb(119, 119, 119); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><p cid="n101" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; position: relative;"><span md-inline="plain">注:Seata的曾用名为FESCAR。</span></p></blockquote><p cid="n102" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">如图所示,</span><span md-inline="strong"><strong><span md-inline="plain">XA 方案的 RM 实际上是在数据库层,RM 本质上就是数据库自身(通过提供支持 XA 的驱动程序来供应用使用)。而 Seata 的 RM 是以二方包的形式作为中间件层部署在应用程序这一侧的,不依赖与数据库本身对协议的支持,当然也不需要数据库支持 XA 协议</span></strong></span><span md-inline="plain">。这点对于微服务化的架构来说是非常重要的:应用层不需要为本地事务和分布式事务两类不同场景来适配两套不同的数据库驱动。</span></p><p cid="n103" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">另外,</span><span md-inline="strong"><strong><span md-inline="plain">XA方案无论 Phase2 的决议是 commit 还是 rollback,事务性资源的锁都要保持到 Phase2 完成才释放。而对于Seata,将锁分为了本地锁和全局锁,本地锁由本地事务管理,在分支事务Phase1结束时就直接释放。而全局锁由TC管理,在决议 Phase2 全局提交时,全局锁马上可以释放。</span></strong></span><span md-inline="plain">只有在决议全局回滚的情况下,全局锁 才被持有至分支的 Phase2 结束。因此,Seata对于资源的占用时间要少的多。对比如下图所示:</span></p><p cid="n104" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-4a4c16c6450f0b2b.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/734/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p><p cid="n105" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="plain">XA锁资源.PNG</span></p><p cid="n106" mdtype="paragraph" style="line-height: inherit; orphans: 4; margin-top: 0.8em; margin-bottom: 0.8em; white-space: pre-wrap; position: relative; color: rgb(51, 51, 51); font-family: &quot;Open Sans&quot;, &quot;Clear Sans&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, &quot;Segoe UI Emoji&quot;, sans-serif; font-size: 16px;"><span md-inline="image" style="min-width: 10px; min-height: 10px; position: relative; word-break: break-all; font-family: monospace; vertical-align: top; display: inline-block; width: 963.996px;"><img referrerpolicy="no-referrer" alt="img" src="https:////upload-images.jianshu.io/upload_images/448235-8975777f610a1d82.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/728/format/webp" onerror="onImageErrorFunc(event)" onload="onLoadedFuncForQuickAction(event)" style="border-width: 0px 4px 0px 2px; border-top-style: initial; border-right-style: solid; border-bottom-style: initial; border-left-style: solid; border-right-color: transparent; border-left-color: transparent; max-width: 100%; image-orientation: from-image; cursor: default; display: block; margin: auto;"></span></p>
赞(0) 收藏(0)  分享
相关标签: 分布式事务 Seata
0个回复
  • 消灭零回复
Vaptcha启动中...