1. cap(一致性、可用性、分区容错性)理论

  1. (c) 一致性
    1. 强一致性,指的是 写操作完成后,任何的读操作都必须返回该值作为结果
      1. 也就是说,在一致性系统中,一旦客户端将值写入任何一台服务器并获得响应,那么之后client从其他任何服务器读取的都是刚写入的数据
      2. 一致性保证了不管向哪台服务器写入数据,其他的服务器能实时同步数据
  2. (a) 可用性
    1. 每次发送请求,总能保证收到响应数据
      1. 允许不是最新的数据
  3. (p) 分区容错性
    1. 什么是分区
      1. 在分布式系统中,不同的节点分布在不同的子网络中,由于一些特殊的原因,这些子节点之间出现了网络不通的状态,但他们的内部子网络是正常的。从而导致了整个系统的环境被切分成了若干个孤立的区域。这就是分区。
    2. 分区容错性
      1. 分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,也就是说,服务器A和B发送给对方的任何消息都是可以放弃的,也就是说A和B可能因为各种意外情况,导致无法成功进行同步,分布式系统要能容忍这种情况。除非整个网络环境都发生了故障

2. 为什么只能在A 和 C 之间取舍

  1. 分布式系统必然存在网络通行,放弃分区容错行,那么只能使用单机架构
  2. image.png | 组合 | 分析 | | —- | —- | | CA | 满足原子和可用,放弃分区和容错。其实就是放弃了分布式架构,使用单体架构解决问题 | | CP | 满足原子和分区容错。也就是说,要放弃可用性。当系统被分区,为了保证原子性,必须放弃可用性,让系统停用。 | | AP | 满足可用性和分区容错性,当出现分区,同时为了保证可用性,必须让节点对外继续服务,这样的话必然导致失去原子性。 |

3. cap之间的取舍

  1. 舍弃P(舍弃分区容错):单点的传统关系型数据库(mysql,oracle),如果使用集群的话,就必须考虑P
  2. 舍弃A(可用性):保证一致性—— 如 Reids\Zookeeper\MongoDB\HBase;
  3. 舍弃C(一致性):保证可用性—— 如CoachDB\DynamoDB

4. 强一致性和 弱一致性、最终一致性

  1. 强一致性
    1. 一个集群需要对外部提供强一致性,所以只要集群内部某一台服务器数据发生了改变,那么就需要等待集群内其他服务器的数据同步完成后,才能这个奶茶给你的对外提供服务
  2. 弱一致性
    1. 系统中某个数据被更新后,对该数据的读取操作可能是更改前的值,也可能是更改后的值。但即使过了“不一致时间窗口”这段时间后,后续对该数据但读取也不一定是最新值。
    2. 所以,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是若一致性
  3. 最终一致性:
    1. 是弱一致性的特殊形式。存储系统保证在没有更新的条件下,最终访问的都是最后更新的值。
    2. 不保证在任意时刻任意节点的同一份数据都是相同的,但是随着时间的迁移,不同节点的同一份数据在向趋同的方向变化。
    3. 简单的说,就是在一段时间后,节点间的数据会最终到达一致状态。

5.base理论

base 是对cap 一致性和可用性权衡对一个结果,核心思想就是 无法做到强一致性,但每个应用都可以更具自身但业务特点,采用适当但方式来使系统达到最终一致性。

  1. BA :
    1. 基本可用整个系统在某些不可抗力的情况下,仍然能够保证“可用性”,即一定时间仍然能够返回一个明确的结果。只不过“基本可用”和“高可用”的区别是
      1. “一定时间”可以适当延长,当举行大促时,响应时间可以适当延长
      2. 给部分用户返回一个降级页面,从而缓解服务器当压力。但要注意当是,返回降级页面仍然是返回明确当结果
  2. S:柔性状态:
    1. 是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统不同节点的数据副本之间进行数据同步的过程存在延时
  3. E: 最终一致性:
    1. 统一数据的不同副本的状态,可以不需要时时一致,但一定要保证经过一定时间后仍然是一致的、

6. 分布式事务协议

  1. 在分布式系统里,每个节点都知道自己操作的成功或者失败,但是不知道其他节点操作的成功或者失败。所以需要引入一个协调者来掌控所有参与者的操作结果,并指示他们是否把操作结果真正的提交或者回滚。
  2. image.png
  3. 二阶段提交协议:
    1. 常用的分布式事务的解决方案,将事务的提交分为两个阶段来进行处理。
      1. 准备阶段
        1. 协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待答复
        2. 各参与者执行事务操作,将undo和redo信息记入事务日志中(但不提交事务)
        3. 如操作执行成功,给协调者反馈 同意,否则反馈 终止
      2. 提交阶段(提交执行阶段)
        1. 协调者节点向所有参与者节点发出正式提交(commit) 的请求
        2. 参与者节点正式完成操作,并释放整个事务期间内占用的资源
        3. 参与者节点向协调者节点发送ack 完成消息
        4. 协调者节点收到所有参与者节点反馈的ack完成事务后,完成事务
        5. 如果任意节点在第一阶段返回的响应消息为终止,或者 协调者节点在第一阶段询问超时之前无法获取所有参与者节点的响应消息:
          1. 协调者节点向所有参与者发出回滚(rollback)请求
          2. 参与者节点利用阶段1 写入undo信息执行回滚,并释放在整个事务期间占用的资源
          3. 参与者节点向协调者节点发送ack回滚完成消息
          4. 协调者节点收到所有参与者节点反馈的ack回滚完成消息后,取消事务。
  4. image.png
  5. image.png
  6. 二阶段提交的一些问题:
    1. 性能问题:
      1. 执行过程中,所有参与节点都是事务阻塞型的。打给你参与者占有公共资源时,其他第三方访问公共资源不得不处于阻塞状态。
    2. 可靠性问题:
      1. 参与者发生故障,协调者需要给参与者额外指定超时机制,超时后整个事务失败。协调者发生故障,参与者会一直阻塞,需要额外的容错机制。
    3. 数据一致性问题:
      1. 协调者在发出commit 消息后宕机,而唯一接受到这条消息的参与者同时宕机了,那么即使通过选举产生了新的协调者,事务状态也是不确定的。

