跳转到内容

基础理论

https://dunwu.github.io/blog/pages/80055a/

  • 随机负载均衡
    • 策略 - 将请求随机分发到候选服务器
    • 特点 - 调用量越大,负载越均衡
    • 适合场景 - 适合服务器硬件相同的场景
  • 轮询负载均衡
    • 策略 - 将请求依次分发到候选服务器
    • 特点 - 请求完全均匀分发
    • 场景 - 适合服务器硬件相同的场景
  • 最小活跃数负载均衡
    • 策略 - 将请求分发到连接数/请求数最少的候选服务器
    • 特点 - 根据候选服务器当前的请求连接数,动态分配
    • 适合场景 - 适用于对系统负载较为敏感或请求连接时长相差较大的场景
  • 哈希负载均衡
    • 策略 - 根据一个 key (可以是唯一 ID、IP 等),通过哈希计算得到一个数值,用该数值在候选服务器列表的进行取模运算,得到的结果便是选中的服务器
    • 特点 - 保证特定用户总是请求到相同的服务器,若服务器宕机,会话会丢失
    • 适合场景 - 可以保证同一 IP 的客户端的请求会转发到同一台服务器上,用来实现会话粘滞(Sticky Session)
  • 一致性哈希负载均衡
    • 策略 - 相同的请求尽可能落到同一个服务器上。尽可能是指:服务器可能发生上下线,少数服务器的变化不应该影响大多数的请求。当某台候选服务器宕机时,原本发往该服务器的请求,会基于虚拟节点,平摊到其它候选服务器,不会引起剧烈变动。
    • 优点 - 加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。
    • 缺点 - 加减节点会造成哈希环中部分数据无法命中。当使用少量节点时,节点变化将大范围影响哈希环中数据映射,不适合少量数据节点的分布式方案。普通的一致性哈希分区在增减节点时需要增加一倍或减去一半节点才能保证数据和负载的均衡。
    • 适合场景 - 一致性哈希可以很好的解决稳定性问题,可以将所有的存储节点排列在首尾相接的 Hash 环上,每个 key 在计算 Hash 后会顺时针找到临接的存储节点存放。而当有节点加入或退出时,仅影响该节点在 Hash 环上顺时针相邻的后续节点。

nginx 的负载均衡配置项

redis限流的3种实现方式

1. 分布式应用的迭代过程

  1. 软件早期是单体应用,就是把项目中所有涉及到的模块都放在一起;
  2. 但是后期由于业务量的增加,发现数据库先扛不住了,于是就把单体应用变成两层:
    1. 用于计算的服务层;
    2. 用户存储的存储层;并且存储层逐渐由演化成分库分表的方式;
  3. 后来又发现服务层也无法支撑业务需求了,于是就把单个服务变成集群,并且慢慢的把服务也进一步划分划分成小模块;

单体应用(巨石应用)到分布式应用的迭代思想无非就这么几种:

  1. 拆分(垂直拆分+水平拆分)
  2. 冗余(集群、异地多活)

2. 分布式应用的特点

  • 分布性
    • 部署随机分布,比如淘宝在北京和上海都部署有机房;
    • 功能随机分布;比如淘宝的计算节点一部分在北京,一部分在上海;淘宝的存储节点部署在北京,而运算服务部署在上海;
  • 自治性: 每个节点都包含独属于自己的资源,如 CPU、内存、IO、磁盘等,每个节点对自己的资源进行自行治理的权限。
  • 并发性
    • 分布式系统可以支持并发的请求任务。如北京和上海的两个用户同时访问淘宝,淘宝系统会同时为这两个用户提供服务。
    • 分布式系统内部之间的不同节点会并发的执行任务。如还是两个用户同时访问淘宝,淘宝的负责运算的节点进行运算的同时,可能另外一个存储节点正在执行读取数据的服务。
  • 对等性: 分布式系统中完成不同功能的主机,在角色上并没有主从之分。例如,部署运算服务的主机和存储服务的主机并没有主从之分,但是在单个功能上有主从之分,如 Mysql 的主从复制部署模型;

