diff --git a/notes/分布式.md b/notes/分布式.md index c048b43e..e98f2860 100644 --- a/notes/分布式.md +++ b/notes/分布式.md @@ -19,10 +19,11 @@ * [五、Paxos](#五paxos) * [执行过程](#执行过程) * [约束条件](#约束条件) -* [五、Raft](#五raft) +* [六、Raft](#六raft) * [单个 Candidate 的竞选](#单个-candidate-的竞选) * [多个 Candidate 竞选](#多个-candidate-竞选) - * [日志复制](#日志复制) + * [数据同步](#数据同步) +* [参考](#参考) @@ -35,7 +36,7 @@ - 互斥量为 1 表示有其它进程在使用锁,此时处于锁定状态; - 互斥量为 0 表示未锁定状态。 -1 和 0 可以用一个整型值表示,也可以用某个数据存在或者不存在表示,存在表示互斥量为 1。 +1 和 0 可以用一个整型值表示,也可以用某个数据是否存在表示,存在表示互斥量为 1。 ## 数据库的唯一索引 @@ -43,7 +44,7 @@ 存在以下几个问题: -- 锁没有失效时间,解锁失败的话其它进程无法再获得锁。 +- 锁没有失效时间,解锁失败的话其它进程无法再获得该锁。 - 只能是非阻塞锁,插入失败直接就报错了,无法重试。 - 不可重入,已经获得锁的进程也必须重新获取锁。 @@ -59,7 +60,7 @@ EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了 使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时仍然可用。 -- 尝试从 N 个相互独立 Redis 实例获取锁,如果一个实例不可用,应该尽快尝试下一个; +- 尝试从 N 个相互独立 Redis 实例获取锁; - 计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N / 2 + 1)实例上获取了锁,那么就认为锁获取成功了; - 如果锁获取失败,就到每个实例上释放锁。 @@ -67,7 +68,7 @@ EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了 ### 1. Zookeeper 抽象模型 -Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示它的父节点为 /app1。 +Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父节点为 /app1。

@@ -96,21 +97,15 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示 一个节点未获得锁,需要监听自己的前一个子节点,这是因为如果监听所有的子节点,那么任意一个子节点状态改变,其它所有子节点都会收到通知(羊群效应),而我们只希望它的后一个子节点收到通知。 -参考: - -- [Distributed locks with Redis](https://redis.io/topics/distlock) -- [浅谈分布式锁](http://www.linkedkeeper.com/detail/blog.action?bid=1023) -- [基于 Zookeeper 的分布式锁](http://www.dengshenyu.com/java/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/10/23/zookeeper-distributed-lock.html) - # 二、分布式事务 -指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。 +指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。 + +例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。 ## 本地消息表 -### 1. 原理 - -本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性。 +本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。 1. 在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。 2. 之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。 @@ -118,23 +113,19 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示

-### 2. 分析 - -本地消息表利用了本地事务来实现分布式事务,并且使用了消息队列来保证最终一致性。 - ## 2PC 两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。 ### 1. 运行过程 -(一)准备阶段 +#### 1.1 准备阶段 协调者询问参与者事务是否执行成功,参与者发回事务执行结果。

-(二)提交阶段 +#### 1.2 提交阶段 如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。 @@ -144,28 +135,22 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示 ### 2. 存在的问题 -(一)同步阻塞 +#### 2.1 同步阻塞 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。 -(二)单点问题 +#### 2.2 单点问题 协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。 -(三)数据不一致 +#### 2.3 数据不一致 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。 -(四)太过保守 +#### 2.4 太过保守 任意一个节点失败就会导致整个事务失败,没有完善的容错机制。 -参考: - -- [聊聊分布式事务,再说说解决方案](https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html) -- [分布式系统的事务处理](https://coolshell.cn/articles/10910.html) -- [深入理解分布式事务](https://juejin.im/entry/577c6f220a2b5800573492be) - # 三、CAP 分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance),最多只能同时满足其中两项。 @@ -184,7 +169,7 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示 可用性指分布式系统在面对各种异常时可以提供正常服务的能力,可以用系统可用时间占总时间的比值来衡量,4 个 9 的可用性表示系统 99.99% 的时间是可用的。 -在可用性条件下,系统提供的服务一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。 +在可用性条件下,要求系统提供的服务一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。 ## 分区容忍性 @@ -198,16 +183,11 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示 可用性和一致性往往是冲突的,很难都使它们同时满足。在多个节点之间进行数据同步时, -* 为了保证一致性(CP),就需要让所有节点下线成为不可用的状态,等待同步完成; -* 为了保证可用性(AP),在同步过程中允许读取所有节点的数据,但是数据可能不一致。 +- 为了保证一致性(CP),就需要让所有节点下线成为不可用的状态,等待同步完成; +- 为了保证可用性(AP),在同步过程中允许读取所有节点的数据,但是数据可能不一致。

-参考: - -- 倪超. 从 Paxos 到 ZooKeeper : 分布式一致性原理与实践 [M]. 电子工业出版社, 2015. -- [What is CAP theorem in distributed database system?](http://www.colooshiki.com/index.php/2017/04/20/what-is-cap-theorem-in-distributed-database-system/) - # 四、BASE BASE 是基本可用(Basically Available)、软状态(Soft State)和最终一致性(Eventually Consistent)三个短语的缩写。 @@ -292,66 +272,69 @@ Acceptor 接收到接受请求时,如果序号大于等于该 Acceptor 承诺 Paxos 协议能够让 Proposer 发送的提议朝着能被大多数 Acceptor 接受的那个提议靠拢,因此能够保证可终止性。 -参考: +# 六、Raft -- [NEAT ALGORITHMS - PAXOS](http://harry.me/blog/2014/12/27/neat-algorithms-paxos/) -- [Paxos By Example](https://angus.nyc/2012/paxos-by-example/) - -# 五、Raft - -Raft 和 Paxos 类似,但是更容易理解,也更容易实现。 - -Raft 主要是用来竞选主节点。 +Raft 也是分布式一致性协议,主要是用来竞选主节点。 ## 单个 Candidate 的竞选 有三种节点:Follower、Candidate 和 Leader。Leader 会周期性的发送心跳包给 Follower。每个 Follower 都设置了一个随机的竞选超时时间,一般为 150ms\~300ms,如果在这个时间内没有收到 Leader 的心跳包,就会变成 Candidate,进入竞选阶段。 -* 下图表示一个分布式系统的最初阶段,此时只有 Follower,没有 Leader。Follower A 等待一个随机的竞选超时时间之后,没收到 Leader 发来的心跳包,因此进入竞选阶段。 +- 下图展示一个分布式系统的最初阶段,此时只有 Follower 没有 Leader。Node A 等待一个随机的竞选超时时间之后,没收到 Leader 发来的心跳包,因此进入竞选阶段。

-* 此时 A 发送投票请求给其它所有节点。 +- 此时 Node A 发送投票请求给其它所有节点。

-* 其它节点会对请求进行回复,如果超过一半的节点回复了,那么该 Candidate 就会变成 Leader。 +- 其它节点会对请求进行回复,如果超过一半的节点回复了,那么该 Candidate 就会变成 Leader。

-* 之后 Leader 会周期性地发送心跳包给 Follower,Follower 接收到心跳包,会重新开始计时。 +- 之后 Leader 会周期性地发送心跳包给 Follower,Follower 接收到心跳包,会重新开始计时。

## 多个 Candidate 竞选 -* 如果有多个 Follower 成为 Candidate,并且所获得票数相同,那么就需要重新开始投票,例如下图中 Candidate B 和 Candidate D 都获得两票,因此需要重新开始投票。 +- 如果有多个 Follower 成为 Candidate,并且所获得票数相同,那么就需要重新开始投票。例如下图中 Node B 和 Node D 都获得两票,需要重新开始投票。

-* 当重新开始投票时,由于每个节点设置的随机竞选超时时间不同,因此能下一次再次出现多个 Candidate 并获得同样票数的概率很低。 +- 由于每个节点设置的随机竞选超时时间不同,因此下一次再次出现多个 Candidate 并获得同样票数的概率很低。

-## 日志复制 +## 数据同步 -* 来自客户端的修改都会被传入 Leader。注意该修改还未被提交,只是写入日志中。 +- 来自客户端的修改都会被传入 Leader。注意该修改还未被提交,只是写入日志中。

-* Leader 会把修改复制到所有 Follower。 +- Leader 会把修改复制到所有 Follower。

-* Leader 会等待大多数的 Follower 也进行了修改,然后才将修改提交。 +- Leader 会等待大多数的 Follower 也进行了修改,然后才将修改提交。

-* 此时 Leader 会通知的所有 Follower 让它们也提交修改,此时所有节点的值达成一致。 +- 此时 Leader 会通知的所有 Follower 让它们也提交修改,此时所有节点的值达成一致。

-参考: +# 参考 +- 倪超. 从 Paxos 到 ZooKeeper : 分布式一致性原理与实践 [M]. 电子工业出版社, 2015. +- [Distributed locks with Redis](https://redis.io/topics/distlock) +- [浅谈分布式锁](http://www.linkedkeeper.com/detail/blog.action?bid=1023) +- [基于 Zookeeper 的分布式锁](http://www.dengshenyu.com/java/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/10/23/zookeeper-distributed-lock.html) - [Raft: Understandable Distributed Consensus](http://thesecretlivesofdata.com/raft) +- [聊聊分布式事务,再说说解决方案](https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html) +- [分布式系统的事务处理](https://coolshell.cn/articles/10910.html) +- [深入理解分布式事务](https://juejin.im/entry/577c6f220a2b5800573492be) +- [What is CAP theorem in distributed database system?](http://www.colooshiki.com/index.php/2017/04/20/what-is-cap-theorem-in-distributed-database-system/) +- [NEAT ALGORITHMS - PAXOS](http://harry.me/blog/2014/12/27/neat-algorithms-paxos/) +- [Paxos By Example](https://angus.nyc/2012/paxos-by-example/) diff --git a/notes/系统设计基础.md b/notes/系统设计基础.md index 805764a9..b6a3ddf5 100644 --- a/notes/系统设计基础.md +++ b/notes/系统设计基础.md @@ -68,7 +68,7 @@ 应用服务器只要不具有状态,那么就可以很容易地通过负载均衡器向集群中添加新的服务器。 -关系型数据库的伸缩性通过 Sharding 来实现,将数据按一定的规则分布到不同的节点上,从而解决单台存储服务器存储空间限制。 +关系型数据库的伸缩性通过 Sharding 来实现,将数据按一定的规则分布到不同的节点上,从而解决单台存储服务器的存储空间限制。 对于非关系型数据库,它们天生就是为海量数据而诞生,对伸缩性的支持特别好。 @@ -78,7 +78,7 @@ 实现可扩展主要有两种方式: -- 使用消息队列进行解耦,应用之间通过消息传递的方式进行通信; +- 使用消息队列进行解耦,应用之间通过消息传递进行通信; - 使用分布式服务将业务和可复用的服务分离开来,业务使用分布式服务框架调用可复用的服务。新增的产品可以通过调用可复用的服务来实现业务逻辑,对其它产品没有影响。 # 四、可用性 @@ -87,7 +87,7 @@ 保证高可用的主要手段是使用冗余,当某个服务器故障时就请求其它服务器。 -应用服务器的冗余比较容易实现,只要保证应用服务器不具有状态,那么某个应用服务器故障时,负载均衡器将该应用服务器原先的用户请求转发到另一个应用服务器上不会对用户有任何影响。 +应用服务器的冗余比较容易实现,只要保证应用服务器不具有状态,那么某个应用服务器故障时,负载均衡器将该应用服务器原先的用户请求转发到另一个应用服务器上,不会对用户有任何影响。 存储服务器的冗余需要使用主从复制来实现,当主服务器故障时,需要提升从服务器为主服务器,这个过程称为切换。 @@ -97,7 +97,7 @@ ## 服务降级 -服务器降级是系统为了应对大量的请求,主动关闭部分功能,从而保证核心功能可用。 +服务降级是系统为了应对大量的请求,主动关闭部分功能,从而保证核心功能可用。 # 五、安全性