• 这两天回顾了mysql中的事务,具体来说就是ACID。
  • 然后恰巧看到一篇写得超好的分布式系统的事务处理,所以就顺便再总结分布式事务一些相关的知识点。

Overview

  • 分布式的背景:
    • 性能:一台服务器的性能不足以提供足够的能力服务于所有的网络请求。
    • 容灾:我们总是害怕我们的这台服务器停机,造成服务不可用或是数据丢失。
  • 如何扩展?
    • 数据分区:就是把数据分块放在不同的服务器上(如:uid % 16,一致性哈希等)。
      • 问题:跨机器的事务处理:比如最经典的“A账号向B账号转钱”,如果A和B不在同一个机器,就涉及到了跨机器的事务。
    • 数据镜像:让所有的服务器都有相同的数据,提供相当的服务。
      • 问题:对于存储在不同服务器上数据分本,怎保证数据一致性
  • 综上,分布式事务要考虑
    • 容灾:数据不丢,节点的failover
    • 数据一致性:事务处理
    • 性能:吞吐量,响应时间
  • 总结:高可用/容灾 --> 必须副本  -->  副本会引发数据一致性问题  -->  数据一致性又会引发性能问题

分布式

问题

  • 通信异常:网络本身的不可靠性,消息丢失和消息延迟非常普遍。

  • 网络分区:当网络由于异常而导致分布式系统中部分节点之间的网络延时不断增大,最终导致组成分布式系统的所有节点中,只有部分节点间能正常通信,该现象称为网络分区,俗称“脑裂”。在极端情况下,这些局部小集群会独立完成原本需要整个分布式系统才能完成的功能,包括对数据的事务处理,这就对分布式一致性提出了非常大的挑战。

  • 三态:分布式系统的每一次请求与响应,存在特有的“三态”概念,即成功、失败与超时。(不同于传统单机,能够得到明确的响应:成功或失败。)

  • 节点故障:每个节点都有可能故障。

CAP/BASE

  • 如何构建一个兼顾可用性和一致性的分布式系统是无数工程师探讨的难题,并随之出现了诸如CAP和BASE这样的分布式系统经典理论。

CAP

  • CAP理论告诉我们,一个分布式系统不能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三个基本需求,最多只能同时满足其中两项。
  • 其中:
    • 一致性是指数据在多个副本之间是否能够保持一致的特性。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一致的状态。在分布式系统中,如果能做到针对一个数据项的更新操作执行成功后,所有的用户都可以读取到其最新的值,这样的系统被认为具有强一致性(严格一致性)。
    • 可用性是指系统提供的服务必须一致处于可用的状态,对于用户的每一个操作请求总是能在有限的时间内返回结果。“有限时间”是一个系统在设计之初就设定好的系统运行指标。比如一个搜索引擎通常0.5s,一个hive查询通常20~30s。
    • 分区容错性是指分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性服务,除非是整个网络环境都发生了故障。网络分区是指在分布式系统中,不同的节点分布在不同的子网络(机房或异地网络等)中,由于一些特殊原因导致这些子网络之间出现网络不连通的状况,但各个子网络的内部网络正常,从而导致整个网络环境被切分成了若干孤立的区域。
  • 放弃p就意味着放弃系统的可扩展性。
  • 放弃a就意味着系统遇到故障时,无法对外提供正常的服务。
  • 放弃c,并不是说完全不需要数据一致性(否则整个系统将失去价值)。事实上,放弃一致性指的是放弃数据的强一致性,而保留数据的最终一致性。这就引入了一个时间窗口的概念,具体时长取决于系统的设计,主要包括数据副本在不同节点之间的复制时间长短。

BASE

  • BASE是Basically Available、Soft state和Eventually consistent三个短语的缩写。
  • BASE是对CAP中一致性和可用性权衡的结果,其来源是对大规模互联网系统分布式实践的总结。
  • 其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性
  1. 基本可用:
    • 基本可用是指在分布式系统出现不可预知故障时,允许损失部分可用性,但这绝不等价于系统不可用。
    • eg:
      • 响应时间损失:查询时间增加;
      • 功能上损失:双11部分消费者都被引导到一个降级页面。
  2. 弱状态:
    • 和硬状态相对,是指允许系统中的数据存在中间状态,并认为中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
  3. 最终一致性:
    • 最终一致性强调的是系统中所有数据副本,在经过一段时间后,最终能够达到一个一致的状态。

一致性模型

* 前提:理论上来说,在分布式计算领域,试图在异步系统和不可靠的通道上来达到一致性状态是不可能的,因此在一致性的研究过程中,都往往假设信道是可靠的。

  • 一致性真是分布式永恒的话题 = =
  • 说起数据一致性来说,简单说有三种类型(当然,如果细分的话,还有很多一致性模型,如:顺序一致性,FIFO一致性,会话一致性,单读一致性,单写一致性)
    • weak弱一致性:当你写入一个新值后,读操作在数据副本上可能读出来,也可能读不出来。
    • eventually最终一致性:当你写入一个新值后,有可能读不出来,但在某个时间窗口之后保证最终能读出来。
    • strong强一致性:新的数据一旦写入,在任意副本任意时刻都能读到新值。比如:文件系统,RDBMS,Azure Table都是强一致性的。
  • weak和eventually一般是异步冗余,而strong一般是同步冗余
    • 异步通常意味着更好的性能,但也意味着更复杂的状态控制。
    • 同步通常会带来性能下降。

