分布式技术笔记1

127 阅读30分钟

my分布式

为什么需要分布式技术?

  • 性能需求,优化架构

    早期:

    后来:

    此图简单刻画了现代应用服务器的基本架构:

    1. 用户请求到达负载均衡服务器(关联唯一域名),负载均衡服务器路由到集群中不同的应用服务器,服务器中对数据库的调用分为读写,分别访问主从,负载均衡器中让用户对静态资源的访问到达CDN(分布式缓存服务器),从而减轻应用服务器的压力。

    2. 分布式系统的基本架构:

      将一个硬件 / 软件拆分,分不到不同的计算机上

      这些计算机彼此之间经过通信协调工作

      一群相互独立的计算机集合共同对外提供服务

基本概念:

  1. 事务:

    由不同小活动组成的大活动,要么全部成功,要么全部失败(ACID)

    • 本地事务:

      通过关系型数据库来控制事务(将事务的管理交给数据库解决)

    • 分布式事务

  2. 分布式和集群

    • 分布式:

      指在多台不同的服务器中部署不同的服务模块,通过远程调用协同工作。

      (似乎是将微服务的各个服务部署到不同服务器上)

    • 集群:

      指在多台不同的服务器中部署相同的应用或服务模块,通过负载均衡对外提供服务。

  3. 分布式事务

    在分布式系统环境下,由不同的服务之间通过网络远程协作完成事务,称之为分布式事务。

    只要和通信相关的业务,不可避免都要考虑许多特殊情况

    无法仅用本地数据库来控制的事务

    业务例子:

    1. 客户下单生成订单减库存事务 in gulimall

      image20230817155541520

      1. 服务1:order生成订单
      2. 服务2:ware减少库存
      3. 服务3:member更改个人信息
      4. 服务4:......

分布式事务产生的场景

  1. 典型场景:微服务架构

    微服务中,分布式事务是由于对各个微服务的调用跨越了JVM进程(由网络)

  2. 单体系统访问多个数据库实例

    当一个事务的操作要跨越多个数据库实例时,产生分布式事务

    是由于多个数据库往往由集群构成,而不会全部安置在本地服务器上,于是不可避免要通过网络

  3. 多个服务访问同一个数据库实例

分布式事务基础理论

  1. CAP理论 —— 分布式系统实现目标

    Consistency:一致性

    Availablity:可用性

    Partition tolerance:分区容忍性

一致性:

  • 写操作后的读操作一定可以读到最新的数据状态,尤其当数据分布在多个节点上时,从任意节点读取到的数据都是最新状态

    例:在主从数据库中

    存在的问题:

    写到主数据库中还没来得及数据同步,就查询从库的数据

    实现一致性:

    1. 写入主数据库后将数据同步,同步期间将数据库锁定,同步完成再释放锁。未释放锁时,禁止外界读取旧数据。
  • 分布式系统实现一致性的特点:

    1. 同步过程导致的一定延迟
    2. 同步过程导致的资源锁定
    3. 对正在同步的资源的请求会返回错误信息,但不会返回旧数据

可用性:

  • 指任何事务操作都可以得到响应的结果,且不会出现响应超时或者响应错误。

    系统稳定性指标就是描述可用性:做到99.9%,99.99%可用,(SLA - 服务水平协议)

    存在的问题:

    如果按照一致性进行,访问正在同步的数据会阻塞/返回错误信息

    实现可用性:

    1. 写入主数据库后将数据同步,但为了保证数据库可用性,不讲数据库的资源进行锁定。——即使数据还没有同步,从数据库也要返回查询的目的数据,即使是旧数据/默认值,但不能返回错误或超时。
  • 分布式系统可用性的特点:

    所有请求都有相应,且不会出现响应超时或响应错误

