关于分布式,你须要知道的真相

目录

  • 1、分布式锁
  • 数据库的惟一索引
  • Redis 的 SETNX 指令
  • Redis 的 RedLock 算法
  • Zookeeper 的有序节点
  • 2、分布式事务
  • 2PC
  • 本地消息表
  • 3、CAP
  • 一致性
  • 可用性
  • 分区容忍性
  • 权衡
  • 4、BASE
  • 基本可用
  • 软状态
  • 最终一致性
  • 5、Paxos
  • 执行过程
  • 约束条件
  • 6、Raft
  • 单个 Candidate 的竞选
  • 多个 Candidate 竞选
  • 数据同步

1、分布式锁

在单机场景下,可使用语言的内置锁来实现进程同步。可是在分布式场景下,须要同步的进程可能位于不一样的节点上,那么就须要使用分布式锁。node

阻塞锁一般使用互斥量来实现:算法

  • 互斥量为 0 表示有其它进程在使用锁,此时处于锁定状态;
  • 互斥量为 1 表示未锁定状态。

1 和 0 能够用一个整型值表示,也能够用某个数据是否存在表示。数据库

数据库的惟一索引

得到锁时向表中插入一条记录,释放锁时删除这条记录。惟一索引能够保证该记录只被插入一次,那么就能够用这个记录是否存在来判断是否存于锁定状态。网络

存在如下几个问题:app

  • 锁没有失效时间,解锁失败的话其它进程没法再得到该锁。
  • 只能是非阻塞锁,插入失败直接就报错了,没法重试。
  • 不可重入,已经得到锁的进程也必须从新获取锁。

Redis 的 SETNX 指令

使用 SETNX(set if not exist)指令插入一个键值对,若是 Key 已经存在,那么会返回 False,不然插入成功并返回 True。分布式

SETNX 指令和数据库的惟一索引相似,保证了只存在一个 Key 的键值对,那么能够用一个 Key 的键值对是否存在来判断是否存于锁定状态。spa

EXPIRE 指令能够为一个键值对设置一个过时时间,从而避免了数据库惟一索引实现方式中释放锁失败的问题。3d

Redis 的 RedLock 算法

使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时仍然可用。日志

  • 尝试从 N 个互相独立 Redis 实例获取锁;
  • 计算获取锁消耗的时间,只有当这个时间小于锁的过时时间,而且从大多数(N / 2 + 1)实例上获取了锁,那么就认为锁获取成功了;
  • 若是锁获取失败,就到每一个实例上释放锁。

Zookeeper 的有序节点

1. Zookeeper 抽象模型

Zookeeper 提供了一种树形结构的命名空间,/app1/p_1 节点的父节点为 /app1。blog

 

 

 

2. 节点类型

  • 永久节点:不会由于会话结束或者超时而消失;
  • 临时节点:若是会话结束或者超时就会消失;
  • 有序节点:会在节点名的后面加一个数字后缀,而且是有序的,例如生成的有序节点为 /lock/node-0000000000,它的下一个有序节点则为 /lock/node-0000000001,以此类推。

3. 监听器

为一个节点注册监听器,在节点状态发生改变时,会给客户端发送消息。

4. 分布式锁实现

  • 建立一个锁目录 /lock;
  • 当一个客户端须要获取锁时,在 /lock 下建立临时的且有序的子节点;
  • 客户端获取 /lock 下的子节点列表,判断本身建立的子节点是否为当前子节点列表中序号最小的子节点,若是是则认为得到锁;不然监听本身的前一个子节点,得到子节点的变动通知后重复此步骤直至得到锁;
  • 执行业务代码,完成后,删除对应的子节点。

5. 会话超时

若是一个已经得到锁的会话超时了,由于建立的是临时节点,因此该会话对应的临时节点会被删除,其它会话就能够得到锁了。能够看到,Zookeeper 分布式锁不会出现数据库的惟一索引实现的分布式锁释放锁失败问题。

6. 羊群效应

一个节点未得到锁,只须要监听本身的前一个子节点,这是由于若是监听全部的子节点,那么任意一个子节点状态改变,其它全部子节点都会收到通知(羊群效应),而咱们只但愿它的后一个子节点收到通知。

2、分布式事务

指事务的操做位于不一样的节点上,须要保证事务的 ACID 特性。

例如在下单场景下,库存和订单若是不在同一个节点上,就涉及分布式事务。

2PC

两阶段提交(Two-phase Commit,2PC),经过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。

1. 运行过程

1.1 准备阶段

协调者询问参与者事务是否执行成功,参与者发回事务执行结果。

 

 

 

1.2 提交阶段

