数据库事务、分布式一致性和分布式事务

文章目录

    • 什么是事务
    • 事务(ACID)的特性
    • 对事务一致性的理解
    • 分布式一致性
      • CAP
      • BASE
    • 分布式事务
      • 本地事务
      • 柔性事务和刚性事务
    • 分布式一致性和分布式事务的理解
    • 一致性协议
      • 向量时钟
      • NWR协议
      • ZAB协议
      • Gossip
      • raft协议和Paxos协议
    • 分布式事务的解决方案:
      • 两阶段提交协议 (2PC)和三阶段提交协议 (3PC)
        • 2pc(阻塞原子提交协议):
        • 3pc(非阻塞原子提交协议)
      • XA(2PC)
      • TCC事务补偿型方案
      • Saga 事务
      • 最大努力通知型
      • 异步确保最终一致性
        • 本地消息表
        • MQ 事务消息

什么是事务

事务是由一系列对系统中的数据进行访问和更新的操作所组成的一个程序执行逻辑单元。狭义上的事务指的就是数据库的事务。

事务(ACID)的特性

  1. 一致性(Consistency):事务的操作需要从一个一致性状态到另一个一致性状态。
  2. 原子性(Automicity):指事务是一个原子操作序列单元。一个事务下的操作要么全部执行成功,要么全部执行不成功。
  3. 持久性(Durability):指事务一旦提交,对数据库中的数据的变更操作就是永久的。
  4. 隔离性(Isolation):指不同的事务操作互不影响。

对事务一致性的理解

在事务处理的ACID属性中,一致性是最基本的属性,其它的三个特性都为了达到一致性而存在的。即一致性是事务的最终目的,原子性、持久性、隔离性是为了实现一致性所使用的方法。

原子性保证在同一个事务内部的一组操作必须全部执行成功(或者全部失败),如果一部分操作成功,一部分操作失败,结果肯定不是一致的状态。原子性一般是通过undo log实现。将对数据库的更新操作记录在undo log中,如果事务中的一部分操作已经成功,但之后的操作因错误不能执行,可以通过回溯undo log将已经成功执行的操作撤销,从而达到全部失败的的目的。

但是原子性是无法完全保证一致性的。在多个事务并发进行的情况下,即使保证了每一个事务的原子性,仍然可能导致数据不一致的结果,即脏读、不可重复读、幻读等。为了保证并发情况下的一致性,引入了隔离性。隔离性级别从低到高有读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。MYSQL隔离性一般使用锁和MVCC实现,具体原理可查看https://blog.csdn.net/qq_41775852/article/details/104853909

有了原子性和隔离性之后,还是不能保证完全的一致性。数据库为了提高写性能,通常会将数据先写入内存中,然后再刷写到磁盘中。如果数据还未刷写到磁盘中时,程序异常崩溃,会导致数据丢失。所以又引入持久性,其一般使用redo log实现。同样,将所有对数据的更新操作都写入 redo log。当数据库系统崩溃后重启,此时数据库处于不一致的状态,必须先执行一个crash recovery的过程:读取redo log进行REDO操作,重演将所有已经执行成功但尚未写入到磁盘的操作,保证持久性。

MYSQL原子性和持久性具体原理可查看:https://www.jianshu.com/p/9b83ea78b380

综上,我们知道,为了实现数据库数据的一致性,必须保证原子性、隔离性和持久性。

分布式一致性

分布式一致性是指数据在多个副本之间是否保持一致性的状态
详细解释:https://blog.csdn.net/qq_41775852/article/details/105002061

对于分布式系统,会出现系统的可用性与严格一致性(这里指分布式一致性)的冲突。因为当要求系统严格分布式一致性时,会降低系统的可用性。对于分布式系统,必须找到兼容分布式一致性和可用性的方法,所以出现了CAP和BASE理论。

CAP