分区容忍性

  • 分区是指在不同子网下部署的各个节点(服务器),分区容忍性指由于网络问题而导致节点之间通信失败后,此时节点任然可以对外提供服务。

    具体目标:

    1. 主从数据库之间网络通信失败,不影响用户读写操作
    2. 其中一个节点挂掉,不影响其他节点对外的服务

    实现分区容忍性:

    1. 尽量使用异步取代同步(例如异步方式同步数据,实现松耦合)
    2. 添加从数据库节点(多服务器集群,防止一台机器挂掉)
  1. CAP组合方式

    在所有分布式事务场景中,不会同时具备CAP三个特性——在具备了P的前提下C和A不能共存。

    1. AP:

      追求分区容忍性和可用性,放弃一致性

      对查询最新版本要求不高,但对时刻可查询要求很高

      场景举例:订单退款 —— 不关心什么时候到账,任意时刻的查询允许查到旧数据,但要求查询不应该有高延迟

      Eureka基于AP架构

    2. CP:

      追求分区容忍性和一致性,放弃可用性

      场景举例:银行转账 —— 不关心转账后查询有点延迟,但要求不能查到旧数据。

      Zookeeper就采用CP一致性

    3. CA:

      放弃分区容忍性 —— 即不进行分区,不做分布式系统。

      按照本地一台服务器的模式生产,即可满足分布式层面的一致性和可用性(单服务器层面的ACID仍需考虑)。

  2. BASE理论

    1. Basically Available(基本可用)

      强调纷纷不是系统在出现不可预知的故障时,允许损失部分可用性

      例如:双十一秒杀活动中,如果抢的人数太多,超过系统QPS峰值,则手动限流 / 降级来降低可用性,用来保护系统稳定性

  3. Soft state(软状态)

    相对而言:ACID的原子性是强制一致性,是一种硬状态

    而软状态允许系统中的数据存在中间状态,并认为该状态并不影响系统的整体可用性

    即:允许系统在多个不同节点的数据副本中存在数据延时

  4. Eventually consistent(最终一致性)

    数据不可能一直是软状态,必须在一个时间期限后达到一致性

    在系统设计中,最终一致性的实现时间取决于:网络延迟、系统负载、不同的存储选型、不同的数据复制方案等因素

    BASE理论是,通过牺牲强一致性来获取可用性。

基本可用:

当出现故障时,允许部分功能不可用,但要保证核心功能可用(基本可用)

场景举例:

电商网站交易付款模块出现问题,但需要核心的商品模块正常浏览

软状态:

由于不要求强一致性,即同步的过程由异步在某一时间完成。那么在写完到同步间存在中间状态——soft state

场景举例:

付款时,付了款但从库还查不到更新,可以短暂声明为:支付中——即数据同步中。

强一致性和最终一致性

  1. CAP中要求的是强一致性——主库写完即要求从库同步好。
  2. 最终一致性 允许在一段时间内,每个节点的数据不一致,但一段时间后必须同步。

全局时钟和逻辑时钟

由于不同机器上的物理始终难以同步,导致无法区分在分布式系统中多个节点的事件顺序

全局时钟:指一个真实的物理时钟,提供全局的时间信息,可以由GPS卫星或其他时间同步写一来提供

  • 但在分布式环境中实现完全一致的全局时钟是非常困难的

    1. 如果设置一个全局时钟服务器,那么传输时间通过的网络会存在物理延迟
    2. 时钟漂移:如果一开始给每个服务器设置相同时间,让他们同步启动来保证获取到相同时间,由于每个硬件时钟都会有微小的漂移,时间会逐渐偏离

逻辑时钟:用于确定事件发生顺序的抽象时钟,其不依赖物理时间,而是依赖于系统中的事件顺序和因果关系。

逻辑时钟算法之一:Lamport时钟——为每一个事件分配一个逻辑时间戳来跟踪事件间的顺序关系

思想:假如两个节点之间不进行交互,那么他们的时间都不需要同步

所以问题的关键在于:节点间的交互要在事件的发生顺序上达成一致

不同数据一致性模型:

image20231010122822139

强一致性:

当更小操作完成之后,任何多个后续进程的访问都会返回最新的更新过的值

难以实现 / 需要牺牲可用性

弱一致性:

系统在数据成功写入之后,不承诺立即可以读到最新写入的值,也不会具体承诺多久只会可以读到

用户读到某一操作对系统数据的更新需要一段时间,这段时间叫做 “不一致性窗口”

最终一致性:

最终一致性是弱一致性的特例,强调所有的数据副本在一段时间后同步

即有确定的不一致性窗口时间

什么会影响窗口的时间?通信延迟、系统负载、复制副本的个数...前提是没有发生故障

根据最终一致性提供的不同保证,可以划分成更多适配业务的模型

