分布式理论入门

分布式架构

image-20220115114435674

理论基础

CAP原则

在分布式系统中,CAP不能同时保证,所谓的CAP就是

  • C(Consistency):数据一致性。分布式系统中,数据会有副本。由于网络或者机器故障等因素,可能有些副本数据写入正确,有些却写入错误或者失败,这样就导致了数据的不一致了。而满足数据一致性规则,就是保证所有数据都要同步。
  • A(Availability):可用性。我们需要获取什么数据时,都能够正常的获取到想要的数据(当然,允许可接受范围内的网络延迟),也就是说,要保证任何时候请求数据都能够正常响应。
  • P(Partition Tolerance):**分区容错性。**当网络通信发生故障时,集群仍然可用,不会因为某个节点挂了或者存在问题,而影响整个系统的正常运作。

在分布式系统中最多只能实现其中俩个,而且分区容错性是必须的(因为在分布式系统中,存在某一节点出错是大概率的),所以数据一致性和可用性只能满足一个

BASE 理论

BASE 是 Basically Available(基本可用)Soft-state(软状态)Eventually Consistent(最终一致性) 三个短语的缩写。

  • **基本可用:**在分布式系统出现故障,允许损失部分可用性(服务降级、页面降级)。
  • 软状态: 允许分布式系统出现中间状态。而且中间状态不影响系统的可用性。这里的中间状态是指不同的 data replication(数据备份节点)之间的数据更新可以出现延时的最终一致性
    • 要求多个节点的数据副本都是一致的,这是一种 “硬状态”
  • **最终一致性:**data replications 经过一段时间达到一致性。
    • 最终一致性需要一段时间使得分区达到同步状态
      • 因果一致性因果一致性是指,如果进程A在更新完某个数据项后通知了进程B,那么进程B之后对该数据项的访问都应该能够获取到进程A更新后的最新值,并且如果**进程B要对该数据项进行更新操作的话,务必基于进程A更新后的最新值,即不能发生丢失更新情况。**与此同时,与进程A无因果关系的进程C的数据访问则没有这样的限制。
      • 读己之所写:读己之所写是指,进程A更新一个数据项之后,它自己总是能够访问到更新过的最新值,而不会看到旧值。也就是说,对于单个数据获取者而言,其读取到的数据一定不会比自己上次写入的值旧。因此,读己之所写也可以看作是一种特殊的因果一致性。
      • 会话一致性:会话一致性将对系统数据的访问过程框定在了一个会话当中,系统能保证在同一个有效的会话中实现“读己之所写”的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。
      • 单调读一致性:单调读一致性是指如果一个进程从系统中读取出一个数据项的某个值后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。
      • 单调写一致性:单调写一致性是指,一个系统需要能够保证来自同一个进程的写操作被顺序地执行。

BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。

数据一致性

分布式事务

  • 前面说到分布式系统中,分区容错是必须的,BASE理论对于数据一致性和可用性分别作出一定妥协;无论是强一致性还是最终一致性和软状态均要保证事务必须在整个分布式系统中符合ACID原则
  • DTP模型
    • AP(Application 应用程序):用于定义事务边界(即定义事务的开始和结束),并且在事务边界内对资源进行操作
    • TM(Transaction Manager 事务管理器):负责分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚等
    • RM(Resource Manager 资源管理器):如数据库、文件系统等,并提供访问资源的方式
    • CRM(Communication Resource Manager 通信资源管理器):控制一个TM域(TM domain)内或者跨TM域的分布式应用之间的通信
    • CP(Communication Protocol 通信协议):提供CRM提供的分布式应用节点之间的底层通信服务
    • XA 规范最重要的作用就是定义 RM(资源管理器)与 TM(事务管理器)之间的交互接口;
  • 根据这个模型:分布式事务需要
    • leader:确定事务顺序发起事务请求监控事务进度提交或者回滚事务
    • 可靠的协议:节点通信协议(CP)分布式系统模型协议(系统容错协议)
    • 注册中心资源管理器、统一配置中心

2PC和3CP

