分布式知识总结

2024-01-25 10:11:44 浏览数 (2)

分布式系统的演进和定义

要理解分布式系统的定义,必须了解应用如何从单体到分布式的演进过程。

单体应用

  • 一台机器上部署单一应用
  • 受单机性能容量限制
  • 单点故障
  • 扩展性差

集群应用

  • 无状态集群应用
    • 任何一个请求都与之前的请求无关。
    • 集群中的节点可以任意伸缩。
  • 有状态的集群应用
    • 单一服务的节点集群
      • 节点间完全隔离,只服务对应的用户。
      • 容错性较差。
    • 共享信息池的节点集群
      • 多个节点共享信息池。
      • 受信息池容量、性能影响。
      • 存在信息池单点故障问题。
    • 信息一致的节点集群
      • 每个节点有独立的信息池。
      • 信息池间同步,存在延迟和一致性问题。
      • 适用于读多写少的场景。

分布式应用

  • 将应用拆分成多个子应用。
  • 不同节点上可能部署不同的子应用。
  • 子应用按需扩展集群。

集群与分布式

  • 集群指多个节点做相同的任务。
  • 分布式指多个节点协同做一种任务。

广义的分布式

  • 判断依据:多个节点是否使用一致的信息池。
  • 无论节点部署相同还是不同应用。
  • 都面临信息池的同步及数据一致性问题。

分布式系统的基本问题

  • 网络通信问题,网络存在抖动断网丢包,通信延迟超时等。
  • 节点故障问题,机器宕机、重启等。
  • 网络分区问题,集群因为网络问题分裂成多个完全独立的集群。
  • 三态问题,每一次请求响应,除成功失败外还存在超时,无法确定请求是否被成功处理。

CAP 定律

  • C是Consistency,一致性
    • 指写入成功后,必须保证后续读取到的是最新的数据。如果仍然读取到过期的数据,就是不一致的。
  • A是Availability,可用性
    • 指提供正常可用的服务能力,不会发生超时或错误。
  • P是Partition tolerance,分区容忍性
    • 指允许集群分裂成多组完全不连通的分区。
  • CAP 定律指:分布式系统无法同时满足CAP三种特性,只能满足其二。
  • 要保证一致性和可用性,则不能保证分区容忍性,即必须保证网络的可靠性不允许出现分区。
  • 事实上,网络是不可靠的,分区容忍性是分布式系统的基本前提。
  • 所以只能在一致性和可用性之间做选择。

一致性级别

  • 强一致性:承诺始终能读取到最新写入的数据,代价是相对高的延迟。
  • 弱一致性:不承诺可以立刻读取到最新写入的数据,但尽可能保证到某个时间级别后读到最新的数据。弱一致性又可分:
    • 会话一致性:保证在同一客户端会话的强一致性,其他会话不保证。
    • 用户一致性:保证在同一用户中的强一致性,其他用户不保证。
  • 最终一致性:保证在经过一段时间后最终会达到一致性的特殊弱一致性。

分布式事务

事务具有 ACID 特性:

  • A 原子性:要么成功,要么失败,没有中间状态。
  • C 一致性:事务执行前后,数据库完整性约束不会被破坏。
  • I 隔离性:不同事务之间不会相互影响。
  • D 持久性:一旦事务提交,数据将持久保存。

分布式事务是指在分布式系统上实现事务,同样需要保证 ACID,尤其是一致性。 分布式事务保证强一致性,但牺牲可用性。

2PC 协议

  • 2PC协议用于实现分布式事务,用于保证分布式系统的强一致性。
  • 2PC是两阶段提交,分为准备阶段和提交阶段。
  • 其关键点是,在准备阶段尽可能完成所有工作,而提交阶段将是耗时极短失败概率小的操作。
  • 其实现,必须存在一个中心化的协调者,负责协调参与者的行为。
  • 如果协调者单点故障将出现数据不一致现象。