因果一致性:

要求有因果关系的操作顺序能够得到保证,非因果关系的操作则无所谓

例如:进程A在更新完某个数据后通知了进程B,那么B之后对该数据的访问都应该能获取到进程A更新后的最新值

例如:微信朋友圈的评论:评论必须在朋友圈之后,评论的回复必须在评论之后

会话一致性:

会话一致性将对系统数据的访问过程规定在一个会话当中

约定系统能保证在同一个有效的会话中实现 “读己之所写”的一致性

例如:分布式Session一致性问题即使会话一致性的一个应用

ACID 与 BASE

ACID强一致性模型适合传统金融等业务,也主要用于在数据库实现中

BASE理论面向高可用、可扩展的分布式系统,其目标是尽可能做到一致性和可用性,更接近现实

Paxos


Quorum 机制

  • Quorum选举算法

    主要数学思想来源于抽屉原理

    在N个副本中,一次更新成功如果有W个,那么在读取数据时,要从大于N-W个副本读取,就能够直到读到一个更新的数据

  • WARO 机制(Write All Read One)

    一种简单的副本控制协议

    当Client请求想某副本写数据时(更新数据),只有当所有副本都更新成功之后,这次写操作才算成功,否则为写入失败。

    • WARO 机制优先保证读服务,但写服务的可用性较低
  • Quorum机制:

    假设有N个副本,更新操作 wi 至少在W个副本中更新成功之后才认为此次更新操作wi成功

    对于读操作而言,至少需要读 R 个副本才能读到此次更新的数据

    其中:W + R > N;即W和R有重叠,一般,W + R = N + 1;

    N是存储数据的副本总数,W是更新成功所需的副本,R是一次数据对象读取需要访问的副本的数量

  • 单一Quorum机制无法保证强一致性

    需要配合一个获取最新成功提交的版本号的metadata服务,从已经获取到的数据中确定谁是最新的


Paxos 节点角色

image20231010140559311

  • Proposer 提案者

    流程开始时,Proposer提出议案,也就是value

    value在工程中可以是任何操作,比如:修改某个变量的值为某个新值

    Paxos协议中,统一将这些操作抽象为value

    不同的proposer可以提出不同的,甚至矛盾的value

  • Acceptor 批准者

    集群中,Acceptor有N个,之间完全对等独立

    Proposer提出的value必须获得超过半数(N / 2 + 1)的Acceptor批准后才能通过

  • Learner 学习者

    不参与选举,而是学习被批准的value

    Paxos中,Learner主要参与相关的状态机同步流程

  • Client 产生议题者

    作为产生议题者,实际不参与选举过程

Paxos中,Proposer和Acceptor是算法的核心角色

Paxos描述的是在一个由多个Proposer和多个Acceptor构成的系统中,如果让多个Acceptor针对Proposer提出的多种议案达成一致的过程,而Learner只是学习最终被审批的提案

image20231010141654602

Paxos选举过程

image20231010141724377

  • 准备阶段:

    Proposer生成全局唯一且递增的ProposalID,向Paxos集群的所有机器发送Prepare请求,这里不携带value,只携带ProposalID

    Acceptor收到Prepare请求后,判断收到的ProposalID是否比之前已响应的所有提案的ID大

    如果是:

    • 在本地持久化ProposalID,记为MAX_N

    • 回复请求,并带上已经Accept的提案中N最大的value

      如果此时还没有已经Accept的提案,则返回value为空

如果否:

  • 不回复或者回复Error

    • 选举阶段:

    分为三个阶段:P2a、P2b、P2c

  • P2a:Proposer发送Accept

    经过一段时间后,Proposer收到一些Prepare回复,有以下几种情况

    • 若回复数量 > 一半的Acceptor 数量,且所有回复的value都为空时

      则Proposer发起Accept请求,并携带自己指定的value

    • 若回复数量 > 一半的Acceptor数量,且有的回复value不为空时

      则Proposer发出accept请求,并带上回复中ProposalID最大的value,作为自己的提案内容

    • 若回复数量 <= 一半的Acceptor数量,则尝试更新生成更大的ProposalID,再转到准备阶段执行

  • P2b:Acceptor应答Accept

    Acceptor收到Accept请求后,判断:

    • 若收到的 N >= Max_N(一般情况下是等于),则回复提交成功,并持久化N和value
    • 若收到的 N < Max_N,则不回复或者回复提交失败
  • P2c:Proposer 统计投票

    经过一段时间后,Proposer会收集到一些 Acceptor回复提交成功的情况:

    • 当回复数量 > 一半的Acceptor数量时,表示提交value成功

      此时可以发一个广播给所有Proposer,Learner,同期他们已经commit的value

    • 当回复数量 <= 一半的Acceptor数量时,尝试更新生成更大的ProposalID,转到准备阶段执行

    • 当收到一条提交失败的回复时,尝试更新生成更大的ProposallID,也转到准备阶段执行