2PC和3PC均有一个leader和一群follower组成,leader负责协调,follower负责具体事务的处理

image-20220311160454036
  • 2PC(强一致、中心化的原子提交协议)
    • 主要分为两个阶段:投票阶段、执行阶段
      • 投票阶段:1.leader收到事务处理请求;2.向所有的follower发送该事务;3.所有follower尝试执行该事务,执行成功则返回yes,否则or;
      • 执行阶段(提交阶段)
        • 如果在规定时间内leader收到所有follower返回yes,向所有的follower发送commit;follower收到Commit请求之后,就会正式执行本地事务Commit操作,并在完成提交之后释放整个事务执行期间占用的事务资源。(下面示例)
        • 如果超时没有收到YES,或者收到任意一个节点发回NO,则向follower发出rollback,follower接收到RoollBack请求后,会回滚本地事务。
    • img
    • 缺陷
      • **高度依赖leader、leader容错性非常差;**后面的问题都是由于这个原因产生的
        • 类似于一开始的NIO的主从模式,不过NIO主从模式是高度依赖从线程(如果从线程一直读不到,将导致主线程阻塞);
      • 二阶段提交存在着诸如同步阻塞、单点问题、脑裂等缺陷
      • 同步阻塞:所有参与节点都是事务阻塞型的。显然当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
      • 单点故障:如果协调者在第一阶段提交后第二阶段commit或者rollback前故障,参与者会一直阻塞下去;
      • 数据不一致:由于commit发出后,协调者宕机,只有部分参与者commit,将出现数据不一致,而且要是恰好接收到commit的也宕机,选举出来的leader将无法确定commit是否完成;
      • 脑裂问题:协调者出现故障,选举新协调者的过程中,原协调者复活,出现多个协调者;
  • 3PCCanCommit、PreCommit、DoCommit三个阶段,3PC主要是加入了follower的超时机制
    • CanCommit:和2PC一样;
    • PreCommit:和2PC第二阶段几乎一样,但是多了follower的超时机制;
      • 协调者成功接受所有的follower的返回YES,发出PreCommit,否则(超时或者有NO)发出中断指令;
      • **从节点如果在一定时间内没有接收到可以进入PreCommit或者接受到中断阶段的指令,中断事务;**如果接受到PreCommit,执行事务(写入undo log)返回ASK
    • DoCommit:在doCommit阶段,如果参与者成功进入PreCommit后无法及时接收到来自协调者的doCommit或者abort请求时,会在等待超时之后,会继续进行事务的提交
      • 成功:
        • 发送提交请求 协调接在preCommit阶段收到全部参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求
        • 事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
        • 响应反馈 事务提交完之后,向协调者发送Ack响应
        • 完成事务 协调者接收到所有参与者的ack响应之后,完成事务。
      • 失败
        • 中断事务协调者在preCommit阶段没有接收到全部参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
        • 发送中断请求 协调者向所有参与者发送abort请求
        • 事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
        • 反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息
        • 中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。
    • 缺陷
      • 3PC基本解决了2PC高度依赖主节点的问题,**但是核心问题是:完全不具有分区容错性,但是又不能确保数据绝对一致性;**没有实现CAP理论,也没有实现BASE理论的基本要求;
        • 3PC类似NIO的从节点轮询加上了超时时间,避免一直阻塞;但是正如NIO可能出现虚假唤醒导致CPU使用率飙升100%,3PC由于没有解决分区容错和数据一致性,可能出现节点挂机后**,数据不一致以及事务疯狂请求、回滚;**
      • 数据不一致和脑裂问题
      • 脑裂问题依然存在;即在部分参与者收到PreCommit请求后等待最终指令,如果此时协调者无法与参与者正常通信,会导致部分参与者继续提交事务,造成数据不一致。
总结
  • 2PC和3PC都是试图实现数据一致性,忽略高可用,但是无论是2PC还是3PC均没有实现数据一致性,而且没有分区容错性;

Paxos