CAP指的是Consistency(一致性)、Availability(可用性)和Partition tolerance(分区容错性)。

  • 一致性:指数据在多个副本之间能够保持一致的特性。
    有以下三种一致性级别:
    • 强一致性:要求对系统数据的修改可以立刻读取,用户体验性最好。一般使用数据同步复制。
    • 弱一致性:不保证什么时候能达到一致性,但是尽可能保证在某个时间级别后,数据达到一致性。一般使用数据异步复制。
    • 最终一致性:弱一致性的一个特例,系统会保证经过一定时间内,最终一定能够达到一个数据一致的状态。保证数据最终会复制到所有副本。
  • 可用性:指系统提供的服务需要一直处于可用状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。
  • 分区容错性:分布式系统在遇到任何网络分区故障时,都需要保证对外提供满足一致性和可用性的服务,除非整个网络都发生了故障。
    数据库事务、分布式一致性和分布式事务_第1张图片
    一个分布式系统是无法同时满足CAP三个特性的,最多只能同时实现两个特性。而在分布式系统中,网络分区故障是不可避免的,所以分区容错性是必须要保证的,只能根据业务特点,在一致性和可用性之间寻找平衡。

BASE

BASE理论是对CAP理论中一致性和可用性权衡的结果,核心思想是即使无法做到强一致性(StrongConsistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)

  • (Basically Available)基本可用
    在分布式系统出现故障的时候,允许损失部分可用性,即保证核心可用。典型的基本可用的例子:
    数据库事务、分布式一致性和分布式事务_第2张图片
  • (Soft State)软状态
    接受一段时间的状态不同步,及中间状态,而改中间状态不影响系统整体可用性。这里的中间状态就是CAP理论中的数据不一致性。
  • (Eventually Consistent)最终一致性
    上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值。

BASE理论面对的是大型的高可用可扩展的分布式系统,其通过牺牲强一致性来获得可用性,允许数据在一段时间内是不一致的,但是最终会达到一致性的状态。

分布式事务

分布式事务是指事务的参与者、支持事务的服务器,资源管理器以及事务管理器分别位于分布式系统的不同节点上。一个分布式事务会涉及多个数据源或是业务系统的操作。

一个分布式事务可以看作是由多个分布式操作序列组成的(例如转账业务涉及两个独立银行服务,一个取款,一个存款),通常可以把这一系列分布式操作序列称为子事务(类似下文的本地事务),每个子事务都能在本地保证自己的ACID。但是由于各个子事务的执行是分布式的,所以要实现刚性的分布式事务,必须保证所有子事务的原子性,即同时成功或者同时失败。但是严格保证子事务的原子性会影响分布式事务的性能,所以大多采用柔性事务。

本地事务

在计算机系统中,更多的是通过关系型数据库来控制事务,这是利用数据库本身的事务特性来实现的,因此叫数据库事务,由于应用主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的事务又被称为本地事务。

柔性事务和刚性事务

刚性事务是指强一致性事务,严格遵循ACID, 本地事务是刚性事务。
柔性事务是指遵循BASE理论的事务, 通常用在分布式环境中。

分布式一致性和分布式事务的理解

以我的理解,分布式一致性和分布式事务其实是两回事。分布式一致性是表示在分布式系统中多个数据副本的一致性性状态。分布式事务表示的是一系列发生在分布式系统中不同节点的操作是否能遵循ACID。

但是经常会发现分布式一致性和分布式事务混为一谈,交叉不清,给我造成了很大困惑。我觉得这是对分布式一致性的认识的不同造成的。

上文所说的分布式一致性是分布式系统上多个节点上数据副本的一致性。但是也可以将其理解为分布式系统上多个节点上的数据的一致性,即分布式事务一致性(自己的理解,因为分布式事务的目的就是保证分布式系统上的数据保持一致的状态)。不同之处在于后者强调的是在不同节点上的数据保持一致(比如转账时,取款的银行扣钱,存款的银行加钱),但是并不要求这多个数据为同一个数据的副本。以此看来,分布式事务一致性其实是包括分布式一致性的。

由于分布式一致性保持多个副本数据一致和分布式事务保持多个数据一致是有很多共性之处的,所以针对于分布式一致性的理论,如CAP、BASE、一致性协议,都可以应用与分布式事务之上。