Raft

基本流程:

  1. 通过一个leader节点负责接收Client的指令,并将日志Entry发送给其他节点
  2. 读请求可以由任何节点处理,但是写请求需要重定向到Leader
  3. Leader先将指令写入到自己的日志,标记为待提交,再同步给其他节点,当超过法定人数的Follower都响应ok,再标记为已提交(Committed)
  4. 已提交的日志都会先有Leader应用于自己的状态机,Follower随后用于自己的状态机
  5. 当Leader故障或者网络不可达,Follower可通过某种方式(心跳机制)知道,并重新选出一个新的Leader来保证集群的正常运行
  6. 当有节点加入或退出集群时,可以将新的配置信息同步给集群

Raft算法分成三个部分

  • Leader选举
  • 日志复制
  • 安全性

复制状态机

相同的初始状态 + 相同的输入 = 相同的结束状态

在多个节点上,从相同的初始状态开始,执行相同的一串命令,最终会产生相同的最终状态

raft中,leader将客户端的请求(command)封装到一个个log entry中,将这些log entries复制到所有的follower节点,然后大家按照相同顺序应用log entries中的command,根据复制状态机理论,大家的结束状态肯定是一致的

  • 使用共识算法,就是为了实现复制状态机。一个分布式场景下的各个节点,就算通过共识算法来保证命令序列的一致,从而时钟保证其状态一致。(投票选主是一种特殊的命令)

状态简化

在任何时刻,每一个服务器都处于leader,follower或candidate三个状态之一

  • Raft把时间分割成任意长度的任期(term)| 全局逻辑时钟

  • 每一段任期从一次选举开始,在某些情况下,一次选举无法选出leader(比如两个节点收到相同的票数,或者没有任何一个节点收到票数超过一半),这一任期会以没有leader结束,一个新的任期(包含一次新的选举)会很快重新开始

    raft保证在一个任期内,对多只有一个leader

  • Raft算法中服务器节点之间使用RPC进行通信,并且Raft只有两种主要的RPC

    1. RequestVote RPC(请求投票):由candidate在选举期间发起
    2. AppendEntries RPC(追加条目):由leader发起,用来复制日志和提供心跳机制
  • 服务器之间通信的时候会交换当前的任期号,如果一个服务器上的当前任期号比其他的小,改服务器会将自己的任期好更新为较大的值。

  • 如果一个candidate或者leader发现自己的任期号过期了,它会立即回到follower

  • 如果一个节点收到一个包含过期的任期号的请求,它会直接拒绝请求。

领导者选举

  • Raft内部有一种心跳机制,如果存在leader,那么它就会周期性地向所有follower发送心跳,来维持自己的地位。如果follower一段时间内没有收到心跳(一段时间其实是随机数,防止多个follower同时变成candidate),那么他就会任务系统中没有可用的leader,然后开始进行选举

  • 开始一个选举过程后,follower先增加自己的当前任期号,并转换到candidate状态,然后投票给自己,并且并行地向集群中其他服务器节点发送投票请求(RequrstVote RPC)

  • 对于一个candidate来说最终有三种结果

    1. 它获得了超过半数选票的选举 -> 成为leader并开始发送心跳

    2. 其他节点赢得了选举 ->收到新的leader的心跳后,如果新leader的任期号不小于自己当前的任期号,那么就从candidate回到follower

      (比如两个follower先后没收到心跳而超时成为candidate,term+1,后一个大概率会收到前一个成为leader后的心跳,于是退回到follower)

    3. 一段时间之后没有任何获胜者 -> 每个candidate都在一个自己的随机选举超时时间后增加任期号开始新一轮投票(真实过程中是:candidate在一段时间内没有确认上方两个之一,就要让自身重启一次选举)

      为什么会没有获胜者?比如有多个follower同时成为candidate,得票太过分散,没有任何一个candidate得票超过半数

      论文中将随机选举超时时间设置为 150 - 300ms

