<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Transaction on NoneBack</title><link>https://noneback.github.io/zh/tags/transaction/</link><description>Recent content in Transaction on NoneBack created by</description><generator>Hugo -- gohugo.io</generator><language>zh</language><copyright>@NoneBack All rights reserved</copyright><lastBuildDate>Thu, 28 Sep 2023 10:43:23 +0800</lastBuildDate><atom:link href="https://noneback.github.io/zh/tags/transaction/index.xml" rel="self" type="application/rss+xml"/><item><title>Percolator: Large-scale Incremental Processing Using Distributed Transactions and Notifications</title><link>https://noneback.github.io/zh/blog/zh/percolator/</link><pubDate>Thu, 28 Sep 2023 10:43:23 +0800</pubDate><guid>https://noneback.github.io/zh/blog/zh/percolator/</guid><description>&lt;p&gt;好久没学习了，学点想学的。本次内容是分布式事务Percolator, 不翻译论文，没有算法细节，只记录自己的理解。&lt;/p&gt;
&lt;h2 id="percolator-和-2pc"&gt;Percolator 和 2PC&lt;/h2&gt;
&lt;h3 id="2pc"&gt;2PC&lt;/h3&gt;
&lt;p&gt;两阶段提交协议中包含两种角色，&lt;strong&gt;Coordinator和Participant&lt;/strong&gt;。协调者负责整个协议的推进，使得多个参与者最终达到一致的决议。参与者响应协调者的请求，根据协调者的请求完成 prepare 操作及 commit/abort 操作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2PC协议保证事务的原子性(ACD)&lt;/strong&gt;，并&lt;strong&gt;未对隔离性(I)做任何实现&lt;/strong&gt;，依赖单机事务(ACD)。Coordinator，显然是关键路径，可能成为单点瓶颈，或者宕机问题阻塞事务流程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="code-block" data-language="text"&gt;
&lt;div class="code-block-header"&gt;
&lt;div class="code-block-meta"&gt;
&lt;span class="code-block-language"&gt;text&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block-actions"&gt;
&lt;button class="copy-code" type="button" aria-label="复制"&gt;复制&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; 协调者 参与者
QUERY TO COMMIT
--------------------------------&amp;gt;
VOTE YES/NO prepare*/abort*
&amp;lt;-------------------------------
commit*/abort* COMMIT/ROLLBACK
--------------------------------&amp;gt;
ACKNOWLEDGMENT commit*/abort*
&amp;lt;--------------------------------
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="percolator"&gt;Percolator&lt;/h3&gt;
&lt;p&gt;本身其实算一种经过优化的二阶段提交的实现，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对锁的使用进行优化，引入Primary-Secondary二级锁，去除了对&lt;strong&gt;Coordinator&lt;/strong&gt;的依赖。&lt;/li&gt;
&lt;li&gt;提供了完整的ACID事务语义实现，并且支持MVCC（依赖时间戳服务）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="percolator协议细节"&gt;Percolator协议细节&lt;/h2&gt;
&lt;p&gt;Percolator系统主要有三部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Client，发起事务的客户端，Client 是整个协议的控制中心，是两阶段提交的协调者（Coordinator）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TO，Time Observer，分配时间戳，提供全局唯一且递增的时间戳，实现MVCC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bigtable，提供单机单行事务，数据存储在Bigtable中，包含数据本身以及附带的一些属性。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;lock + write + data&lt;/code&gt;: for transaction，lock表示cell被事务持有，write表示数据的可见性&lt;/p&gt;
&lt;p&gt;&lt;code&gt;notify + ack&lt;/code&gt;: for watcher or notifier&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/noneback/images/picgo/20230927163910.png" alt="https://raw.githubusercontent.com/noneback/images/picgo/20230927163910.png" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从外部看，Percolator以SDK的提供给业务方使用。提供事务以及R/W。模型类似于 &lt;code&gt;Begin Txn → Sets of RW Operations → Commit or About or Rollback&lt;/code&gt;其中Bigtable最为持久化组件屏蔽了底层Tablet Server Data Sharding的细节，事务中的每一个写操作或者读后写（统称为Write）操作都视为分布式事务的参与者，而这些操作最后可能会分派到多个Tablet Server节点上。&lt;/p&gt;
&lt;h3 id="算法流程"&gt;算法流程&lt;/h3&gt;
&lt;p&gt;一个事务的所有 Write 在提交之前都会先缓存在 Client，然后在提交阶段一次性写入；Percolator 的事务提交是标准的两阶段提交，分为 Prewrite 和 Commit 。&lt;/p&gt;
&lt;h4 id="prewrite"&gt;Prewrite&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;从TO获取一个时间戳，作为事务的开始时间。&lt;/li&gt;
&lt;li&gt;给数据上锁，标记数据被当前事务占有。上锁失败则表示数据被其他事物占有，当前事物失败。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;上锁过程利用了Primary-Secondary机制，选择一个 Write 作为 primary，其它 Write 则是 secondary。Secondary的锁记录指向Primary。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://raw.githubusercontent.com/noneback/images/picgo/202309271613141.png" alt="https://raw.githubusercontent.com/noneback/images/picgo/202309271613141.png" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;显然，Prewrite阶段的数据对其他事务均不可见。&lt;/p&gt;
&lt;h4 id="commit"&gt;Commit&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;尝试对Prewrite中的数据进行Commit。Commit的时候先对Primary记录进行Commit，Primary记录的提交时间将作为整个事务的提交时间。首先对记录的锁记录进行检测，如果锁不存在，则表示Prewrite阶段的锁被其他事物清理，则事物执行失败。如果存在，则写记录中的write列，表示数据对系统可见。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;异步网络之中，单节点故障，网络延迟很常见。算法需要在发现这些故障的时候，清理掉这些锁记录，避免死锁。所以，在Commit阶段，如果锁不存在，则表示事务的参与者发生了问题当前事务需要被清理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;提交成功之后对锁记录进行清理。显然，锁清理也是可以异步的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些设计使得算法去除了中心化&lt;strong&gt;Coordinator&lt;/strong&gt;的&lt;strong&gt;&lt;strong&gt;依赖&lt;/strong&gt;&lt;/strong&gt;。因为过去需要依赖这个中心服务来维护事务各个参与者的信息。而在本算法中，利用Primary-Secondary二级锁以及Write列就可以实现。Write列表示数据对外的可见性以及数据版本链条。Lock列表示数据被事务持有。Primary-Secondary记录了参与者的逻辑从属关系。这样的设计使得Primary记录的提交变成了整个事务的提交点。一但Primary被提交，所有的Secondary记录可以通过检查对应Primary记录的Write列来进行异步提交。&lt;/p&gt;
&lt;h3 id="snapshot-isolation"&gt;Snapshot Isolation&lt;/h3&gt;
&lt;p&gt;两阶段提交解决的是事务的原子性。在此基础上，Percolator还提供了&lt;strong&gt;&lt;strong&gt;Snapshot Isolation&lt;/strong&gt;&lt;/strong&gt;的隔离性。简而言之，Snapshot Isolation要求提交的事务不能导致数据冲突，事务的读操作满足Snapshot Read。利用事务开始时间以及Primary记录的提交时间，可以维护一个事务之间的全序关系，这些问题自然就可以解决了。&lt;/p&gt;
&lt;h3 id="异步网络的死锁问题"&gt;异步网络的死锁问题&lt;/h3&gt;
&lt;p&gt;之前提到，异步网络之中，单节点故障，网络延迟很常见。算法需要在发现这些故障的时候，清理掉这些锁记录，避免死锁。故障检测的策略可以很简单，比如超时，故障会导致当前事务失败；节点故障又恢复正常，当时的事务已经失败，则此时需要对节点上相关锁记录进行清理。锁的清理可以异步化，比如在Prewrite上锁时，当发现记录Lock列非空，则去检测其Primary锁是否为空，Primary非空，则表示这个事务为完成，可以清理；为空则表示事务提交，则去找到事务提交时间，并把数据提交，再清理锁记录（RollForward）。&lt;/p&gt;
&lt;h3 id="通知机制"&gt;通知机制&lt;/h3&gt;
&lt;p&gt;通知机制对于异步系统的状态观测和联动很重要。但不是本文重点。&lt;/p&gt;
&lt;h2 id="percolator在tidb上的使用"&gt;Percolator在TiDB上的使用&lt;/h2&gt;
&lt;p&gt;基于我们上文的分析，我们可以得出这样的结论：Percolator是一种优化过的2PC分布式事务实现，实现的基础是支持单机事务的存储引擎。&lt;/p&gt;
&lt;p&gt;让我们来简单看看TiDB的的基于Percolator算法实现分布式事务。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://download.pingcap.com/images/docs-cn/tidb-architecture-v6.png" alt="https://download.pingcap.com/images/docs-cn/tidb-architecture-v6.png" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;TiDB和TiKV架构如上。TiDB关系表里的数据最终都被映射到了TiKV中的KV中。TiKV是一个基于Raft+RocksDB的分布式KV。RocksDB是一个支持事务操作的KV。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://download.pingcap.com/images/docs/tikv-rocksdb.png" alt="https://download.pingcap.com/images/docs/tikv-rocksdb.png" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;所以TiDB的事务的执行路径可以是这样：对关系表的事务操作转为对一组KV的事务操作，再基于Percolator去执行，以此实现关系表的事务操作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当然不可能提供和单机TP数据库一样的事务语义和性能保证。但Share Nothing架构也有自己的优点，所以这个也许并不重要。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://zhuanlan.zhihu.com/p/22594180"&gt;两阶段提交的工程实践&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://mysql.taobao.org/monthly/2018/11/02/"&gt;PolarDB 数据库内核月报&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://karellincoln.github.io/2018/04/05/percolator-translate/"&gt;percolator：在线增量处理系统 中文翻译&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.notion.so/percolator-879c8f72f80b4966a2ec1e41edc74560?pvs=21"&gt;percolator：在线增量处理系统 中文翻译 | 一只小小鸟&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zh.wikipedia.org/zh-hans/%E4%BA%8C%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4"&gt;二阶段提交 - 维基百科，自由的百科全书&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cn.pingcap.com/blog/percolator-and-txn"&gt;Percolator 和 TiDB 事务算法&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.oceanbase.wiki/concept/transaction-management/transactions/distributed-transactions/two-phase-commit"&gt;两阶段提交 | OceanBase 学习指南&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.pingcap.com/zh/tidb/stable/tidb-architecture"&gt;TiDB 整体架构&lt;/a&gt;&lt;/p&gt;</description></item><item><title>分布式事务</title><link>https://noneback.github.io/zh/blog/zh/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/</link><pubDate>Thu, 20 May 2021 23:55:11 +0800</pubDate><guid>https://noneback.github.io/zh/blog/zh/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/</guid><description>&lt;h1 id="事务与分布式事务"&gt;事务与分布式事务&lt;/h1&gt;
&lt;h2 id="事务"&gt;事务&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;事务&lt;/strong&gt;是数据库执行过程中的一个逻辑单位，由一个有限的数据库操作序列构成。数据库需要确保事务操作的&lt;strong&gt;原子性&lt;/strong&gt;：当事务成功时，意味着事务的所有操作全部都执行完成；但事务失败时，数据库将所有执行过的SQL操作回滚。&lt;/p&gt;
&lt;p&gt;数据库单机事务主要拥有四个特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原子性，事务作为一个整体被执行，包含在其中的对数据库的操作要么全部被执行，要么都不执行&lt;/li&gt;
&lt;li&gt;一致性，事务应确保数据库的状态从一个一致状态转变为另一个一致状态，一致状态的含义是数据库中的数据应满足完整性约束&lt;/li&gt;
&lt;li&gt;隔离性，多个事务并发执行时，一个事务的执行不应影响其他事务的执行&lt;/li&gt;
&lt;li&gt;持久性，已被提交的事务对数据库的修改应该永久保存在数据库中&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="分布式事务"&gt;分布式事务&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;分布式事务&lt;/strong&gt;是指事务的&lt;strong&gt;参与者&lt;/strong&gt;、&lt;strong&gt;支持事务的服务器&lt;/strong&gt;、&lt;strong&gt;资源服务器&lt;/strong&gt;以及&lt;strong&gt;事务管理器&lt;/strong&gt;分别位于&lt;strong&gt;不同&lt;/strong&gt;的分布式系统的不同节点之上。&lt;/p&gt;
&lt;p&gt;随着微服务架构的普及，大型业务域往往包含很多服务，一个业务流程需要由多个服务共同参与完成。在特定的业务场景中，需要保障多个服务之间的数据一致性。&lt;/p&gt;
&lt;p&gt;例如在大型电商系统中，下单接口通常会扣减库存、减去优惠、生成订单 id, 而订单服务与库存、优惠、订单 id 都是不同的服务，下单接口的成功与否，不仅取决于本地的 db 操作，而且依赖第三方系统的结果，这时候分布式事务就保证这些操作要么全部成功，要么全部失败。&lt;/p&gt;
&lt;p&gt;所以本质上来说，&lt;strong&gt;分布式事务就是为了保证不同数据库的数据一致性。&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id="使用场景"&gt;使用场景&lt;/h1&gt;
&lt;p&gt;在电商系统中，典型的使用场景有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;下单扣减库存&lt;/p&gt;
&lt;p&gt;下单时，需要的操作有生成订单记录，扣减商品库存等操作。两者同上是独立的微服务，所以严格来说，需要分布式事务保证下单操作的原子性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第三方支付&lt;/p&gt;
&lt;p&gt;微服务架构下，支付与订单都是独立的服务。订单的支付状态依赖于财经服务的通知。财经服务又依赖于第三方支付服务的通知。&lt;/p&gt;
&lt;p&gt;一个经典的场景如图：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://xiaomi-info.github.io/2020/01/02/distributed-transaction/notify-message.png" alt="https://xiaomi-info.github.io/2020/01/02/distributed-transaction/notify-message.png" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从图中可以看出有两次调用，第三方支付调用支付服务，以及支付服务调用订单服务，这两步调用都可能出现&lt;strong&gt;调用超时&lt;/strong&gt;的情况，此处如果没有分布式事务的保证，就会出现用户订单实际支付情况与最终用户看到的订单支付情况&lt;strong&gt;不一致&lt;/strong&gt;的情况。&lt;/p&gt;
&lt;h1 id="实现方案"&gt;实现方案&lt;/h1&gt;
&lt;h2 id="两阶段提交"&gt;两阶段提交&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://i.loli.net/2021/05/19/MfWzxseBFKaAnhk.png" alt="https://i.loli.net/2021/05/19/MfWzxseBFKaAnhk.png" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;一次事务的提交主要分为两个阶段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;准备阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TM开始事务，记录事务开始的日志，并向参与事务的RM询问是否能够执行提交操作，并等待RM响应&lt;/li&gt;
&lt;li&gt;RM执行本地事务，记录Redo/Undo日志，向TM返回执行结果，但不提交事务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提交/回滚阶段&lt;/p&gt;
&lt;p&gt;（ 1 ）如果所有参与的RM执行成功，进入&lt;strong&gt;提交阶段&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TM记录事务提交日志，并向所有RM发送提交事务指令&lt;/li&gt;
&lt;li&gt;RM收到指令后，提交本地事务，向TM返回执行结果&lt;/li&gt;
&lt;li&gt;TM记录事务结束&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;（ 2 ）如果准备或提交任一RM执行失败或者超时&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TM记录回滚记录，并向所有RM发送回滚指令&lt;/li&gt;
&lt;li&gt;RM回滚本地事务，向TM返回结果&lt;/li&gt;
&lt;li&gt;TM记录事务结束&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="特性"&gt;特性&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;- 原子性：支持
- 一致性：强一致
- 隔离性：支持
- 持久性：支持
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="弊端"&gt;弊端&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;- 同步阻塞：当参与事务者存在占用公共资源的情况，其中一个占用了资源，其他事务参与者就只能阻塞等待资源释放，处于阻塞状态。
- 单点故障：一旦事务管理器出现故障，整个系统不可用
- 数据不一致：如果事务管理器只发送了部分 commit 消息，此时网络发生异常，那么只有部分参与者接收到 commit 消息，也就是说只有部分参与者提交了事务，使得系统数据不一致。
- 不确定性：当事务管理器发送 commit 之后，并且此时只有一个参与者收到了 commit，那么当该参与者与事务管理器同时宕机之后，重新选举的事务管理器无法确定该条消息是否提交成功。
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="本地消息表"&gt;本地消息表&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;事务发起方维护一张**本地消息表**，业务表与本地消息表的操作处于同一个本地事务内，通过异步的**定时任务**扫描消息表并投递到下游。
广义的本地消息表方案中，下游通知方式并不局限于消息投递，也可以通过RPC调用等方式通知。
![https://i.loli.net/2021/05/19/tmNeiALsdof24PW.png](https://i.loli.net/2021/05/19/tmNeiALsdof24PW.png)
1. 事务发起者执行本地事务，同时操作业务表和本地消息表
2. 定时任务定时扫描待发送的本地消息(本地消息表中)，将其发送到消息队列
- 发送成功，则将本地消息标记为已发送
- 发送失败，则重试直至成功
3. 消息队列投递消息至下游
4. 下游事务参与者收到消息后，执行本地事务
- 本地事务执行失败，不返回ACK，消息队列重复投递消息
- 本地事务执行成功，则向消息队列返回ACK，全局事务结束
- 消息或ACK丢失，消息队列重复投递消息
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="异常场景"&gt;异常场景&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;- 消息发送丢失，通过定时任务重复发送解决
- 投递到下游的消息丢失，通过重复投递机制解决，需保障下游操作幂等
- 下游回复的ACK丢失，通过重复投递机制解决，需保障下游操作幂等
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="优点与问题"&gt;优点与问题&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;优点：
- 系统吞吐量高，通过消息中间件解耦，下游事务异步化
- 业务侵入度适中，需要实现本地消息表和定时任务
问题：
- 事务支持不完备，不接受下游分支事务的回滚，只能重试
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="特性-1"&gt;特性&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;- 原子性：支持
- 一致性：最终一致
- 隔离性：不支持（分支事务提交之后对其它事务可见）
- 持久性：支持
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="尽最大努力通知"&gt;尽最大努力通知&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;最大努力通知是最简单的一种柔性事务，适用于一些最终一致性时间敏感度低的业务，且被动方处理结果 不影响主动方的处理结果。
这个方案的大致意思就是：
1. 系统 A 本地事务执行完之后，发送个消息到 MQ；
2. 这里会有个专门消费 MQ 的服务，这个服务会消费 MQ 并调用系统 B 的接口；
3. 要是系统 B 执行成功就 ok 了；要是系统 B 执行失败了，那么最大努力通知服务就定时尝试重新调用系统 B, 反复 N 次，最后还是不行就放弃。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="优点与问题-1"&gt;优点与问题&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;优点：
- 实现简单
问题：
- 无补偿机制，不保证送达
- 幂等要求，需要提供接口保证一致性与原子性，系统无法保证
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="特性-2"&gt;特性&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;- 原子性：不支持(需要额外接口保证)
- 一致性：不支持(需要额外接口保证)
- 隔离性：不支持（分支事务提交之后对其它事务可见）
- 持久性：支持
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="经典场景"&gt;经典场景&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;支付回调：
支付服务收到第三方服务支付成功通知后，先更新自己库中订单支付状态，然后同步通知订单服务支付成功。如果此次同步通知失败，会通过异步脚步不断重试地调用订单服务的接口。
![https://xiaomi-info.github.io/2020/01/02/distributed-transaction/try-best-notify.jpg](https://xiaomi-info.github.io/2020/01/02/distributed-transaction/try-best-notify.jpg)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://xiaomi-info.github.io/2020/01/02/distributed-transaction/"&gt;分布式事务，这一篇就够了&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>