分布式架构设计 - 理论学习

AI 摘要: 高可用性集群是由一组计算机组成,通过协调工作获得更好的性能与可用性。在集群中,节点的故障可以使用检查点来恢复系统的状态,避免重新计算结果。高可用性集群通过提供冗余计算机和故障转移来确保应用程序的持续可用性。分布式计算体系结构利用消息传递协议和共享数据库实现进程间通信和协调工作。在分布式系统设计中,根据分区容错性,可以选择CP或AP作为侧重点。ACID提供强一致性,但可能牺牲可用性。在系统过载时,可以采取有损服务和资源扩容的策略提升整体系统性能。

1. 集群(集群模式提供比单点更高可用性、可靠性的规模效应)

由一组计算机组成(可以包含虚拟机或容器),一起协调工作,以获得更好的性能和可用性,以及更低的成本; 整体抽象上被视为单一系统看待,完成一项内容(ES 集群、Web 集群、RabbitMQ 集群、Mysql 集群),计算机集群将每个节点设置为执行相同的任务,由软件控制和调度。

1.1. 集群基本介绍

1.1.1. 集群概念

  • Cluster - 突出整体概念
  • 部署集群通常是为了提高单台集群的性能和可用性,同时从成本和收益上大于单台服务器,集群目的:
    • 数据共享、计算能力、存储能力共享
    • 管理成本、费用成本降低(VM)

1.1.2. 集群好处

  • 性能更佳,系统吞吐更高
  • 容错能力更强(高可用、可靠性)
  • 伸缩能力更好(扩展性),无状态的服务机器支持水平弹性扩缩容
  • 更廉价(对比 IOE 方案 IBM、ORACLE、EMC)

1.1.3. 集群属性

  • 负载均衡(不同的负载均衡调度算法)
  • 高可用(基于故障转移实现)

1.1.4. 集群间数据节点通信方式

  • MPI(MsgPassInterface 消息传递接口,现大多由 TCP/IP 和 Socket 连接)
  • PVM(并行虚拟机)

1.1.5. Linux 集群常见软件

  • Linux Virtual Server
  • Linux-HA
  • 基于 Kubernets 容器编排的多 Pod 集群架构

1.2. 集群软件开发和管理成本

1.2.1. 并行编程

  • 负载均衡集群(如 Web 服务器)使用集群体系结构来支持大量用户,并且通常每个用户请求都被路由到特定节点,实现任务并行而无需多节点协作,因为系统的主要目标是提供快速用户访问共享数据。然而,为少数用户执行复杂计算的“计算机集群”需要利用集群的并行处理能力并在几个节点之间划分“相同计算”。
  • 程序的自动并行化仍然是技术挑战,但是并行编程模型可以用于通过在不同处理器上同时执行程序的单独部分来实现更高程度的并行性。

1.2.2. 调试和监控

当节点在长多节点计算期间出现故障时,应用程序检查点可用于恢复系统的给定状态。这在大型集群中是必不可少的,因为随着节点数量的增加,在大量计算负载下节点发生故障的可能性也会增加。检查点可以将系统恢复到稳定状态,以便可以恢复处理而无需重新计算结果。

1.2.3. 管理成本

  • 任务调度
  • 任务执行(MapReduce、Hadoop)
  • 故障转移防护

1.3. 高可用集群

参考:https://en.wikipedia.org/wiki/High-availability_cluster

高可用性集群(也称为 HA 群集或故障转移群集)是支持服务器应用程序的计算机组,可以在最短的停机时间内可靠地使用这些应用程序。它们通过使用高可用性软件来运行组或集群中的冗余计算机 在系统组件发生故障时提供持续服务。

如果没有集群,如果运行特定应用程序的服务器崩溃,则在崩溃的服务器修复之前,应用程序将不可用。

HA 群集通过检测硬件/软件故障来解决这种情况,并立即在另一个系统上重新启动应用程序而无需管理干预,这一过程称为故障转移。作为此过程的一部分,群集软件可以在启动应用程序之前配置节点。例如,可能需要导入和装载适当的文件系统,可能必须配置网络硬件,并且还可能需要运行某些支持应用程序。