3PC 协议

  • 3PC协议是2PC的改进,目标与2PC相同。
  • 3PC是三阶段提交,分为准备阶段、预提交阶段和提交阶段。
  • 对比2PC,3PC对协调者和参与者都设置了超时时间,在参与者等待提交超时后会自动提交。
  • 在提交阶段,如果协调者发出回滚,但参与者失联会提交,则出现数据不一致情况。

TCC 协议

  • TCC是业务层面的2PC,而2PC和3PC都是分布式数据库事务的协议。
  • TCC是Try-Confirm-Cancel。
  • Try 阶段是准备阶段尽可能完成所有工作,都成功则 Confirm,否则 Cancel。
  • Confirm 和 Cancel 必须保证幂等,而且 Cancel 允许空回滚。

BASE 理论

BASE 是对 CAP中一致性和可用性权衡的结果,核心思想是即使无法做到强一致性,但可以根据自己的业务特点,采用适当的方式达到最终一致性。 BASE 来源于对大规模分布式系统实践的总结。

  • BA是 Basically Available,基本可用
    • 如损失响应时间
    • 如保证核心功能可用,损失部分功能的可用性
  • S是 Soft State,软状态
    • 允许系统中的数据存在中间状态,并认为该中间状态不会影响系统整体可用性。
  • E是 Eventually Consistent,最终一致性
    • 所有数据副本经过一段时间后,最终会达到一致

共识算法

  • 共识算法是对 BASE 理论的实践。
  • 目标是使分布式系统在出现各种异常(网络故障、节点故障、网络分区等)时,仍然能够达成最终一致。
  • 共识算法和分布式事务区别:分布式事务保证绝对一致性牺牲可用性,而共识算法通过保证共识达成最终一致性。
  • 常见共识算法有 Paxos、Raft。
  • Paxos 和 Raft 都是解决非拜占庭容错问题,即不存在恶意节点伪造信息。
  • Paxos 是最早提出的共识算法,比较复杂。
  • Raft 比较新,相对简单。Raft 是当前分布式系统的首选算法。

Paxos 算法

  • Paxos 算法是分布式系统中实现一致性的算法。
  • 基本思想
    • 将节点分为提议者、接受者、学习者。
    • 提议者提出提案,接受者接受提案并投票,学习者学习已经达成一致的提案。
    • 需经过多轮的消息交换和投票产生一个大家认可的值,然后所有节点执行操作最终达成一致。
  • 优点
    • 较高容错性,能容忍节点故障和网络延迟
    • 较高扩展性,适应不同规模的分布式系统,从几个节点到几千个节点
  • 缺点
    • 复杂型,理解和实现有一定难度
    • 性能,多轮消息交换有性能开销
  • Zookeeper 的zab 算法基于 Paxos 算法改进而来。

Raft 算法

  • 比 Paxos 更具可理解性。
  • 通过 Leader 选举、心跳机制、日志复制等方式来维护数据一致性。
  • Etcd 采用 Raft。

算法细节:

  • 日志复制
    • 基于复制状态机模型实现
    • 相同的初始状态 相同的输入=相同的结束状态
    • 相同的输入通过操作日志实现
  • Leader 选举
    • 节点角色
      • 领导,负责提交日志,并广播日志
      • 跟随者,负责日志复制
      • 候选人,竞选 Leader
    • 任期
      • 作为逻辑时钟,通过任期 ID 识别过期信息
      • 节点之间通信会对比任期,更新到最大
    • 心跳机制
      • 领导节点通过广播心跳给其他节点
      • 其他节点收到心跳后重置定时器,定时器过期后认为领导不存在开始选举
    • 选举过程
      • 跟随者将自己的任期 ID 加 1,标记自己为候选人,向其他节点拉票。
      • 其他节点根据先到先得原则投票,票数超过节点数的一半则当选。
      • 收到宣称领导的信息时,对比任期 ID 来接受或拒绝。
      • 如果一轮出现多个候选人且票数一样则无法得出领导人,会再次选举。
  • 写入过程
    • 只有 Leader 节点可以处理写入请求。
    • Leader 收到请求后,将请求添加到日志中,然后向其他节点复制日志。
    • 只有超过一半节点复制成功 Leader 才认为写入成功。
  • 读取过程
    • Raft 共识算法本身并不保证读取的强一致性,需使用额外的手段。
    • 如确保 Leader 的最新日志已复制到当前节点再读取,才能保证强一致性。