一致性状态也可以应用于分布式事务,强一致性表示事务提交后,分布式系统的多个数据必须全部保持一致。最终一致性表示,事务提交后,多个数据可以有不一致的状态,但是最终会达到一致。

对于分布式事务,CAP表示保持分布式系统上多个数据强一致性和系统可用性会造成冲突。所以经常采用遵循BASE原理的分布式事务,即最终一致性。

一些一致性协议也可以应用于分布式事务的实现中,比如2pc、3pc、等。

一致性协议

在一个分布式系统的设计过程中,往往会在系统的可用性和分布式一致性之间的进行反复地权衡,于是就产生了一系列的一致性协议。

向量时钟

逻辑时钟和向量时钟

NWR协议

NWR是一种在分布式存储系统中用于控制一致性级别的一种策略。在Amazon的Dynamo云存储系统中,就应用NWR来控制一致性。

  • N:在分布式存储系统中,有多少份备份数据
  • W:代表一次成功的更新操作要求至少有w份数据写入成功
  • R:代表一次成功的读数据操作要求至少有R份数据成功读取 N

NWR值的不同组合会产生不同的一致性效果。

  • 当W+R>N的时候,整个系统对于客户端来讲能保证强一致性。如果R+W>N,则读取操作和写入操作成功的数据一定会有交集,这样就可以保证一定能够读取到最新版本的更新数据,数据的强一致性得到了保证。
  • 如果R+W<=N,则无法保证数据的强一致性,即为弱一致性。因为成功写和成功读集合可能不存在交集,这样读操作无法读取到最新的更新数值,也就无法保证数据的强一致性。

在具体实现系统时,仅仅依靠NWR协议还不能完成一致性保证,因为在上述过程中,当读取到多个备份数据时,需要判断哪些数据是最新的,如何判断数据的新旧?这需要向量时钟来配合,所以对于Dynamo来说,是通过NWR协议结合向量时钟来共同完成一致性保证的。

ZAB协议

ZAB协议中的原子广播阶段使用了二阶段提交协议,是为了保证数据写操作在多个节点上面的原子性。原子广播和崩溃选举后的数据同步过程保证了zookeeper分布式数据一致性。
https://blog.csdn.net/qq_41775852/article/details/104947943

Gossip

Gossip协议如其名,流行病协议,一个节点有状态需要更新到网络的其它节点的时候,它会随机的选择周围的几个节点散播消息,收到消息的节点会重复这个过程,直到网络中所有的节点都收到了消息。这个过程需要一定的时间,消息之间的传递具有一定的延迟性。但是理论上所有的节点都会收到所有的消息,因此它是一个最终一致性消息。ElasticSearch在寻找Node时候使用了类Gossip的协议。

raft协议和Paxos协议

这两个协议是一致性协议,也是分布式共识算法。因为这两者解决的是对某个提案(proposal)大家达成一致意见的过程,其不仅可用于解决分布式一致性,也可以用于解决选主等需要所有节点达到共识的问题,实际上zookeeper的zab协议就是简化的paxos协议,用于解决崩溃选举。

分布式事务的解决方案:

两阶段提交协议 (2PC)和三阶段提交协议 (3PC)

2pc和3pc都可以用来在分布式事务中保证原子性。但是他们都有缺陷:

2pc(阻塞原子提交协议):

如果参与者之一或网络发生故障时会发生什么情况:如果任何一个准备请求失败或者超时,协调者就会中止事务。如果任何提交或中止请求失败,协调者将无条件重试。但是如果协调者崩溃,会发生什么情况就不太清楚了。

如果协调者在发送准备请求之前失败,参与者可以安全地中止事务。但是,一旦参与者收到了准备请求并投了“是”,就不能再单方面放弃 —— 必须等待协调者回答事务是否已经提交或中止。如果此时协调者崩溃或网络出现故障,参与者什么也做不了只能等待。参与者的这种事务状态称为存疑(in doubt)的或不确定(uncertain)的。

没有协调者的消息,参与者无法知道是提交还是放弃。原则上参与者可以相互沟通,找出每个参与者是如何投票的,并达成一致,但这不是2PC协议的一部分。