若是事务在每一个参与者上都执行成功,事务协调者发送通知让参与者提交事务;不然,协调者发送通知让参与者回滚事务。

须要注意的是,在准备阶段,参与者执行了事务,可是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

 

 

 

2. 存在的问题

2.1 同步阻塞

全部事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,没法进行其它操做。

2.2 单点问题

协调者在 2PC 中起到很是大的做用,发生故障将会形成很大影响。特别是在阶段二发生故障,全部参与者会一直等待,没法完成其它操做。

2.3 数据不一致

在阶段二,若是协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。

2.4 太过保守

任意一个节点失败就会致使整个事务失败,没有完善的容错机制。

本地消息表

本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操做知足事务特性,而且使用了消息队列来保证最终一致性。

  1. 在分布式事务操做的一方完成写业务数据的操做以后向本地消息表发送一个消息,本地事务能保证这个消息必定会被写入本地消息表中。
  2. 以后将本地消息表中的消息转发到消息队列中,若是转发成功则将消息从本地消息表中删除,不然继续从新转发。
  3. 在分布式事务操做的另外一方从消息队列中读取一个消息,并执行消息中的操做。

 

 

 

3、CAP

分布式系统不可能同时知足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance),最多只能同时知足其中两项。

 

 

 

一致性

一致性指的是多个数据副本是否能保持一致的特性,在一致性的条件下,系统在执行数据更新操做以后可以从一致性状态转移到另外一个一致性状态。

对系统的一个数据更新成功以后,若是全部用户都可以读取到最新的值,该系统就被认为具备强一致性。

可用性

可用性指分布式系统在面对各类异常时能够提供正常服务的能力,能够用系统可用时间占总时间的比值来衡量,4 个 9 的可用性表示系统 99.99% 的时间是可用的。

在可用性条件下,要求系统提供的服务一直处于可用的状态,对于用户的每个操做请求老是可以在有限的时间内返回结果。

分区容忍性

网络分区指分布式系统中的节点被划分为多个区域,每一个区域内部能够通讯,可是区域之间没法通讯。

在分区容忍性条件下,分布式系统在遇到任何网络分区故障的时候,仍然须要能对外提供一致性和可用性的服务,除非是整个网络环境都发生了故障。

权衡

在分布式系统中,分区容忍性必不可少,由于须要老是假设网络是不可靠的。所以,CAP 理论其实是要在可用性和一致性之间作权衡。

可用性和一致性每每是冲突的,很难使它们同时知足。在多个节点之间进行数据同步时,

  • 为了保证一致性(CP),不能访问未同步完成的节点,也就失去了部分可用性;
  • 为了保证可用性(AP),容许读取全部节点的数据,可是数据可能不一致。

4、BASE

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

BASE 理论是对 CAP 中一致性和可用性权衡的结果,它的核心思想是:即便没法作到强一致性,但每一个应用均可以根据自身业务特色,采用适当的方式来使系统达到最终一致性。

基本可用

指分布式系统在出现故障的时候,保证核心可用,容许损失部分可用性。

例如,电商在作促销时,为了保证购物系统的稳定性,部分消费者可能会被引导到一个降级的页面。

软状态

指容许系统中的数据存在中间状态,并认为该中间状态不会影响系统总体可用性,即容许系统不一样节点的数据副本之间进行同步的过程存在时延。

最终一致性

最终一致性强调的是系统中全部的数据副本,在通过一段时间的同步后,最终能达到一致的状态。

ACID 要求强一致性,一般运用在传统的数据库系统上。而 BASE 要求最终一致性,经过牺牲强一致性来达到可用性,一般运用在大型分布式系统中。

在实际的分布式场景中,不一样业务单元和组件对一致性的要求是不一样的,所以 ACID 和 BASE 每每会结合在一块儿使用。

5、Paxos

用于达成共识性问题,即对多个节点产生的值,该算法能保证只选出惟一一个值。

主要有三类节点:

  • 提议者(Proposer):提议一个值;
  • 接受者(Acceptor):对每一个提议进行投票;
  • 告知者(Learner):被告知投票的结果,不参与投票过程。

 

 

 

执行过程

规定一个提议包含两个字段:[n, v],其中 n 为序号(具备惟一性),v 为提议值。

1. Prepare 阶段

下图演示了两个 Proposer 和三个 Acceptor 的系统中运行该算法的初始过程,每一个 Proposer 都会向全部 Acceptor 发送 Prepare 请求。

 

 

 

当 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n1, v1],而且以前还未接收过 Prepare 请求,那么发送一个 Prepare 响应,设置当前接收到的提议为 [n1, v1],而且保证之后不会再接受序号小于 n1 的提议。