3. 分布式应用遇到的挑战

系统复杂度与可用性的非线性关系: 引入一个新的组件,意味着系统的复杂度增加,复杂度增加就意味着可用性降低。

作为 Java 程序员,在分布式应用场景下,已经有非常多的成熟方案,这些成熟的方案已经帮我们屏蔽掉底层所遇到的核心问题,因此我们的关注点就变成了“如何站在巨人肩膀上解决分布式应用的业务问题”。这要求我们不但对自己业务非常了解,同时也要求我们对中间件系统非常了解。

所以,分布式应用所遇到的挑战主要有两个:

  1. 如何在众多的中间件系统中找到能够满足自己需求的那一款。-> 技术选型。
  2. 找到满足自己需求的那一款之后,如何更好的使用。 把业务系统和中间件系统分开看,中间件系统可以帮我们屏蔽分布式应用中遇到的问题,但是我们的业务系统本身也属于一个分布式应用,同样也会遇到分布式应用中所遇到的各种各样的问题,因此我们就要在实现业务系统考虑并解决这些问题。

事实上,分布式应用中遇到的问题,本质上可以分成三种:NPC。

  • Network Delay:网络延迟。网络延迟、网络三态(超时、失败、成功)
  • Process Pause:进程暂停。如 JVM 的 STW。
  • Clock Drift:时钟漂移。如极端情况下,运维人员暴力修改系统时钟时间等。

4. 如何做技术选型?

主要包括以下几个方面:

  1. 经济上:时间成本(学习、开发、运维)、资源成本(服务器资源、运营商的经济成本(机房、网络、电力等资源))
  2. 功能上:
    1. 性能需求: 最大 TPS、QPS、SLA、网络延迟、占用的服务器资源(包括 CPU、内存、磁盘存储、IO )等、是否可观测、可维护性、伸缩性、可追踪性、是否支持三高等
    2. 功能需求: 是否满足业务需要
  3. 社区活跃度上:越活跃越好,意味着遇到问题可以直接解决;
  4. 已有经验上:是否经历了生产环境验证、经历了怎么样的生产环境的验证等;

5. 如何更好的使用?

主要考虑两方面:

  1. 自己的业务代码中如何更好的使用中间件?
  2. 中间件解决这些业务场景时的原理、优缺点?

下面问题,可以帮助我们在进行架构设计的时候,考虑的全面些

  1. 网络可靠。考虑网络三态的备用方案;
  2. 延迟为零。
  3. 带宽是无限的。
  4. 网络是安全的。
  5. 拓扑不会改变。
  6. 有一个管理员。
  7. 运输成本为零。
  8. 网络是同质的。

图源:https://deniseyu.io/art/

视频讲解地址在此

图源:https://architecturenotes.co/fallacies-of-distributed-systems/

6. 总结

分布式应用遇到的挑战就是:

  1. 业务系统在分布式场景下的挑战;【技术选型】
  2. 基础设施系统在分布式场景下的挑战;【选好了如何用】

7. 理论基础

8. CAP 理论

9. 内容:

  1. Consistency: 一致性。在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本); XA方案、Paxos算法、ZAB算法、Raft算法、一致性 Hash 算法
  2. Availability: 可用性。在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性);评判标准、心跳检测、异地多活和同城双活、gossip、隔离、限流、负载均衡
  3. Partition tolerance: 分区容错性。以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性, 就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择。日志复制、主备、互备、集群

image.png

一致性是指“所有节点同时看到相同的数据”,即更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致,等同于所有节点拥有数据的最新版本。 可用性是指“任何时候,读写都是成功的”,即服务一直可用,而且是正常响应时间。我们平时会看到一些 IT 公司的对外宣传,比如系统稳定性已经做到 3 个 9、4 个 9,即 99.9%、99.99%,这里的 N 个 9 就是对可用性的一个描述,叫做 SLA,即服务水平协议。比如我们说月度 99.95% 的 SLA,则意味着每个月服务出现故障的时间只能占总时间的 0.05%,如果这个月是 30 天,那么就是 21.6 分钟。 分区容忍性具体是指“当部分节点出现消息丢失或者分区故障的时候,分布式系统仍然能够继续运行”,即系统容忍网络出现分区,并且在遇到某节点或网络分区之间网络不可达的情况下,仍然能够对外提供满足一致性和可用性的服务。