可以完成2PC的唯一方法是等待协调者恢复。这就是为什么协调者必须在向参与者发送提交或中止请求之前,将其提交或中止决定写入磁盘上的事务日志:协调者恢复后,通过读取其事务日志来确定所有存疑事务的状态。任何在协调者日志中没有提交记录的事务都会中止。因此,2PC的提交点归结为协调者上的常规单节点原子提交。

所以2pc最大的问题是阻塞问题:协调者故障,所有参与者必须阻塞等待协调者恢复。

3pc(非阻塞原子提交协议)

3pc将提交分成三阶段,第二阶段和第三阶段引入了参与者超时机制处理机制,其中第三阶段参与者不需要阻塞直到与协调者恢复,超时自行提交事务,但是这可能会导致数据不一致。因为并不能确定协调者是真的故障了,还是只是因为网络原因与参与者无法通信。可能出现,协调者决定abort事务,但是因为网络原因,没有成功发送到某一参与者,超时后此参与者提交事务,则与其他参与者处于数据不一致的状态。

参考博客:https://blog.51cto.com/11821908/2058651

XA(2PC)

X/Open DTP(X/Open Distributed Transaction Processing Reference Model) 是X/Open 这个组织定义的一套分布式事务的标准,也就是了定义了规范和API接口,由各个厂商进行具体的实现。 X/Open DTP 定义了三个组件: AP,TM,RM。
数据库事务、分布式一致性和分布式事务_第3张图片

  • AP(Application Program):也就是应用程序,可以理解为使用DTP的程序
  • RM(Resource Manager):资源管理器,这里可以理解为一个DBMS系统,或者消息服务器管理系统,应用程序通过资源管理器对资源进行控制。资源必须实现XA定义的接口
  • TM(Transaction Manager):事务管理器,负责协调和管理事务,提供给AP应用程序编程接口以及管理资源管理器

其中在DTP定义了以下几个概念:

  • 全局事务:对于一次性操作多个资源管理器的事务,就是全局事务
  • 分支事务:在全局事务中,某一个资源管理器有自己独立的任务,这些任务的集合作为这个资源管理器的分支事务
  • 控制线程:用来表示一个工作线程,主要是关联AP,TM,RM三者的一个线程,也就是事务上下文环境。简单的说,就是需要标识一个全局事务以及分支事务的关系

如果一个事务管理器管理着多个资源管理器,DTP是通过两阶段提交协议来控制全局事务和分支事务。

  • 第一阶段:准备阶段 事务管理器通知资源管理器准备分支事务,资源管理器告之事务管理器准备结果
  • 第二阶段:提交阶段 事务管理器通知资源管理器提交分支事务,资源管理器告之事务管理器结果

XA的ACID特性:

  • 原子性:XA议使用2PC原子提交协议来保证分布式事务原子性
  • 隔离性:XA要求每个RMs实现本地的事务隔离,子事务的隔离来保证整个事务的隔离。
  • 持久性:同样每个RMs实现本地的事务持久,来保证整个事务持久。
  • 一致性:通过原子性、隔离性、持久性以及自身一致性的实现来保证“数据库从一个一致状态转变为另一个一致状态”;

特点:

XA的优点:强一致性

XA的缺点与2pc协议的缺点类似,主要为同步阻塞、单点问题、数据不一致、容错性不好

TCC事务补偿型方案

TCC(Try-Confirm-Cancel)分布式事务模型相对于 XA 等传统模型,其特征在于它不依赖资源管理器(RM)对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。

数据库事务、分布式一致性和分布式事务_第4张图片

一个完整的TCC业务由一个主业务服务和若干个从业务服务组成,主业务服务发起并完成整个业务活动,TCC模式要求从服务提供三个接口:Try、Confirm、Cancel。

  1. Try:完成所有业务检查,预留必须业务资源。
  2. Confirm:真正执行业务,不作任何业务检查;只使用Try阶段预留的业务资源;Confirm操作满足幂等性。
  3. Cancel:释放Try阶段预留的业务资源;Cancel操作满足幂等性。

