auto commit

This commit is contained in:
CyC2018 2018-11-20 00:36:58 +08:00
parent b486e645a2
commit d90eb6fc00
3 changed files with 35 additions and 11 deletions

View File

@ -173,7 +173,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
网络分区指分布式系统中的节点被划分为多个区域,每个区域内部可以通信,但是区域之间无法通信。 网络分区指分布式系统中的节点被划分为多个区域,每个区域内部可以通信,但是区域之间无法通信。
在分区容忍性条件下,分布式系统在遇到任何网络分区故障的时候,仍然需要能对外提供服务,除非是整个网络环境都发生了故障。 在分区容忍性条件下,分布式系统在遇到任何网络分区故障的时候,仍然需要能对外提供一致性和可用性的服务,除非是整个网络环境都发生了故障。
## 权衡 ## 权衡
@ -181,8 +181,8 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父
可用性和一致性往往是冲突的,很难使它们同时满足。在多个节点之间进行数据同步时, 可用性和一致性往往是冲突的,很难使它们同时满足。在多个节点之间进行数据同步时,
- 为了保证一致性CP需要牺牲部分节点的可用性(即部分节点虽仍正常工作但不会响应用户请求),但保证读出的数据一定是具有强一致性的 - 为了保证一致性CP不能访问未同步完成的节点,也就失去了部分可用性
- 为了保证可用性AP在同步过程中允许读取所有节点的数据,但是数据可能不一致。 - 为了保证可用性AP允许读取所有节点的数据但是数据可能不一致。
<div align="center"> <img src="../pics//0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg"/> </div><br> <div align="center"> <img src="../pics//0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg"/> </div><br>
@ -226,17 +226,41 @@ ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE
## 执行过程 ## 执行过程
规定一个提议包含一个提议序号 n其中序号具有唯一性 规定一个提议包含两个字段:[n, v],其中 n 为序号具有唯一性v 为提议值
当 Acceptor 接收到一个Prepare请求包含的提议序号为 n1 并且之前还未接收过Prepare请求那么发送一个响应设置当前接收到的提议为 n1 ,并且保证以后不会再接受序号小于 n1 的提议。 ### 1. Prepare 阶段
如果 Acceptor 接收到一个Prepare请求其包含的提议号为 n2如果 n2 大于其之前响应的所有的 Prepare 消息所附带的提议号,并且大于其之前响应的所有 Accept 消息所附带的提议号,则发送响应消息,并在响应消息中附带上其已经 Accept 过的提议,并保证不再接受序号小于 n2 的消息 下图演示了两个 Proposer 和三个 Acceptor 的系统中运行该算法的初始过程,每个 Proposer 都会向所有 Acceptor 发送 Prepare 请求
当一个 Proposer 接收到超过一半 Acceptor 的 Prepare 响应时,就可以发送 Accept 请求。Accept 请求包括 Prepare 阶段使用的提议号以及提议值,如果 Prepare阶段没有 Acceptor 回应任何已经 Accept 的值则该 Proposer 可以自己选择一个,否则使用 Prepare 阶段中所有收到的值中提议序号最高的一个。 <div align="center"> <img src="../pics//1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png"/> </div><br>
Acceptor 收到 Accept 请求后,如果该请求中的提议序号大于等于其已经 Accept 或者在 Prepare 阶段收到的提议的序号,则接受该值。否则丢弃该消息 当 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n1, v1],并且之前还未接收过 Prepare 请求,那么发送一个 Prepare 响应,设置当前接收到的提议为 [n1, v1],并且保证以后不会再接受序号小于 n1 的提议
Acceptor 接收到 Accept 请求时,如果序号大于等于该 Acceptor 承诺的最小序号,那么就发送通知给所有的 Learner。当 Learner 发现有大多数的 Acceptor 接收了某个提议,那么该提议的提议值就被 Paxos 选择出来。 如下图Acceptor X 在收到 [n=2, v=8] 的 Prepare 请求时,由于之前没有接收过提议,因此就发送一个 [no previous] 的 Prepare 响应,设置当前接收到的提议为 [n=2, v=8],并且保证以后不会再接受序号小于 2 的提议。其它的 Acceptor 类似。
<div align="center"> <img src="../pics//fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg"/> </div><br>
如果 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 类似。
<div align="center"> <img src="../pics//2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg"/> </div><br>
### 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 请求。
<div align="center"> <img src="../pics//9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png"/> </div><br>
### 3. Learn 阶段
Acceptor 接收到 Accept 请求时,如果序号大于等于该 Acceptor 承诺的最小序号,那么就发送 Learn 提议给所有的 Learner。当 Learner 发现有大多数的 Acceptor 接收了某个提议,那么该提议的提议值就被 Paxos 选择出来。
<div align="center"> <img src="../pics//bf667594-bb4b-4634-bf9b-0596a45415ba.jpg"/> </div><br>
## 约束条件 ## 约束条件

View File

@ -625,7 +625,7 @@ void take_two(int i) {
down(&s[i]); down(&s[i]);
} }
void put_two(i) { void put_tow(i) {
down(&mutex); down(&mutex);
state[i] = THINKING; state[i] = THINKING;
test(LEFT); test(LEFT);

View File

@ -149,7 +149,7 @@ uniqueInstance 采用 volatile 关键字修饰也是很有必要的, `uniqueIn
2. 初始化 uniqueInstance 2. 初始化 uniqueInstance
3. 将 uniqueInstance 指向分配的内存地址 3. 将 uniqueInstance 指向分配的内存地址
但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。指令重排在单线程环境下不会出问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T<sub>1</sub> 执行了 1 和 3此时 T<sub>2</sub> 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance但此时 uniqueInstance 还未被初始化。 但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。指令重排在单线程环境下不会出问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T<sub>1</sub> 执行了 1 和 3此时 T<sub>2</sub> 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance但此时 uniqueInstance 还未被初始化。
使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。 使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。