分布式系统中,多个节点之间的网络本来是连通的,但是因为某些故障(比如部分节点网络出了问题)某些节点之间不连通了,整个网络就分成了几块区域,这就叫 网络分区

10. 三者之间的关系:

在分布式系统中,由于系统的各层拆分,P 是确定的,CAP 的应用模型就是 CP 架构和 AP 架构。分布式系统所关注的,就是在 Partition Tolerance 的前提下,如何实现更好的 A 和更稳定的 C。

11. 应用

比如 ZooKeeper、HBase 就是 CP 架构,Cassandra、Eureka 就是 AP 架构,Nacos 不仅支持 CP 架构也支持 AP 架构。选择 CP 还是 AP 的关键在于当前的业务场景,没有定论,比如对于需要确保强一致性的场景如银行一般会选择保证 CP 。

  • ZooKeeper 保证的是 CP。 任何时刻对 ZooKeeper 的读请求都能得到一致性的结果,但是, ZooKeeper 不保证每次请求的可用性比如在 Leader 选举过程中或者半数以上的机器不可用的时候服务就是不可用的。
  • Eureka 保证的则是 AP。 Eureka 在设计的时候就是优先保证 A (可用性)。在 Eureka 中不存在什么 Leader 节点,每个节点都是一样的、平等的。因此 Eureka 不会像 ZooKeeper 那样出现选举过程中或者半数以上的机器不可用的时候服务就是不可用的情况。 Eureka 保证即使大部分节点挂掉也不会影响正常提供服务,只要有一个节点是可用的就行了。只不过这个节点上的数据可能并不是最新的。
  • Nacos 不仅支持 CP 也支持 AP。

12. BASE 理论

BASE 理论open in new window起源于 2008 年, 由 eBay 的架构师 Dan Pritchett 在 ACM 上发表。

13. 简介

BASEBasically Available(基本可用)Soft-state(软状态)Eventually Consistent(最终一致性) 三个短语的缩写。BASE 理论是对 CAP 中一致性 C 和可用性 A 权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,它大大降低了我们对系统的要求。

14. BASE 理论的核心思想

即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。

也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。

BASE 理论本质上是对 CAP 的延伸和补充,更具体地说,是对 CAP 中 AP 方案的一个补充。为什么这样说呢? CAP 理论这节我们也说过了:

如果系统没有发生“分区”的话,节点间的网络连接通信正常的话,也就不存在 P 了。这个时候,我们就可以同时保证 C 和 A 了。因此,如果系统发生“分区”,我们要考虑选择 CP 还是 AP。如果系统没有发生“分区”的话,我们要思考如何保证 CA 。

因此,AP 方案只是在系统发生分区的时候放弃一致性,而不是永远放弃一致性。在分区故障恢复后,系统应该达到最终一致性。这一点其实就是 BASE 理论延伸的地方。

15. BASE 理论三要素

image.jpg BASE理论三要素

15.1. 基本可用

基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。 什么叫允许损失部分可用性呢?

  • 响应时间上的损失: 正常情况下,处理用户请求需要 0.5s 返回结果,但是由于系统出现故障,处理用户请求的时间变为 3 s。
  • 系统功能上的损失:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系统的部分非核心功能无法使用。

15.2. 软状态

软状态指允许系统中的数据存在中间状态(CAP 理论中的数据不一致),并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

15.3. 最终一致性

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

分布式一致性的 3 种级别:

  1. 强一致性:系统写入了什么,读出来的就是什么。
  2. 弱一致性:不一定可以读取到最新写入的值,也不保证多少时间之后读取到的数据是最新的,只是会尽量保证某个时刻达到数据一致的状态。
  3. 最终一致性:弱一致性的升级版,系统会保证在一定时间内达到数据一致的状态。