7. 三阶段提交

  1. 三阶段提交协议是二阶段条协议的改进版本,三阶段提交有两个改动点
    1. 在协调者和参与者中都引入了超时机制
    2. 在第一阶段和第二阶段中插入一个准备阶段。保证了最后提交阶段之前各参与节点的状态是一致的

image.png

班长要组织全班同学聚餐,由于大家毕业多年,所以要逐个打电话敲定时间,时间初定10.1日。然后开始逐个打电话。

班长:小A,我们想定在10.1号聚会,你有时间嘛?有时间你就说YES,没有你就说NO,然后我还会再去问其他人,具体时间地点我会再通知你,这段时间你可先去干你自己的事儿,不用一直等着我。(协调者询问事务是否可以执行,这一步不会锁定资源)

小A:好的,我有时间。(参与者反馈)

班长:小B,我们想定在10.1号聚会……不用一直等我。

班长收集完大家的时间情况了,一看大家都有时间,那么就再次通知大家。(协调者接收到所有YES指令)

班长:小A,我们确定了10.1号聚餐,你要把这一天的时间空出来,这一天你不能再安排其他的事儿了。然后我会逐个通知其他同学,通知完之后我会再来和你确认一下,还有啊,如果我没有特意给你打电话,你就10.1号那天来聚餐就行了。对了,你确定能来是吧?(协调者发送事务执行指令,这一步锁住资源。如果由于网络原因参与者在后面没有收到协调者的命令,他也会执行commit)

小A顺手在自己的日历上把10.1号这一天圈上了,然后跟班长说,我可以去。(参与者执行事务操作,反馈状态)

班长:小B,我们觉得了10.1号聚餐……你就10.1号那天来聚餐就行了。

班长通知完一圈之后。所有同学都跟他说:”我已经把10.1号这天空出来了”。于是,他在10.1号这一天又挨个打了一遍电话告诉他们:嘿,现在你们可以出门拉。。。。(协调者收到所有参与者的ACK响应,通知所有参与者执行事务的commit)

小A,小B:我已经出门拉。(执行commit操作,反馈状态)

阶段1 canCommit: 协调者向参与者发送canCommit 请求,参与者可以提交就返回yes响应,否则就返回no响应
阶段2 preCommit:

  1. 假设参与者均反馈yes,协调者执行事务;
  2. 参与者接收到preCommit请求,将undo 和 redo 信息记录到事务日志中,但是不提交事务;
  3. 参与者执行了事务操作后,返回ack响应,等待最终指令
  4. image.png

阶段3 doCommit:

  1. 在该阶段真正执行事务的提交
  2. 进入阶段3 之后,无论协调者是否出现问题,都会导致参与者无法接受到协调者发出的doCommit请求或者abort请求。此时,参与者都会在等待超时之后,继续执行事务提交。
  3. 流程如下:
    1. 协调者收到参与者发送的ack响应之后,将预提交状态进入到提交状态,并向所有参与者发送doCommit 请求
    2. 参与者收到doCommit 请求后,执行事务并提交,在完成事务提交之后释放资源
    3. 任何一个参与者返回no 或者等待超时协调者无法收到参与者的反馈,即中断事务
    4. 中断事务:
      1. 协调者向所有的参与者发送abort请求
      2. 参与者收到abort请求折后,利用在二阶段记录的undo信息执行事务回滚的操作,并在完成回滚之后释放掉所有的事务资源
      3. 参与者完成事务回滚之后,向协调者反馈ack消息
      4. 协调者接收到参与者反馈的ack消息之后,执行事务中断

image.png
三阶段提交总结:
优点:

  1. 相比二阶段三阶段提交降低了阻塞范围,等待超时或者参与者中断事务

8. TCC 方案(二阶段提交):

  1. tcc方案是应用层侵入业务的两阶段提交,是目前最火的一种柔性事务方案。核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作
  2. 第一阶段
    1. Try(尝试):主要是对业务系统做检测以及资源预留(加锁,锁住资源)
  3. 第二阶段
    1. 本阶段更具第一阶段对结果,决定是执行confirm还是cancel
    2. confirm(确认):执行真正对业务(执行业务,释放锁)
    3. cancel(取消):是预留资源对取消(出问题,释放锁)
    4. image.png

9.Seata 名次解释

  1. TC
    1. 事务协调者
  2. TM
    1. 事务管理器
    2. 开始全剧事务、提交或回滚全局事务
  3. RM
    1. 与TC交谈、报告事务状态,并驱动事务分支提交或者回滚
    2. 其实就是 一个 Service

image.png