整个TCC业务分成两个阶段完成:

  1. 第一阶段:主业务服务分别调用所有从业务的try操作,并在活动管理器中登记所有从业务服务。当所有从业务服务的try操作都调用成功或者某个从业务服务的try操作失败,进入第二阶段。

  2. 第二阶段:活动管理器根据第一阶段的执行结果来执行confirm或cancel操作。如果第一阶段所有try操作都成功,则活动管理器调用所有从业务活动的confirm操作。如果有try操作失败,则调用所有从业务服务的cancel操作,回滚try操作。

  • 如果confirm或者cancel失败,则不断进行重试直至成功,所以confirm和cancel需要满足幂等性。

  • 如果confirm阶段如果有一个参与者失败了,该如何处理?其实上面操作都是xts-client做的,还有一个xts-server专门做事务补偿的。(蚂蚁金服基于TCC实现了XTS,XTS的解决方案)。

特点:

TCC是对二阶段的一个改进,try阶段通过预留资源(比如余额1000,预留资源100块,其余900可正常使用)的方式避免了同步阻塞资源的情况,但是TCC编程需要业务自己实现try,confirm,cancle方法,对业务入侵太大,实现起来也比较复杂。

TCC是应用层的2PC, 具有最终一致性。之前一直不理解为什么是最终一致性而不是强一致性。当执行try操作之后,try会预留部分资源,比如余额1000,预留资源100块,所以当前余额900,则当读取余额时会返回900块,但这并不是真实一致的数据,因为有可能其他节点try失败,所有节点回滚try操作,余额又变成1000。所以TCC只能保证数据的最终一致性。

TCC位于业务服务层,不在资源层,不与具体的服务框架耦合。

优点:

Try操作可以灵活选择业务资源的锁定粒度,不会造成同步阻塞。

最终一致性,严格保证分布式事务要么全部成功,要么全部自动回滚。

缺点:

Canfirm和Cancel的幂等性很难保证。、

每个服务都要实现TCC接口, 较为复杂。

与业务层耦合性高,难以扩展。

适用:

  • 严格一致性

  • 执行时间短

  • 实时性要求高

    举例: 红包, 收付款, 实时汇款业务.

Saga 事务

Saga 是 30 年前一篇数据库伦理提到的一个概念。其核心思想是将长事务拆分为多个本地短事务,由 Saga 事务协调器协调,如果正常结束那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作。

**Saga 的组成:**每个 Saga 由一系列 sub-transaction Ti 组成,每个 Ti 都有对应的补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果。这里的每个 T,都是一个本地事务。

可以看到,和 TCC 相比,Saga 没有“预留 try”动作,它的 Ti 就是直接提交到库。

Saga 的执行顺序有两种:

  • T1,T2,T3,…,Tn。

  • T1,T2,…,Tj,Cj,…,C2,C1,其中 0 < j < n 。

Saga 定义了两种恢复策略:

**向后恢复,**即上面提到的第二种执行顺序,其中 j 是发生错误的 sub-transaction,这种做法的效果是撤销掉之前所有成功的 sub-transation,使得整个 Saga 的执行结果撤销。

**向前恢复,**适用于必须要成功的场景,执行顺序是类似于这样的:T1,T2,…,Tj(失败),Tj(重试),…,Tn,其中 j 是发生错误的 sub-transaction。该情况下不需要 Ci。

**在 Saga 模式中不能保证隔离性,因为没有锁住资源,其他事务依然可以覆盖或者影响当前事务。**可以从业务层面入手加入一 Session 以及锁的机制来保证能够串行化操作资源。

特点:

数据一致性有问题,因为Saga不保证隔离性,必须在业务层自己保证隔离性

最大努力通知型

这是分布式事务中要求最低的一种, 通过消息中间件实现, 在消息由MQ Server投递到消费者之后, 允许在达到最大重试次数之后直接结束事务, 无需人工介入确保成功.