选举过程:

分为candidate向follower发起Request和Follower返回Response

  • request和response中都包含自身任期,用于判断是否接收这个RPC
  • request中lastLogIndex和lastLogTerm是为了安全考虑的因素
  • 对于follower而言,对于同一个任期,会按照先来先得的原则投出自己唯一的选票

日志复制

  • Leader被选举出来后,开始为客户端的请求提供服务

  • 客户端怎么知道新leader是哪个节点?

    client请求一次老leader

    1. 老leader还是leader,万事大吉

    2. 老leader变成follower,通过新leader的心跳得知新leader的id,重新请求

    3. 老leader挂机,重新随机请求

      由于Raft能够保证在存活服务器大于半数时正常工作,所以一定能请求到1,2类型

  • leader接收到客户端的指令后,会把指令作为一个新的条目追加到日志中去。

    日志的组成部分:

    1. 状态机指令:往往是设置某个变量到某个值
    2. leader任期号:类似整个系统的逻辑时间
    3. 日志号(log index):用来区分日志的前后关系,还能用于上下对齐比较

  • 生成日志后,leader会将此日志并行的发送AppendEntries RPC给follower,让他们复制改条目。

    当该条目被超过半数的follower复制后并通知leader,leader就可用在本地执行该指令并把结果返回客户端

    leader在本地执行了指令后就是提交;

  • 图中leader是更新最快的,其余follower有的缺少几个日志,有的缺少整个任期

    但是只要有超过半数(3个)follower收到日志,leader就可以执行下一步日志——即图中第七步被提交,执行第八步

  • 落后的follower怎么跟上?

    由于leader或follower随时都有崩溃或缓慢的可能性,Raft需要在有宕机的情况下继续支持日志复制,并保证每个副本日志顺序的一致性

    分为三种情况:

    1. follower缓慢

      如果有follower因为某些原因没有给leader响应,那么leader会不断地重发追加条目请求(AppendEntries RPC,哪怕leader已经回复了客户端(已经提交了))

    2. follower宕机

      如果有follower崩溃后恢复,这时Raft追加条目的一致性检查生效,保证follower能按照顺序恢复崩溃后的缺失的日志

      一致性检查:

      • leader在每一个发往follower的追加条码RPC中,会放入前一个日志条目的索引位置和任期号,如果follower在它的日志中找不到前一个日志,那么他会拒绝此日志,leader收到follower的拒绝后,会发送前一个日志条目,从而逐渐向前定位到follower第一个缺失的日志
    3. leader宕机

      如果leader崩溃,那么崩溃的leader可能已经复制了日志到部分follower但还没有提交,而被选出的新leader又可能不具备这些日志,这样就导致部分follower中的日志和新leader的日志不相同

      Raft在这种情况下,leader通过强制follower复制它的日志来解决不一致的问题,这意味着follower中跟leader冲突的日志条目会被新leader的日志条覆盖(因为没有提交,所以不违背外部一致性)

  • 总结:

    • leader在当权之后就不需要任何特殊的操作来使日志绘画到一致状态

    • leader只需要进行正常的操作,然后日志就能在回复AppendEntries一致性检查失败的时候自动趋于一致

    • leader从来不会覆盖或者删除自己的日志条目(Append-Only)

    • 日志复制机制能保证一致性特性:

      1. 只要过半服务器能正常运行,raft就能够接受、复制并应用新的日志条目
      2. 在正常情况下,新的日志条目可在一个RPC来回中被复制给集群中的过半机器
      3. 单个允许慢的follower不会影响整体的性能
  • 追加条目RPC:

Raft 安全性

  • 问题1:

    Leader宕机处理:选举限制

    如果一个follower落后了leader若干条日志(但没有漏一整个任期),那么下次选举中,按照领导者选举里的规则,它依旧有可能当选leader,它在当选新leader后就永远无法不上之前缺失的那部分日志,从而造成状态机之间不一致。

    • 所以需要对领导者选举增加一个限制,保证被选举出来的leader一定包含了之前各个任期所有被提交的日志条目

    • 限制手段:

      通过RequestVote RPC包中包含的candidate的日志信息,可以得知candidate的最后一个日志和follower的最后一个日志哪个更新,如果follower更新,则follower会拒绝掉该投票请求

      新:

  • 问题2:

    Leader宕机处理:新leader是否提交之前任期内的日志条目

    一旦当前任期内的某个日志条目依旧存储到过半的服务器节点上,leader就知道该日志条目可以被提交

    • 提交:

      follower什么时候提交?在追加日志RPC中添加leaderCommit表示leader依旧提交的日志,follower可以提交这个日志之前的日志

      并且并不需要通过下一次追加日志才能获取提交上一次日志的通知,是因为心跳也是特殊的追加日志RPC,是不含有日志体但有leaderCommit

      于是由于心跳信息也是间隔发送,存在一种危险情况:leader已经提交了,但还没发送心跳时follower宕机,导致客户端虽收到提交,但实则有问题

ZooKeeper

ZooKeeper是一个分布式的、开源的分布式应用程序的协调服务

主要功能:

  1. 配置管理

  2. 分布式锁

    在单服务器下,一个jvm内用synchonize或者显示锁加锁能够保证一个共享资源不被多个线程交叉访问,但在集群服务器中,synchonize无法跳跃 jvm 将共享数据只属于一个jvm内的一段程序

    类似数据库中的数据,消息队列的数据,配置中心的数据...

    引入第三方工具 —— 分布式锁

    思路类似AOP,在每个服务器要访问共享数据前,前往ZooKeeper获取锁

    要么通过(获取),要么阻塞(等待锁释放),

  3. 集群管理

    作为注册中心使用

    provider将自身注册到Zookeeper,consumer通过访问注册中心获取到provider的信息,通过远程调用完成功能

ZooKeeper的特性都依赖于其高容错的数据一致性协议——Zab协议

区块链:

  • 区块链本质上是一个去中心化的数据库,特点是去中心化,公开透明

  • 天生分布式,是一个分布式账本,每个节点都可以参与数据库的记录

  • 区块链:注重安全和可信度胜过效率的一项技术

  • 区块链中的共识机制:

    决定了谁有记账的权利,以及此权力的选择过程和理由

    不同虚拟货币采用的共识机制不同,常见的有POW,POS,DPOS...

Consistency 一致性 和Consensus 共识

  • 一致性:侧重内容在时间顺序上的一致和统一
  • 共识:指许多参与者对某项内容达成共识
POW 工作量证明:

最早是用来防垃圾邮件的

Google邮箱强制要求每一个给Google服务器发送邮件的发送者必须先完成一定量的计算工作

造成一小段时间的延迟(比如延迟1s)

对于正常的邮件发送,1s延迟可以接收,但对垃圾邮件的攻击者却不能

比特币挖矿:

指将一段时间内比特币系统中发生的交易进行确认,并记录在区块链上形成新的区块的过程

而记账权需要竞争。利用计算机随机碰撞解题的过程就是挖矿

挖矿成功会获得比特币奖励(比特币系统中的印钞),以及本区块中所有交易产生的手续费(交易人给矿工的小费)

分布式事务

  • 分布式事务关注的是分布式场景下如何处理事务

    是指:当事务的参与者、支持事务操作的服务器、存储等资源分别位于分布式系统的不同节点之上

    事务:指要么这一系列操作全部执行成功,要么全部不执行

  • 分布式事务伴随着系统拆分出现的

    随让解决了海量数据对扩展性的要求,但增加了架构上的复杂性

    系统拆分来自存储服务的拆分

    • 存储层拆分:

      当表单容量达到千万级,就要考虑数据库拆分 —— 从单一数据库变成多个分库、多个分表

      在业务中如果需要进行跨库或者跨表更新,就要保证数据的一致性----分布式事务

    • 服务层拆分:

      系统架构的研究是:从集中式到分布式、业务功能之间越来越解耦

      例如电商网站系统:

      早期业务由一个单体工程支撑整套服务,但随着系统规模变大,公司将核心业务抽取出来作为独立的服务——商品、订单、库存等作为独立子项目

      将业务逻辑的执行分不到不同的服务器上

  • 分布式事务解决方案:

    1. 2PC 两阶段提交

      强一致性、中心化的原子提交协议

    2. 3PC 三阶段提交

    3. TCC 分段提交

  • 最终一致性的解决方案:

    1. 消息补偿——

      基于本地消息表 / 消息队列将程序执行异步化

      本地消息表:

      • 思路:将分布式事务的流程归纳到主服务器上,其他节点是否完成都需要对主服务器报告 | 上层建立一个事务消息表,标记调用其他事务是否完成,下层需要处理这个消息,并回调确认信息

        另外会有一个异步机制来定期扫描未完成的消息,来保证最终一致性

      • 感觉和MQ类似,只不过MQ服务器是另外的,本地消息表由自身服务器控制