在高可用性集群环境中运行,应用程序必须至少满足以下技术要求(其中最后两个对于其在集群中的可靠功能至关重要,并且最难以完全满足):

  • 必须有一种相对简单的方法来启动,停止,强制停止和检查应用程序的状态。实际上,这意味着应用程序必须具有一个或多个命令行界面来控制应用程序,包括支持多个应用程序实例。
  • 应用程序必须能够使用共享存储(如 NAS/SAN)。
  • 最重要的是,应用程序必须尽可能多地将其状态存储在非易失性共享存储上。同样重要的是能够在故障之前使用共享存储中保存的状态在最后状态下重新启动另一个节点。
  • 如果数据崩溃或从已保存状态重新启动,则应用程序不得损坏数据。
  • 通过使用虚拟服务器环境可以最大限度地减少许多这些约束,其中虚拟机管理程序本身具有群集感知功能,并在物理主机之间提供虚拟机的无缝迁移(包括运行内存状态)

1.4. 故障转移

参考:https://en.wikipedia.org/wiki/Failover

1.4.1. 故障转移流程

  • 在服务器级别,故障转移自动化通常使用“心跳”系统,通过网络连接来连接两个服务器。
  • 只要在主服务器和第二服务器之间继续定期“脉冲”或“心跳”,第二服务器就不会使其系统联机,有第三个“备件”服务器运行备用组件进行“热”切换防止停机。
  • 故障来临时候,第二台服务器在检测到第一台机器的“心跳”发生变化后立即接管第一台服务器的工作,,同时:
    • 某些系统能够自动发送故障转移通知,完成自动切换;
    • 某些系统不会完全自动进行故障转移,但需要人为干预;一旦人员批准了故障转移,这种“手动批准自动化”配置就会自动运行

1.4.2. 转移策略

在使用故障转移之前,需要定好何种情况才被认定为一个故障,以及出现故障如何转移

2. 分布式(Distribute,突出共同目标)

2.1. 分布式介绍

2.1.1. 分布式概念

  • 分布式操作系统是在独立的,集合的软件网络化,通信和物理上独立的计算节点,它们处理由多个 CPU 提供服务的作业。每个单独的节点都拥有全局聚合操作系统的特定软件子集。每个子集都是两个不同服务提供者的组合。第一个是无处不在的最小内核或微内核,它直接控制该节点的硬件。其次是系统管理组件的更高级别集合协调节点的个人和协作活动。这些组件抽象微内核功能并支持用户应用程序。
  • 分布式操作系统提供操作系统所需的基本服务和功能,但添加了属性和特定配置,以支持其他要求,例如增加规模和可用性。对于用户而言,分布式 OS 以类似于单节点单片操作系统的方式工作。也就是说,虽然它由多个节点组成,但它对用户和应用程序来说都是单节点。

2.1.2. 分布式特征

  • 实体自治(通常指分布式节点,甚至是分布式应用进程),实体可以独立运行和管控
  • 实体间通过消息传递互相通信(比如 HTTP、RPC、THRIFT、GRPC 等)

2.1.3. 分布式的其他属性

  • 分布式系统必须容忍整体计算机的故障
  • 系统的结构(网络拓扑,网络延迟,计算机的数量)是事先不知道的,系统可以包括不同种类的计算机和网络链路,并且系统可以在分布式程序的执行期间改变。
  • 每台计算机只有一个有限的,不完整的系统视图。每台计算机只能知道输入的一部分。

2.1.4. 分布式好处

  • 可靠性,没有单点故障
  • 分布式系统可以更容易扩展和管理
  • 性能收益,使用几个低端计算机的集群来获得期望的性能水平可能更具成本效益

2.1.5. 分布式带来的问题

  • 分布式算法
  • 餐饮哲学家问题
  • 互斥
  • 死锁
  • 共识问题
  • 拜占庭容错
  • 时钟同步
  • 选举

2.1.6. 分布式架构

  • 客户端 - 服务器:C/S
  • 三层:Web 应用,展示层、逻辑层、数据层
  • n-tier:引用 Web 应用程序的体系结构,它进一步将其请求转发给其他应用程序
  • 点对点
  • SOA 架构
  • 微服务架构