一致性哈希

哈希算法在分布式集群中的应用场景:

  • 请求的负载均衡,对于请求IP进行哈希,然后对集群节点数取模,可以映射到具体节点上。
  • 分布式存储,对 key 值取哈希,然后对集群节点数取模,可以锁定到具体节点上。

普通哈希算法,如果节点数发生变更(故障或扩容),则映射关系会大量失效:

  • 请求的负载均衡,会路由到其他节点,导致原会话丢失。
  • 分布式存储,需要迁移大量数据。

使用一致性哈希,可以避免映射关系大规模失效。

算法要点:

  • 将节点标识和请求 key 的都进行哈希,然后对 2 ^32 取模,映射到 [0, 2^32-1] 上一个值上。
  • [0, 2^32-1]形成了一个哈希环,从 key 的位置在环中顺时针找到第一个节点则是映射的目标节点。
  • 为防止分布不均,将节点映射成多个虚拟节点,再将虚拟节点映射到环上。

幂等

  • 幂等是指对同一操作发起多次请求时,对系统状态的影响是一致的。
  • 分布式系统中,接口有三态问题(成功、失败、超时),为提高系统可靠性,重试是不可避免的。
  • 通常查询和删除操作具有幂等性,而新增和修改操作不具有幂等性。
  • 将非幂等操作转换为幂等的方法:
    • 唯一约束,生成全局唯一ID(UUID 或雪花算法),利用数据库唯一约束进行防重。
    • 乐观锁,对数据加版本号,写入时把之前读取的版本号作为条件同时对版本号加 1。
    • 防重token,操作前先获取 token,操作时服务端通过token 判断是否重复提交。

分布式锁

  • 锁用于控制多线程对同一个资源的并发访问,将访问串行化,避免相互干扰。
  • 分布式锁是在分布式系统中实现的锁,控制不同节点上对同一资源的并发访问。
  • 分布式锁的实现,本质是通过将锁保存在节点外的共享存储中来实现,如:
    • 数据库悲观锁
    • 数据库乐观锁
    • 基于Redis的分布式锁
    • 基于Zookeeper或 Etcd 的分布式锁

分布式系统的通信

RPC

RPC(Remote Procedure Call),远程过程调用,用于将网络通信简化为本地函数调用。 RPC 可以使分布式应用内部通信更加简单高效。 RPC 是一种方法论,RPC 协议是一组规范或标准,而 RPC 框架则提供了基于协议的实现。

RPC 协议构成
  • 接口标准,如通过特定IDL 来定义接口。
  • 传输协议标准,如通过TCP、HTTP进行网络传输。
  • 序列化协议,如通过JSON、ProtoBuf等进行序列化。
RPC 框架构成
  • 客户端接口存根,代理客户端调用。
  • 网络传输模块,利用传输协议处理客户端和服务端的数据传输。
  • 序列化模块,将请求和返回值转换为网络传输的数据。
  • 服务端接口存根,监听网络请求处理服务端调用发送处理结果。
  • 框架以客户端和服务端的依赖库、代码生成工具集等形式提供。
一次 RPC 调用的流程
  • 客户端以本地函数调用方式调用服务。
  • 客户端存根收到请求将方法、入参等信息序列化成能够网络传输的消息体。
  • 客户端存根找到远程的服务地址,将消息通过网络发送给服务端。
  • 服务端存根收到消息进行反序列化,然后调用本地服务进行处理。
  • 服务端本地服务处理后返回结果给服务端存根。
  • 服务端存根序列化结果并发送给客户端。
  • 客户端存根收到消息进行反序列化。
  • 客户端获得最终结果。