2PC/3PC

  • 背景是:在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。
  • 当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。

2PC

  •  两阶段:
    • 阶段一:提交事务请求:
      • 协调者会问所有的参与者结点,是否可以执行提交操作。
      • 各参与者开始执行准备工作,如::为资源上锁,预留资源,写undo/redo log……
      • 参与者响应协调者,返回“可以提交”or“拒绝提交”。
    • 阶段二:正式提交阶段:
      协调者根据各参与者的反馈情况来决定最终是否可以进行事务提交操作。
      • 执行事务提交
        1. 发送提交请求:协调者向所有参与者节点发出Commit请求;
        2. 事务提交
        3. 反馈事务提交结果:参与者完成事务提交后,向协调者发送Ack
        4. 完成事务
      • 中断事务
        1. 发送回滚请求:协调者向所有参与者节点发出Rollback请求;
        2. 事务回滚:参与者利用其在阶段一中记录的Undo信息来执行回滚操作;
        3. 反馈事务回滚结果
        4. 中断事务
  • 优点:原理简单,实现方便
  • 缺点:同步阻塞,单点问题,脑裂,太过保守。
    • 同步阻塞:2PC最大的问题,会极大地限制分布式系统的性能。因为在2PC执行过程中,所有该事务操作的逻辑都处于阻塞状态,也就是说,各个参与者在等待其他参与者响应的过程中将无法进行其他任何操作。
    • 单点问题:一旦协调者出现问题,整个2PC都无法运转。更严重的是,如果协调者在phase2中出现问题的话,那么其他参与者将会一直处于锁定事务资源的状态中,而无法继续完成事务操作。
    • 数据不一致:在phase2,如果协调者向所有的参与者发送Commit请求之后,发生了局部网络异常或是协调者在尚未发送完Commit请求之前自身发生崩溃,最终导致只有部分参与者收到了Commit请求,那么整个分布式系统就会出现数据不一致现象。
    • 太过保守:当协调者无法获取参与者的响应信息时,协调者只能依靠其自身的超时机制来判断是否需要中断事务,这样的策略过于保守。换句话说,2PC提交协议没有涉及较为完善的容错机制,任意一个节点的失败都会导致整个事务的失败。

3PC

  • 3PC是由CanCommit、PreCommit和DoCommit三个阶段组成的事务处理协议。
  • 三段提交的核心理念是:在询问的时候并不锁定资源,除非所有人都同意了,才开始锁资源
  • 3PC的状态转移图
  • 优点:3PC最大的优点就是降低了参与者的阻塞范围,能够在出现单点故障后继续达成一致。
  • 缺点:在参与者接收到preCommit消息后,如果出现网络分区,此时协调者所在的节点和参与者无法进行正常的通信,在这种情况下,该参与者依然会进行事务提交,这必然出现数据的不一致性。

Paxos

  • 关于Paxos,可以参考wiki。(也可以参考我之前的blog)
  • Paxos算法解决的问题是,在不考虑出现消息篡改(即拜占庭错误)的情况下,如何在一个可能发生异常(消息延迟、丢失,进程慢、被杀死、重启等)的分布式系统中如何就某个值达成一致,保证不论发生以上任何异常,都不会破坏决议的一致性。
  • 简单说来,Paxos的目的是让整个集群的结点对某个值的变更达成一致。
  • Paxos算法基本上来说是个民主选举的算法——大多数的决定会成个整个集群的统一决定。任何一个点都可以提出要修改某个数据的提案,是否通过这个提案取决于这个集群中是否有超过半数的结点同意(所以Paxos算法需要集群中的结点是单数)。   [Majority Vote]

 

架构设计

Master-Slave

  • 最经典的master-slave架构。对于这种加构,Slave一般是Master的备份。
  • 功能上来说:
    • 读写请求都由master负责
    • 写请求写到master上后,再同步到slave上。
  • 从master同步到slave上:
    • push-based: 可由master来push。
      • 可以做到强一致性:master先写自己,然后再写slave,两者都成功才返回成功。
      • --> 整个过程是同步的。
      • --> 但如果slave失败了,那么有两种方法:
        • 标记slave不可用并继续服务
        • master回滚自己并返回写失败。
    • pull-based: 最终一致性。
      • 但pull-based的问题在于:如果master在pull周期内垮掉了,就会导致数据丢失。
      • --> 如果想要避免丢失,只能等master恢复。(服务不可用)
      • --> 当然,在可以容忍数据丢失的情况下(比如,对于只负责计算的节点而言,就没有数据丢失和一致性的问题),master-slave就可以解决单点问题了。

Master-Master

  • 又叫Multi-master:一个系统存在两个或多个Master,每个Master都提供read-write服务。  [感觉是P2P]
  • 其实可以看到,上述master-slave架构,可用性是不高的:
    • push-based的架构同步写,性能不高。
    • pull-based的构架则存在master故障导致的宕机。
  • 优点:
    • 如果一个master fails,其他节点可以持续提供服务
  • 缺点:
    • 一致性问题:最终一致性。