分布式事务解决方案:

  • 在单台关系型数据库中,利用事务机制可以保证每个独立节点上的数据操作满足ACID

    但在分布式常见下,多个节点之间由于是通过网络进行沟通协商,很难顺利利用单个节点的事务机制

两阶段提交协议:

  • 两阶段提交算法基于以下假设

    • 在该分布式系统中,存在一个节点作为协调者,其他节点作为参与者

    • 所有节点都采用预写式日志,日志被写入后保存在可靠的存储设备上

      即使节点损坏也不会导致日志数据丢失

    • 所有节点不会永久性损坏,损坏后任能恢复

流程:

  1. 提交请求阶段:

    协调者将通知事务参与者准备提交事务,然后进入表决过程

    表决过程中,参与者将告知协调者自己的决策:

    同意(参与者在本地事务执行成功)或取消(本地事务执行故障)

    在此阶段,参与节点并没有进行Commit操作

  2. 提交阶段:

    在提交阶段,协调者将基于第一个阶段的投票结果进行决策:提交或者取消此事务

    当所有参与者都同意提交,协调者才会通知各个参与者提交事务,否则通知取消

    参与者收到协调者的消息后执行对应操作,即本地Commit或者Rollback

思路:

  • 先试探一下各个服务器,看看能否顺利执行,防止某个服务进行失败导致全场rollback

三阶段提交协议:

过程说明:

  1. CanCommit 阶段

    协调者向参与者发送Commit请求,参与者如果可以提交就返回Yes,否则返回No

    类似二阶段的准备阶段

  2. PreCommit 阶段

    协调者根据参与者的反馈进行操作

    • 假如所有参与者的反馈都是Yes,事务会预执行

      • 协调者向参与者发送preCommit请求,并进入Prepared阶段
      • 参与者收到PreCommit请求后,会执行事务操作
      • 参与者将执行结果是否成功(ACK / !ACK)返回,同时开始等待最终指令
    • 假如有任何一个参与者发送了No,或者等待超时,事务会中断

      • 协调者向所有参与者发送中断请求
      • 参与者收到后执行事务中断
  3. DoCommit阶段

    协调者根据收到的结果进行操作

    • 假如协调者收到所有参与者发送的ACK响应

      • 从预提交状态进入到提交状态,并向所有参与者发送doCommit请求
      • 参与者收到doCommit请求后,执行正式的事务提交,并在完成事务提交后释放所有事务资源
      • 参与者事务提交完毕后,向协调者二发送ACK响应
      • 协调者接收到所有参与者的ACK响应后,完成事务
    • 假如协调者没有接收到某个参与者的ACK响应,执行事务中断

    • 超时提交:参与者如果没有收到协调者的通知,超时之后会执行Commit操作

三阶段的改进:

  1. 引入超时机制

    在2PC中,只有协调者拥有超时机制,如果在一定时间内没有收到参与者的消息则默认失败

    在3PC中,同时在协调者和参与者中都引入了超时机制

  2. 添加预提交阶段

    PreCommit是一个缓冲,保证了在最后提交阶段之前,各个节点的状态是一致的


重启分布式理论


image20231009152905959

image20231009152934739

image20231009152947948

image20231009153000987

image20231009153013425

image20231009153026382

image20231009153039490


  • 分布式系统的核心是可扩展性,通过对服务、存储的扩展,来提高系统的处理能力
  • 通过多台服务器协同工作,来完成单台服务器无法处理的任务