分布式计算体系结构的另一个基本方面是在并发进程之间通信和协调工作的方法。通过各种消息传递协议,进程可以彼此直接通信,通常以主/从关系。或者,“以数据库为中心”的体系结构可以通过利用共享数据库使得能够在没有任何形式的直接进程间通信的情况下完成分布式计算

2.2. 并行、并发、分布式计算

2.2.1. 并行和并发

  • 并发计算:突出在同一时间执行任务,微观上面任务执行还是有先后的
  • 并行计算:突出在多处理器上同时执行任务

2.2.2. 并行计算和分布式计算

  • 并行计算可以被看作分布式计算的一个特定的紧密耦合的形式,分布式计算可以被视为并行计算的松散耦合形式
  • 并行和分布式的区别(颗粒度):
    • 在并行计算中,所有处理器可以访问共享存储器以在处理器之间交换信息
    • 在分布式计算中,每个处理器都有自己的专用内存(分布式内存),通过在处理器之间传递消息来交换信息
  • 并行算法分布式算法
    • 共享内存多处理器中的高性能并行计算使用并行算法
    • 大规模分布式系统的协调使用分布式算法

2.3. 分布式数据存储 CAP 理论

参考:https://en.wikipedia.org/wiki/CAP_theorem

2.3.1. CAP 理论

  • 一致性(Consistency:):每次读取都会收到最近的写入或错误
  • 可用性(Availability):每个请求都会收到(非错误)响应 - 可以不保证它包含最新的写入
  • 网络分区容忍性(Partition tolerance):尽管分布式存储节点之间的网络丢弃(或延迟)任意数量的消息,系统仍继续运行

2.3.2. CAP 说明

  • 没有分布式系统可以避免网络故障,因此通常必须容忍网络分区。(P 不能割舍)
  • CP(一致,但不一定高可用,分区数据要做数据同步,导致可能不可用)架构
    • 在选择一致性(consistency)而非可用性(availablity)时,如果由于网络分区而无法保证特定信息是最新的,则系统将返回错误或超时。
  • AP(可用,但可能不是最新的)架构
    • 在选择可用性(availablity)而非一致性(consistency)时,系统将始终处理查询并尝试返回最新的可用信息版本,即使由于网络分区而无法保证其是最新的。(可能存在脑裂问题,信哪个可用的情况)
  • 在没有网络故障的情况下,也就是说,当分布式系统正常运行时,可以满足可用性(A)和一致性(C)
  • CAP 经常被误解,好像必须始终选择放弃三种保证中的一种。实际上,只有在发生网络分区或故障时,才能在一致性和可用性之间进行选择; 在所有其他时间,不需要进行任何权衡。
  • 考虑到传统 ACID 设计的数据库系统,例如 RDBMS 选择一致性而非可用性,而围绕 BASE 理念设计的系统(例如 NoSQL 运动中常见的)选择可用性而不是一致性
  • 高可用性要求意味着系统必须复制数据。一旦分布式系统复制数据,就会出现一致性和延迟之间的权衡。

2.4. PACELC 定理(PAC ELSE PLC)

参考:https://en.wikipedia.org/wiki/PACELC_theorem

  • PACELC 定理是 CAP 定理的扩展。它指出,在分布式计算机系统中进行网络分区(P)时,必须在可用性(A)和一致性(C)(根据 CAP 定理)之间进行选择,否则(E),即使系统是在没有分区的情况下正常运行,必须在延迟(L)和一致性(C)之间进行选择。
  • PACELC 建立在 CAP 定理的基础上。这两个定理都描述了分布式数据库如何在一致性,可用性和分区容错方面具有局限性和权衡。然而,PACELC 进一步说明了另一个权衡因素:即使没有分区,也存在延迟和一致性之间的时间,从而更全面地描述分布式系统的潜在一致性权衡
  • 高可用性要求意味着系统必须复制数据。一旦分布式系统复制数据,就会出现一致性和延迟之间的权衡。

3. 分布式系统共识问题