业界比较推崇是最终一致性级别,但是某些对数据一致要求十分严格的场景比如银行转账还是要保证强一致性。

那实现最终一致性的具体方式是什么呢? 《分布式协议与算法实战》open in new window 中是这样介绍:

  • 读时修复 : 在读取数据时,检测数据的不一致,进行修复。比如 Cassandra 的 Read Repair 实现,具体来说,在向 Cassandra 系统查询数据的时候,如果检测到不同节点的副本数据不一致,系统就自动修复数据。
  • 写时修复 : 在写入数据,检测数据的不一致时,进行修复。比如 Cassandra 的 Hinted Handoff 实现。具体来说,Cassandra 集群的节点之间远程写数据的时候,如果写失败 就将数据缓存下来,然后定时重传,修复数据的不一致性。
  • 异步修复 : 这个是最常用的方式,通过定时对账检测副本数据的一致性,并修复。

比较推荐 写时修复,这种方式对性能消耗比较低。

16. 总结

ACID 是数据库事务完整性的理论,CAP 是分布式系统设计理论,BASE 是 CAP 理论中 AP 方案的延伸。

17. 常用算法

17.1. Paxos

  • WARO 机制 (Write All Read One)

    • 更新数据时,需要对集群内所有节点进行更新,所有节点更新完后,读数据时只需要读取其中一个节点就能保证读到最新数据;
    • 但是这种机制只是保证了读操作的可用性,更新操作的可用性较低,因为只要有一个副本没有更新成功,此次更新操作就失败了;
  • Quorum 机制

    • 是 WARO 机制在寻求 更新操作 和 读操作 可用性的一种平衡;
    • 一个集群中具有N个数据副本,如果写操作时,至少要写w个副本,那么读操作时,至少要读取N-W+1个副本,才保证能读到最新的数据;
  • WARO 与 Quorum 区别

    • CAP中P是客观存在的,那就需要对C和A进行取舍,多发生在更新所有副本数据的业务场景下;
    • WARO 保证了系统具有强一致性(所有的副本数据相同),但是牺牲了可用性(只有所有副本写成功后才算成功,否则就是失败);
    • Quorum 保证了系统具有一致性(但不需要所有的副本数据相同),又兼顾了可用性(只写n个副本,读m-n+1个副本就可以读出更新后的新数据);
  • Paxos 解决了什么问题?

    • 解决了分布式系统中数据一致性问题;
  • Paxos 三种角色的各自作用

    • Proposer 提案者: 负责提出议案;
    • Acceptor 批准者: 负责批准或否决议案;
    • Learner 学习者: 负责对外提供读写能力;
  • Paxos 算法过程

    • 准备阶段
      • Proposer 带着 生成的全局唯一的提案ID( ProposalID ) 发送给所有的 Acceptor ;
      • Acceptor 收到请求后,判断 ProposalID 是否与之前响应过的所有提案的ID还要大:
        • 是:
          • 持久化 ProposalID ,并记录为 最大ID( Max_N );
          • 回复请求,并带上 ProposalID 对应的 value ;
          • 承诺不会接受 ID值 比 ProposalID 还要小的提案,
        • 否:
          • 不回复或回复error
    • 选举阶段
      • Proposer 判断 Acceptor 的回复情况:
        • if (( 回复数量 > 一半的 Acceptor 数量 ) && ( 所有回复的 value 都为空【这种情况,表明还没有被Accept的提案】 )): Proposer 带着自己指定的 value 发给 Acceptor ;
        • if (( 回复数量 > 一半的 Acceptor 数量 ) && ( 有的value不为空 )) : Proposer 带上上一步回复的 value 发给 Acceptor;
        • if ( 回复数量 < 一半的 Acceptor 数量 ) : 尝试生成更大的 ProposalID ;
      • Acceptor 判断收到的 ProposalID 与本地存储的 Max_N 的大小关系:
        • if( ProposalID >= Max_N) : 回复提交成功,并持久化 value;
        • else : 不回复或回复失败;
      • Proposer 统计提交回复结果 :
        • if ( 回复数量 > 一半的 Acceptor 数量 ) : 表示提交 value 成功,此时回发送广播给所有的 Proposer 、 learner ,通知它们已提交的 value;
        • if (( 回复数量 <= 一半的 Acceptor 数量 ) || ( 收到一条失败回复 )) :  尝试生成更大的 ProposalID ,并转到【准备阶段】;
  • 举例说明

  • Paxos 面试题

    • 半数以内Acceptor失效怎么办?两种情况
      • 如果失效前还没有确定最终的 value,那就重新竞争提案;
      • 如果失效前已经确定了最终的 value,说明已经达到共识,那么所有的 Proposer 都以这个 value 作为最终值;
    • Acceptor 需要接受更大的ProposalID的意义是什么?
      • 有点类似于 DB 中的版本号,数值大的才可以获得权限;目的在于减少阻塞问题的发生;
    • 如何产生唯一的 ProposalID?
      • 只要所有的 ProposalID 是从不相交的数据集中获取即可;
      • 可以使用机器号+步差,如五个主机,每次递增 1,那么就用主机 id+1 的方式表示;也可以使用 ServerID+时间戳;
  • 选举阶段: Proposer 发送 (ProposalID,null)给所有的 Acceptor

    • Acceptor 判断 ProposalID > 本地已经保存的最大的 ProposalID :
    • 是: 返回响应信息,响应信息格式为: (ProposalID,null)
    • 拿到“所有的请求+本地已保存的ProposalID”中最大的 ProposalID ,并带上这个ProposalID 对应的 value 作为响应信息进行返回;