最大努力通知方案的实现:

  1. 业务活动的主动方,在完成业务处理之后,向业务活动的被动方发送消息,允许消息丢失(丢失之后,被动方可以主动查询消息)。

  2. 会有个专门消费 MQ 的最大努力通知服务(有多种实现方法,一种直接使用MQ进行最大努力通知,另一种是独立的通知程序消费MQ,再进行最大努力通知服务,还可以主动方直接向被动方发消息),这个服务会消费 MQ 然后写入数据库中记录下来,或者是放入个内存队列也可以。然后发送通知消息给被动方。

  3. 业务活动的被动方如果正常接收了数据,就正常返回响应,并结束事务。否则,最大努力通知服务会按规则重复通知,直到通知N次后不再通知。

  4. 由于通知次数是有限的,不可能无限制的通知。所以主动方提供校对查询接口给被动方按需校对查询,用于恢复丢失的业务消息。

  5. 如果被动方没有正常接收消息,根据定时策略,向业务活动主动方查询,恢复丢失的业务消息,达到最终一致性。

数据库事务、分布式一致性和分布式事务_第5张图片

特点:

  • 可查询操作、幂等操作
  • 适用于对业务最终一致性的时间敏感度低的系统;
  • 适合跨企业的系统间的操作,或者企业内部比较独立的系统间的操作,比如银行通知、商户通知等.
  • 高并发, 低耦合
  • 不支持回滚;

数据库事务、分布式一致性和分布式事务_第6张图片

异步确保最终一致性

eBay 的架构师Dan Pritchett,曾在一篇解释BASE 原理的论文《Base:An Acid Alternative》中提到一个eBay 分布式系统一致性问题的解决方案。它的核心思想是将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。

本地消息表

本地消息表借助关系型数据库中的表实现。

数据库事务、分布式一致性和分布式事务_第7张图片

主要过程为:

  1. A 系统在自己本地一个事务里操作同时,插入一条数据到消息表(保证本地操作和消息插入同时成功或失败);
  2. 接着 A 系统将这个消息发送到 MQ 中去;
  3. B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息
  4. B 系统执行成功之后,就会更新自己本地消息表的状态以及 A 系统消息表的状态
  5. 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到 MQ 中去,让 B 再次处理;

特点:

这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 成功,但是其严重依赖于数据库的消息表来管理事务,会影响并发性。

MQ 事务消息

有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交。所以可以不再使用数据库事务实现本地操作和消息发送的原子性。

主要过程:

  1. 事务发起方首先发送prepare消息到MQ。
  2. 在发送prepare消息成功后执行本地事务。
  3. 根据本地事务执行结果返回commit或者是rollback。
  4. 如果消息是rollback,MQ将删除该prepare消息不进行下发,如果是commit消息,MQ将会把这个消息发送给consumer端。
  5. 如果执行本地事务过程中,执行端挂掉,或者超时,MQ将会不停的询问其同组的其它producer来获取状态。
  6. Consumer端的消费成功机制有MQ保证(MQ不断重试)。

数据库事务、分布式一致性和分布式事务_第8张图片

特点:

实现了最终一致性,不需要依赖本地数据库事务。这种方式适合的业务场景广泛,而且比较可靠。不过这种方式技术实现的难度比较大。目前主流的开源MQ(ActiveMQ、RabbitMQ、Kafka)均未实现对事务消息的支持,所以需二次开发。

参考博客:

https://blog.csdn.net/qq_36142146/article/details/85247960

https://www.cnblogs.com/jajian/p/10014145.html

https://www.cnblogs.com/mayundalao/p/11798502.html

https://www.cnblogs.com/bluemiaomiao/p/11216380.html

https://blog.csdn.net/weixin_34211761/article/details/91441749

https://www.liangzl.com/get-article-detail-97306.html

https://blog.csdn.net/oldshaui/article/details/88743085

https://blog.csdn.net/congyihao/article/details/70195154?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://www.jianshu.com/p/f94c6f2a8e0f

https://www.jianshu.com/p/ac101d023d6b
https://www.cnblogs.com/luxiaoxun/p/8832915.html

你可能感兴趣的:(分布式系统)