3.1. 拜占庭将军问题(节点共识问题)

  1. 分布式系统中,各节点可能存在故障通信等问题,同时还可能存在恶意攻击等问题,需要在此基础上解决节点的共识问题;
  2. 共识问题解决方法:
    • 基于口信消息
    • 基于签名消息
  3. 算法类型:
    • 存在恶意节点行为(区块链),采用拜占庭容错算法,如BFT/PBFT/Pow
    • 无恶意节点,消息伪造等情况,采用非拜占庭容错(故障容错 - CFT)算法,如Paxos、Raft算法、ZAB协议

3.2. 分布式 CAP 理论

3.2.1. CAP 的三个指标(一致性、可用性、分区容忍性)

  1. 一致性(强调分布式系统的数据一致能力):对客户端的承诺,强调各个节点之间的数据一致,即集群和单节点是一致的。
  2. 可用性(强调分布式系统的分区容错能力):客户端不论访问哪个节点,都能得到响应数据,但不保证是最新的;
  3. 分区容错性:分布式每个分区(节点)在出现故障时(比如通信问题),分布式系统应该任然能提供服务;

在 P 分区容错性,必然的前提下,我们的分布式系统设计在不同业务上,AP 和 CP 有不同的侧重点,即当出现了分区错误的时候(节点网络问题),应该考虑选择 CP 还是 AP。 - 选择了 CP 模型,如果在某个节点写失败下,分布式系统会整体拒绝提供服务(读的话可以支持); - 选择了 AP 模型,如果在某个节点写失败下,分布式系统整体还是保证可用的(可以事后补偿达到最终数据一致);客户端对节点的读取操作,节点返回当前节点提供的信息,允许返回不一致的信息(可能不是最新的信息)。

3.3. ACID - 追求一致性性,CP 模型延伸

3.3.1. 二阶段提交,代表 XA、TCC、Raft、Paxos

  1. 二阶段提交过程:
    • 投票阶段:Coordinator 协调者, 联系其他节点投票,进入二阶段提交请求阶段(投票阶段),收集投票结果
      • 每个节点如果确认,就需要锁定相关资源,等待协调者投票结果反馈。一旦承诺,就必须确保事务执行到位,即使节点存在故障或其他问题(代码保证)
      • 协调者搜集了全部节点的投票结果,进行评估是否需要执行分布式事务
    • 执行阶段:Coordinator 协调者,基于投票结果,按照要么全部执行,要么全部取消的原则(实现 ACID 中的原子性),将结果通知所有的节点
      • 每个节点基于通知的结果,确保按协调者的要求执行
  2. 二阶段提交最早用于数据库分布式事务(代表协议 XA,比如 MYSQL 就支持 XA 分布式事务),XA 协议也叫做Distributed Transaction Processing(DTP)模型
  3. 二阶段提交的问题:
    • 节点提交请求节点(投票阶段),需要预留资源(资源锁定)
    • 针对资源预留,数据库是独立的系统,无法弹性的调整锁的粒度,如果锁得范围过大,会影响并发度
    • 问题替代方案 - TCC 利用业务确认和取消的幂等性,确保事务执行成功
  4. Raft、Paxos 这类强一致性分布式算法,也采用二阶段提交协议思想,只是需要大部分节点确认就执行事务,而 ACID 要求全部节点确认才执行事务。
  5. 三阶段提交,是基于考虑到协调者故障,节点参与者资源长时间锁定问题,加入节点询问和超时机制,但带来了更多的节点消息通信,使得系统更加复杂,较少使用。