17.2. 一致性 Hash

17.2.1. 出现的背景

以redis集群分片为导语,引入集群扩展性问题,引入hash的缺点,继而引入一致性hash。

  1. 一致性哈希算法(Java实现)
  2. 一致性hash

18. 分布式应用的性能指标

高可用

高性能 购买电脑的时候,我们会问这台电脑的性能怎么样,意思就是在问这台电脑用的体验怎么样、硬件设备的支持的特性和能力到底怎么样? 高性能就是指把整个分布式系统作为一个整体来看,它对外提供给用户的使用体验到底是怎样的。你做一套淘宝系统,我做一套淘宝系统,如果你的系统用户体验比我好,那就可以说你的性能比我的要好。同样的,如果同样的硬件资源,你的也比我的好,那照样可以说你的性能比我的好。主要的衡量指标:同样的业务目标下,资源使用率越小,性能越高。

18.1. 简介

  1. 简单的说,高性能(High Performance)就是指程序处理速度快,所占内存少,cpu占用率低
  2. 高并发和高性能是紧密相关的,提高应用的性能,是肯定可以提高系统的并发能力的。
  3. 应用性能优化的时候,对于计算密集型IO密集型还是有很大差别,需要分开来考虑。
  4. 增加服务器资源(CPU、内存、服务器数量),绝大部分时候是可以提高应用的并发能力和性能 (前提是应用能够支持多任务并行计算,多服务器分布式计算才行),但也是要避免其中的一些问题,才可以更好的更有效率的利用服务器资源。

18.2. 提高性能的注意事项

  1. 避免因为IO阻塞让CPU闲置,导致CPU的浪费。
  2. 避免多线程间增加锁来保证同步,导致并行系统串行化。
  3. 免创建、销毁、维护太多进程、线程,导致操作系统浪费资源在调度上。
  4. 避免分布式系统中多服务器的关联,比如:依赖同一个mysql,程序逻辑中使用分布式锁,导致瓶颈在mysql,分布式又变成串行化运算。

作者:黑爪猫 链接:https://juejin.cn/post/6844903944955625479 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

高并发

19. 参考

  1. 分布式系统 - 理论基础,理论及一致性算法
  2. 理解分布式系统的8个谬误
  3. CAP & BASE理论详解
  4. 分布式系统遇到的十个问题
  5. https://www.cnblogs.com/xybaby/p/7787034.html
  6. https://juejin.cn/post/6844903944955625479
  7. https://bbs.huaweicloud.com/blogs/194361
  8. https://developer.aliyun.com/article/979134

make it come true