以下图,Acceptor X 在收到 [n=2, v=8] 的 Prepare 请求时,因为以前没有接收过提议,所以就发送一个 [no previous] 的 Prepare 响应,设置当前接收到的提议为 [n=2, v=8],而且保证之后不会再接受序号小于 2 的提议。其它的 Acceptor 相似。

 

 

 

若是 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n2, v2],而且以前已经接收过提议 [n1, v1]。若是 n1 > n2,那么就丢弃该提议请求;不然,发送 Prepare 响应,该 Prepare 响应包含以前已经接收过的提议 [n1, v1],设置当前接收到的提议为 [n2, v2],而且保证之后不会再接受序号小于 n2 的提议。

以下图,Acceptor Z 收到 Proposer A 发来的 [n=2, v=8] 的 Prepare 请求,因为以前已经接收过 [n=4, v=5] 的提议,而且 n > 2,所以就抛弃该提议请求;Acceptor X 收到 Proposer B 发来的 [n=4, v=5] 的 Prepare 请求,由于以前接收到的提议为 [n=2, v=8],而且 2 <= 4,所以就发送 [n=2, v=8] 的 Prepare 响应,设置当前接收到的提议为 [n=4, v=5],而且保证之后不会再接受序号小于 4 的提议。Acceptor Y 相似。

 

 

 

2. Accept 阶段

当一个 Proposer 接收到超过一半 Acceptor 的 Prepare 响应时,就能够发送 Accept 请求。

Proposer A 接收到两个 Prepare 响应以后,就发送 [n=2, v=8] Accept 请求。该 Accept 请求会被全部 Acceptor 丢弃,由于此时全部 Acceptor 都保证不接受序号小于 4 的提议。

Proposer B 事后也收到了两个 Prepare 响应,所以也开始发送 Accept 请求。须要注意的是,Accept 请求的 v 须要取它收到的最大提议编号对应的 v 值,也就是 8。所以它发送 [n=4, v=8] 的 Accept 请求。

 

 

 

3. Learn 阶段

Acceptor 接收到 Accept 请求时,若是序号大于等于该 Acceptor 承诺的最小序号,那么就发送 Learn 提议给全部的 Learner。当 Learner 发现有大多数的 Acceptor 接收了某个提议,那么该提议的提议值就被 Paxos 选择出来。

 

 

 

约束条件

1. 正确性

指只有一个提议值会生效。

由于 Paxos 协议要求每一个生效的提议被多数 Acceptor 接收,而且 Acceptor 不会接受两个不一样的提议,所以能够保证正确性。

2. 可终止性

指最后总会有一个提议生效。

Paxos 协议可以让 Proposer 发送的提议朝着能被大多数 Acceptor 接受的那个提议靠拢,所以可以保证可终止性。

6、Raft

Raft 也是分布式一致性协议,主要是用来竞选主节点。

单个 Candidate 的竞选

有三种节点:Follower、Candidate 和 Leader。Leader 会周期性的发送心跳包给 Follower。每一个 Follower 都设置了一个随机的竞选超时时间,通常为 150ms~300ms,若是在这个时间内没有收到 Leader 的心跳包,就会变成 Candidate,进入竞选阶段。

  • 下图展现一个分布式系统的最初阶段,此时只有 Follower 没有 Leader。Node A 等待一个随机的竞选超时时间以后,没收到 Leader 发来的心跳包,所以进入竞选阶段。

 

 

 

  • 此时 Node A 发送投票请求给其它全部节点。

 

 

 

  • 其它节点会对请求进行回复,若是超过一半的节点回复了,那么该 Candidate 就会变成 Leader。

 

 

 

  • 以后 Leader 会周期性地发送心跳包给 Follower,Follower 接收到心跳包,会从新开始计时。

 

 

 

多个 Candidate 竞选

  • 若是有多个 Follower 成为 Candidate,而且所得到票数相同,那么就须要从新开始投票。例以下图中 Node B 和 Node D 都得到两票,须要从新开始投票。

 

 

 

  • 因为每一个节点设置的随机竞选超时时间不一样,所以下一次再次出现多个 Candidate 并得到一样票数的几率很低。

 

 

 

数据同步

  • 来自客户端的修改都会被传入 Leader。注意该修改还未被提交,只是写入日志中。

 

 

 

  • Leader 会把修改复制到全部 Follower。

 

 

 

  • Leader 会等待大多数的 Follower 也进行了修改,而后才将修改提交。

 

 

 

  • 此时 Leader 会通知的全部 Follower 让它们也提交修改,此时全部节点的值达成一致。

 

相关文章
相关标签/搜索