服务端IO模型
  • 同步阻塞IO:线程阻塞,直到有数据才恢复。
  • 同步非阻塞IO:线程不阻塞,需要轮询判断是否有数据。
  • 同步多路复用IO:一个线程监听多个 IO,哪个有数据了就交给对应线程处理。
  • 异步IO:内核直接将数据复制到用户空间。
服务端线程模型
  • 单线程模型
    • 一个线程处理所有请求
    • 同个时间只能处理一个请求
    • 仅开发调试用
  • 多线程短连接模型
    • 一个线程处理一个请求,完成后关闭连接
    • 有多少并发请求就有多少线程,线程数有限
    • 频繁建立网络连接开销大
  • 多线程长连接模型
    • 一个线程处理一个连接上的多个请求,服务端不关闭连接。
    • 请求频率低时浪费资源,并发量大时无法处理。
  • 线程池模型
    • 提前创建好一定数量的线程,请求来了分配给空闲线程处理。
    • 本质上是生产者-消费者模型
    • 同样可以支持短连接或长连接。
服务端 reactor 模式
  • 在多路复用IO模型的epoll方式基础上的模式。
  • reactor 为反应堆,表示一个多路复用器。
  • 单 reactor 单线程模式:
    • 只有一个主线程运行 reactor(一个epoll) 和处理事件。
  • 单 reactor 多线程(协程)模式:
    • 一个主线程运行 reactor(一个epoll),通过工作线程(或协程)处理事件。
  • 主从 reactor 多线程模式:
    • 一个主reactor负责建立连接,多个从reactor负责处理 IO 操作。
常用 RPC 框架
  • gRPC
    • Google 开发的开源 RPC 框架,属于云原生 CNCF 的一部分。
    • 通过 protobuf 定义接口,支持为各种开发语言自动生成客户端和服务端存根。
    • 高性能,支持二进制序列化协议。
    • 通信协议基于 HTTP2,支持双向流,消息头压缩,多路复用,服务端推送等。
    • 支持请求响应式和流式 RPC。

消息队列

  • 消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递。
  • 消息发布者只管发布消息,消息是否到达队列取决于消息队列本身的功能和稳定性。
  • 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。
  • 常用的消息队列有 RabbitMQ,Kafka,RocketMQ 等。

分布式系统中间件

Etcd

  • 是分布式一致性的键值对存储系统。
  • 适用于存储分布式系统中的控制数据或少量变更频繁的应用数据。
  • Go开发,Apache开源协议。
  • 特点:
    • 简单:基于 HTTP JSON 的 API,用 curl 命令就可以使用。
    • 安全:可选SSL认证机制。
    • 快速:官方给的 QPS 测试数据相对较高。
    • 可信:使用 Raft 算法实现分布式一致性。
  • 适用场景:
    • 服务发现。
    • 消息发布与订阅。
    • 负载均衡。
    • 分布式锁,分布式队列
  • 业界应用:
    • k8s使用etcd存储docker集群的配置信息。
    • apisix使用etcd存储配置信息。
  • etcd对比zookeeper:
    • 一致性协议:etcd使用raft,zk基于paxos,raft更简单。
    • 运维:etcd容易,zk难。
    • 社区活跃度,etcd比较活跃。
    • api:etcd提供 http json,gRPC接口,zk 需要使用客户端。
    • 安全:etcd支持ssl,zk不支持。
  • etcd对比redis:
    • 定位不同,etcd目标是分布式系统配置数据一致性,redis目标是内存数据库。
    • 数据持久性:前者可以确保数据不丢失,后者虽然也提供持久化机制但极端场景仍然会丢失。
    • 数据一致性:前者通过raft保证分布式各节点强一致性,后者属于单一结点设计,仅支持主从复制不支持强一致性。
    • 数据类型和模型:前者模型相对简单,后者提供复杂结构适应更多场景。
  • etcd 的 watch 原理:
    • v2:使用 HTTP1协议,每一个 Watcher 对应一个TCP长连接,通过轮训来获取最新的变化事件。
    • v3:基于 HTTP2的 gRPC 自己双向流的 WatchAPI,服务端向客户端流式推送。

0 人点赞