相关概念
  • 要点:基于BASE理论
    • 基本可用:允许分区容错导致系统服务不可用,但是可以自主恢复,表现为基本可用;

      • 服务不可用:在主节点单点故障期间,重新选择主节点期间不可用;
      • 基本可用:系统自主选择主节点,选择完毕后自动恢复服务;
    • 软状态:集群节点的数据在一定时间段内允许不同步

      • 数据的更新只需要超过半数节点统一,其他节点可能延后;
    • 最终一致性:集群节点的数据最终会同步

      • 延后的节点数据通过同步算法,在一定时间内会自动同步数据,系统恢复一致性状态;
三个角色

Paxos不要求每个节点只担任一个角色,但是所有节点都有一个角色,例如单机系统本质就是一个节点担任全部角色

  • Proposer:主节点,Paxos算法的主节点和2PC、3PC没有什么区别,担任DTP理论的事务管理器的角色;但是Paxos不要求只有一个主节点;
  • Acceptor:从节点,在DTP理论中担任资源管理器的角色,从节点和2CP、3PC的功能也没有任何区别;
  • learner:选举投票节点
两次协商
约定
分代理论

在选主过程中,并不能保证一次选主成功;为了避免出现明朝的剑砍清朝的官,所以需要通过约定限制一轮投票的作用时间

  • 一个Proposer没有出现故障。则始终处在当前分代
  • 需要选主的时候:
约定(规则)

算法

一致性hash算法
基础
  • 传统的hash算法和节点数具有强相关性,节点数的变化将会使得将深刻影响分布式系统中的数据;
    • 传统hash是通过hash值对节点求余得到;如果节点断连(或者故障)那么所有数据都要重新hash,否则将丢失一部分数据;
  • 一致性hash算法:将所有的节点排列在收尾相接的hash环上,**每个key在计算Hash后会顺时针找到临接的节点存放。**而当有节点加入或退出时,仅影响该节点在Hash环上顺时针相邻的后续节点。
  • 加入虚拟节点的一致性hash算法:
    • 由于hash环的节点数对于数据存储具有很大的影响,当节点数比较小的时候,一个节点失效将导致大量缓存失效(然后流入下一个节点),而hash环节点又不是均匀的可能会使得一个节点负载远大于其他节点;
    • 为了避免这种现象,引入了虚拟节点的概念:
      • 虚拟节点:每一个服务节点计算多个 Hash,每个计算结果位置都放置一个此服务节点,这样一个节点就会在hash环上被映射到多个位置(虚拟节点越多,hash环节点的越均匀,但是一台服务器断连后需要迁移的节点也越多)。
实现
  • 初始化环:首先将各个节点映射到2^31-1次方的桶上,这样每个节点就负责 2^31-1的一部分;
    • image-20220410174654733
  • 数据保存:每一个key的顺时针方向最近节点,就是key所归属的缓存节点
  • 环结构改变:
    • 增加:当增加节点(例如node4到node1间增加节点时)只会影响俩个节点中间的数据,或者说,只需要检查插入位置顺时针下一个节点的key;
    • 删除:同理该节点失效后只会影响其下一个节点;
  • 虚拟节点:虚拟节点使得一个物理节点对应多个环映射节点;

设计理念

  1. 系统业务解耦系统分拆的目标是分布式的基础;
    • 系统拆分:一般可以分为按模块、分层的思路拆分系统
    • 数据一致性:数据的一致性要求是分布式系统的重要组成,数据一致性一般基于Paxos算法的各种简化版实现;
  2. 系统容错尽可能避免系统架构和业务层而引起的不稳定
    • 服务降级
    • 熔断和限流
    • 幂等
    • 异步处理
    • 事务补偿
  3. 高可用更快的发现故障,更快的隔离故障
    • 负载均衡

数据一致性和高可用具有矛盾性,我们知道高可用往往需要冗余,而冗余很容易导致数据不一致;

高可用
  • 冗余+无状态+自动冷热切换是实现高可用的主要手段负载均衡主要实现方式:对负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,在高可用相较于负载均衡关键是管理可用的服务(上线或下线服务、服务恢复、数据备份等等)
  • 为了实现高可用至少需要同时提供负载均衡管理和服务管理:
    • 负载器:专门对于请求进行使用负载均衡策略选择服务
    • 注册器和管理器(注册中心):管理所有的服务和负载管理器(当然也可以顺便管理其他注册和管理器),清除无效的注册项;
      • 心跳检测:Keepalived(实现)和Heartbeat(实现)是常用的俩种服务可用监控算法;