3.3.2. TCC(Try-Confirm-Cancel),事务补偿

  1. TCC(预留-确认-取消)
    • 预留阶段(TRY):
      • 协调者尝试让各个节点保留资源,准备执行各自的任务
      • 协调者注册确认与取消操作
      • 协调者收集各节点,针对预留节点的回复
    • 确认阶段(Confirm):
      • 执行预留阶段资源满足情况下,协调者确认操作,协调者向各个节点发送事务确认执行的操作
      • 各节点向协调者返回各自任务执行情况
    • 取消阶段(Cancel):
      • 执行预留阶段,如果某节点不满足资源,协调者通知其他节点全部取消操作,达到一致性
  2. TCC 的本质是补偿事务,也是基于二阶段提交思想,程序应用扮演了协调者的角色。可以将 TCC 理解为编程模型,即业务层面上的协议,即确认和取消操作都应该是幂等的,因为当确认或取消失败时候,应用程序需要满足补偿重试达到一致;
  3. 少用 TCC:TCC 不是依赖数据库来实现分布式事务的一致性,而是在业务层面上实现分布式事务,好处是对数据库压力减少,带来的问题就是对代码的侵入性增加,提升了代码的复杂度。因此,从代码简洁和维护性上,如果要确保分布式事务的强一致性,优先考虑支持分布式事务的数据库,比如MYSQL XA,当数据库无法满足业务要求时候(比如性能开销),再来考虑 TCC。
  4. 幂等性:同一操作对同一系统,所产生的影响均与一次执行的影响一致,不会因为多次导致副作用的产生,主要是基于Token、索引这类唯一标识,标记同一操作,消除多次执行的副作用
  5. 失败重试:幂等性需要将提交相关信息保存到持久存储上,即使故障、超时,也需要在故障恢复、超时后,不断重试以实现自己的承诺。

3.3.3. ACID 在 CAP 中的考虑

ACID 是强一致性,即 CP 优先考虑,可用性方必然受到损失。如果一个节点出现,分布式事务是必然失败的。但绝大多数场景,对一致性要求没有那么高,

3.4. BASE - 追求可用性,AP 模型的延伸

3.4.1. BASE(BasicallyAvialiable、SoftState、EventuallyConsistent) - 基本可用、软状态、最终一致

  1. BASE 强调可用性,属于 CAP 中的 AP 延伸,其中最关键的是基本可用和最终一致,软状态指数据的过渡状态,不同节点之间存在短暂的不一致,最终会达成数据的一致。

3.4.2. 基本可用(BasicallyAvailable)分布式设计考虑

在系统过载情况,一方面考虑提供有损服务,弃朱保帅,另一方面积极寻求资源扩容,提升整体系统的吞吐量

  1. 流量错峰(不同地区售票时间错峰出售)
  2. 异步处理(买票排队,基于队列先收到用户买票请求,排队异步处理,延迟响应)
  3. 服务降级(看到非实时数据,采用缓存数据提供服务)
  4. 过载保护(熔断/限流,直接拒绝掉一部分请求,或者当请求队列满了,移除一部分请求,保证整体系统可用)
  5. 故障隔离(出现故障,做到故障隔离,避免影响其他服务)
  6. 弹性扩容(基于 Metric 和 Monitor 实现系统态势感知,做到弹性伸缩)

3.4.3. 最终一致性(EventuallyConsistent)

  1. 最终一致:系统所有数据经历一段时间后,最终会达到一个一致的状态;
  2. 最终一致的数据,以什么数据为准:
    • 以最新写入的数据为准(KV 存储)
    • 以第一次写入的数据为准(不希望存储数据被更改)
  3. 如何实现最终一致性:
    • 读时修复,读数据的时候,检查分布式各节点数据是否一致,不一致则通知系统修复(读需要做数据比对,考虑开销,算法效率)
    • 写时修复(数据存储+失败重传),写数据的时候,检查分布式各节点数据是否一致,不一致则通知系统同步修复(不需要同其他节点做数据比对,仅在有差异时候才修复)
    • 异步修复,定期检测数据是否一致,最终达到一致(常用)
  4. 考虑设计支持一次性级别,比如All、Quorum、One、Any,让用户选择相应的一致性级别,比如 ALL 来支持强一致性。

4. 参考

  • 计算机集群:https://en.wikipedia.org/wiki/Computer_cluster
  • 集群高可用:https://en.wikipedia.org/wiki/High-availability_cluster
  • 故障转移:https://en.wikipedia.org/wiki/Failover
  • 并行计算:https://en.wikipedia.org/wiki/Parallel_computing
  • 分布式计算:https://en.wikipedia.org/wiki/Distributed_computing
  • CAP 理论:https://en.wikipedia.org/wiki/CAP_theorem
  • PACELC 定理:https://en.wikipedia.org/wiki/PACELC_theorem
  • 分布式操作系统:https://en.wikipedia.org/wiki/Distributed_operating_system