俩者是实现负载均衡最基本的组件,先了解注册器和管理器

注册器和管理器器

​ 这里的注册器和管理器就是我们说的注册中心,注册中心至少需要有以下功能:

  • 维护注册中心列表:简单来说服务注册列表就是服务名和服务地址的对应
  • 实现服务注册和发现:最基本的功能;
  • 服务检查:通过策略检查服务是否可用;

在学习springBoot和springCloud的时候学习过3个注册中心:zookeeper、eureka、nacos、consule,注册中心对比如下:

image-20220115115149999

​ 上面的注册中心主要围绕:CAP原则,需要CP还是AP,其次就是和当前的系统容错(服务降级等)集成及负载均衡策略;

负载器

​ 负载器或者说负载均衡器,通过指定的策略(负载均衡算法)选择服务;

负载均衡算法主要包括:

  • 轮询:轮流循环的将请求的服务发到注册列表的中对应的该服务;这种轮询不考虑设备的差异;
  • 加强轮询:设置一个权重,根据权重确定一次轮询(循环)该服务节点可以分配的请求的数量;这种轮询不考虑不同请求执行的时间
  • hash算法将客户端的源地址,端口进行哈希运算,根据运算的结果转发给一台服务器进行处理这样同一台设备的请求除非出现服务不可用,否则将一直使用该服务器的服务;
  • 一致性hash算法:
  • 随机算法:每次随机选择一个服务器的该服务;
  • 最短响应时间:选择所有该服务中,响应时间最短的服务器的该服务;
  • 最小连接数:选择所有该服务中,连接数量最少的服务器的该服务;
  • 加权最小连接数:为所有服务器的服务连接设置权值;
系统容错

服务降级、熔断和限流是系统容错的主要表现,他们共同避免出现系统雪崩(即由于一个服务出现问题导致其他服务请求激增进而整个系统该服务的服务器均不可用);

服务限流

限流主要针对短时高并发的情况,服务限流通过对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致系统运行缓慢或宕机,限流的根本目的是为了保障服务在短时高并发下的高可用。

  • 流量计数器显然这是一个非常优秀且容易实现的方法,我们设定一段时间(起点设置为0,到终点前如果请求超过阈值则限流); 例如限制一秒钟的能够通过的请求数为100,则在接下去的1s内,每来一个请求,计数加1,如果累加的数字达到了100,那么后续的请求就会被全部拒绝。等到1s结束后,把计数恢复成0,重新开始计数。

    • 该算法的最大问题是如果在周期后段有大量请求进入但未达到限流标椎,然后开启新周期,这时重新开始计数,显然这会又会进入到限流为止(这样系统最大并发就是两倍限流才能稳定运行)
  • 漏桶算法:**内部有一个容器,类似生活用到的漏斗,当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。**这样系统总的处理速度是稳定的;

    • 无法应对短时间的突发流量,而且对于桶的大小设置也是个问题,太大了将使得后面的请求延迟非常高,太小了则频繁的丢弃请求。
  • 令牌桶算法存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌,如果桶中令牌数达到上限,就丢弃令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。

    • 该算法解决了前面俩个算法的不足,既能应对短时流量,又能避免计数器中,2倍最大并发的不足;但是令牌桶算法显然基于生产者消费者模型,所以需要一个支持高并发的容器用于统计和计数;
服务熔断

​ 服务熔断则是针对服务不可用或者高延迟导致可能出现服务雪崩,拖垮整个系统;例如:

image-20220402152519073
  • 熔断需要一个:统计器、恢复机制、熔断处理策略;
  • 熔断也可以通过计数器的方法进行统计(服务响应时间超时次数在一段时间的次数);熔断最重要的是熔断的恢复和熔断处理
    • img
    • Hystrix策略:
      • 在熔断管理器中(注册中心)服务有三种状态:熔断(关闭)、半开、可用(开启)
        • 计数器在一定时间内发现对该请求的响应时间超时达到一定次数:标记该服务为熔断,后续调取该服务则使用熔断策略的方法
        • 熔断管理器每个一段时间会将熔断服务重新标记为半开,允许调取(一次)服务,**服务标记为半开下,**下次调取是否能在限制时间内返回响应决定是否继续熔断(或者变为可用)
        • 可用状态下,所有请求都调取服务,根据响应决定是否需要熔断;
    • 熔断处理:根据策略处理
服务降级
  • 前面(熔断、限流)主要聚焦服务端服务器整个服务的容错,而服务降级主要聚焦服务的某一些核心服务功能的容错
  • 服务降级:当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心服务运作
    • 由于服务降级会使得非核心服务熔断,所以确定核心服务非常关键;
    • 非核心服务降级后(本质就是熔断),通过熔断机制恢复;
    • 当核心服务也触发熔断的条件,整个则整个服务器的服务熔断;

集群恢复

  • 后面学习过程中将会不断的出现:单点故障、集群恢复

分布式事务

  • 事务是一个很重要的概念,在单机模式下,只需要使用Spring框架进行事务控制即可,但是在分布式架构中,事务可能设计多个微服务,这时就需要分布式事务协调全局事务;
    1. 在面试时,面试官问:x提交了博文,但是由于服务超时,导致dubbo重试(实际已经持久化到redis),这时博客会不会再次被提交(显然会)
      • 我的回答:加入一个全局事务id到消费者中,每次检查是否存在该id,则可以避免(存在则无需再次提交,直接返回成功)
    2. 这里只保证了成功,如果失败了呢(就是x持久化了,但是后面其他操作可能涉及其他微服务,怎么保证全局一致);所以就有了下面的学习

分布式事务

在这里插入图片描述
  • 在分布式事务中,主要涉及两大类RM(资源管理器):
    • 完整支持事务的关系数据库(MySQL等)
    • 非完整支持事务的数据库及部分消息中间件(特别是redis、众所周知,redis的事务本质就是管道命令,不支持回滚)

事务模型

image-20220517194739854
XA模型
  • 基于两阶段提交的模型,显然需要RA本身支持两阶段提交(否则将无法回滚)
AT模型
补偿机制
  • 事务补偿不依赖RA实现事务,需要在业务层面进行;在补偿机制中:
    • 尽力完成整个事务(尽可能提交):多次尝试需要保证幂等
    • 根据不同的事务规则进行回滚,允许中间状态;
    • 不依赖RA实现全局事务,通过逻辑代码进行补偿处理
TCC模型
  • TCC将事务分成2阶段:
    • Try:尝试提交
    • confirm:确认提交
    • cancel:取消回滚(如果try或者confirm失败)
  • 三个接口:由于TCC将全局事务分为三个阶段,所以需要三个业务接口分别处理这三个逻辑
    • Try:本地事务处理接口,即事务进行局部提交,在本地中数据将进行一致性变化将变化结果或者过程保留进行预留
    • confirm:后续的微服务及本地事务没有回滚,进行最终提交(将数据由预留变为实际操作),为了保证全局一致性,要求 Try 成功 Confirm 一定要能成功。(因为后续微服务已经提交)
    • cancel:回滚接口,将本地事务(局部已提交)进行回滚操作,释放预留资源,恢复全局一致性;
      • 空回滚:部分事务可能会因为锁超时等导致需要回滚,但是并未执行预留,这时需要空回滚;
SAGA模型
  • SAGA模型是TCC事务补偿的AOP版本,因为在TCC模型中,需要逻辑业务代码嵌套实现,但是旧系统和涉及外部调用则无法使用;
  • SAGA模型:**将TCC的第一二阶段交给本地事务进行处理,**SAGA只进行冲正补偿(即回滚);
    • 分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会去退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。
  • 由于这种方式完全不进行全局事务控制(原子、隔离性),只保证最终一致性,所以可能会出现脏读、丢失修改等;

实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

舔猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值