diff --git a/docs/database/mysql/mysql-query-cache.md b/docs/database/mysql/mysql-query-cache.md
index a0df886f..a1383531 100644
--- a/docs/database/mysql/mysql-query-cache.md
+++ b/docs/database/mysql/mysql-query-cache.md
@@ -76,10 +76,10 @@ mysql> show variables like '%query_cache%';
我们这里对 8.0 版本之前`show variables like '%query_cache%';`命令打印出来的信息进行解释。
- **`have_query_cache`:** 该 MySQL Server 是否支持查询缓存,如果是 YES 表示支持,否则则是不支持。
-- **`query_cache_limit`:**MySQL 查询缓存的最大查询结果,查询结果大于该值时不会被缓存。
-- **`query_cache_min_res_unit`:**查询缓存分配的最小块的大小(字节)。当查询进行的时候,MySQL 把查询结果保存在查询缓存中,但如果要保存的结果比较大,超过 `query_cache_min_res_unit` 的值 ,这时候 MySQL 将一边检索结果,一边进行保存结果,也就是说,有可能在一次查询中,MySQL 要进行多次内存分配的操作。适当的调节 `query_cache_min_res_unit` 可以优化内存。
-- **`query_cache_size`:**为缓存查询结果分配的内存的数量,单位是字节,且数值必须是 1024 的整数倍。默认值是 0,即禁用查询缓存。
-- **`query_cache_type`:**设置查询缓存类型,默认为 ON。设置 GLOBAL 值可以设置后面的所有客户端连接的类型。客户端可以设置 SESSION 值以影响他们自己对查询缓存的使用。
+- **`query_cache_limit`:** MySQL 查询缓存的最大查询结果,查询结果大于该值时不会被缓存。
+- **`query_cache_min_res_unit`:** 查询缓存分配的最小块的大小(字节)。当查询进行的时候,MySQL 把查询结果保存在查询缓存中,但如果要保存的结果比较大,超过 `query_cache_min_res_unit` 的值 ,这时候 MySQL 将一边检索结果,一边进行保存结果,也就是说,有可能在一次查询中,MySQL 要进行多次内存分配的操作。适当的调节 `query_cache_min_res_unit` 可以优化内存。
+- **`query_cache_size`:** 为缓存查询结果分配的内存的数量,单位是字节,且数值必须是 1024 的整数倍。默认值是 0,即禁用查询缓存。
+- **`query_cache_type`:** 设置查询缓存类型,默认为 ON。设置 GLOBAL 值可以设置后面的所有客户端连接的类型。客户端可以设置 SESSION 值以影响他们自己对查询缓存的使用。
- **`query_cache_wlock_invalidate`** :如果某个表被锁住,是否返回缓存中的数据,默认关闭,也是建议的。
`query_cache_type` 可能的值(修改 `query_cache_type` 需要重启 MySQL Server):
diff --git a/docs/database/mysql/mysql-questions-01.md b/docs/database/mysql/mysql-questions-01.md
index 372d6a7e..163c6cb6 100644
--- a/docs/database/mysql/mysql-questions-01.md
+++ b/docs/database/mysql/mysql-questions-01.md
@@ -228,7 +228,7 @@ InnoDB 的性能比 MyISAM 更强大,不管是在读写混合模式下还是
## MySQL 索引
-MySQL 索引相关的问题比较多,对于面试和工作都比较重要,于是,我单独抽了一篇文章专门来总结 MySQL 索引相关的知识点和问题: [MySQL 索引详解](./mysql-index.md) 。
+MySQL 索引相关的问题比较多,对于面试和工作都比较重要,于是,我单独抽了一篇文章专门来总结 MySQL 索引相关的知识点和问题: [MySQL 索引详解](https://javaguide.cn/database/mysql/mysql-index.html) 。
## MySQL 查询缓存
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/images/curator.png b/docs/distributed-system/distributed-process-coordination/zookeeper/images/curator.png
deleted file mode 100644
index 360993d5..00000000
Binary files a/docs/distributed-system/distributed-process-coordination/zookeeper/images/curator.png and /dev/null differ
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/images/watche机制.png b/docs/distributed-system/distributed-process-coordination/zookeeper/images/watche机制.png
deleted file mode 100644
index c85c4501..00000000
Binary files a/docs/distributed-system/distributed-process-coordination/zookeeper/images/watche机制.png and /dev/null differ
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/images/znode-structure.png b/docs/distributed-system/distributed-process-coordination/zookeeper/images/znode-structure.png
deleted file mode 100644
index 0f2c9d6c..00000000
Binary files a/docs/distributed-system/distributed-process-coordination/zookeeper/images/znode-structure.png and /dev/null differ
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/images/zookeeper集群.png b/docs/distributed-system/distributed-process-coordination/zookeeper/images/zookeeper集群.png
deleted file mode 100644
index e6a6e711..00000000
Binary files a/docs/distributed-system/distributed-process-coordination/zookeeper/images/zookeeper集群.png and /dev/null differ
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/images/zookeeper集群中的角色.png b/docs/distributed-system/distributed-process-coordination/zookeeper/images/zookeeper集群中的角色.png
deleted file mode 100644
index fba78b60..00000000
Binary files a/docs/distributed-system/distributed-process-coordination/zookeeper/images/zookeeper集群中的角色.png and /dev/null differ
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/images/连接ZooKeeper服务.png b/docs/distributed-system/distributed-process-coordination/zookeeper/images/连接ZooKeeper服务.png
deleted file mode 100644
index c7c37bbd..00000000
Binary files a/docs/distributed-system/distributed-process-coordination/zookeeper/images/连接ZooKeeper服务.png and /dev/null differ
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-in-action.md b/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-in-action.md
index c592dfa0..2721e10e 100644
--- a/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-in-action.md
+++ b/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-in-action.md
@@ -36,7 +36,7 @@ root@eaf70fc620cb:/apache-zookeeper-3.5.8-bin# cd bin
如果你看到控制台成功打印出如下信息的话,说明你已经成功连接 ZooKeeper 服务。
-
+
### 2.3. 常用命令演示
@@ -163,7 +163,7 @@ numChildren = 1
Curator 是Netflix公司开源的一套 ZooKeeper Java客户端框架,相比于 Zookeeper 自带的客户端 zookeeper 来说,Curator 的封装更加完善,各种 API 都可以比较方便地使用。
-
+
下面我们就来简单地演示一下 Curator 的使用吧!
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md b/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md
index 3a5e92cb..82a1e83b 100644
--- a/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md
+++ b/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-intro.md
@@ -1,10 +1,8 @@
# ZooKeeper 相关概念总结(入门)
-## 1. 前言
-
相信大家对 ZooKeeper 应该不算陌生。但是你真的了解 ZooKeeper 到底有啥用不?如果别人/面试官让你给他讲讲对于 ZooKeeper 的认识,你能回答到什么地步呢?
-拿我自己来说吧!我本人曾经使用 Dubbo 来做分布式项目的时候,使用了 ZooKeeper 作为注册中心。为了保证分布式系统能够同步访问某个资源,我还使用 ZooKeeper 做过分布式锁。另外,我在学习 Kafka 的时候,知道 Kafka 很多功能的实现依赖了 ZooKeeper。
+拿我自己来说吧!我本人在大学曾经使用 Dubbo 来做分布式项目的时候,使用了 ZooKeeper 作为注册中心。为了保证分布式系统能够同步访问某个资源,我还使用 ZooKeeper 做过分布式锁。另外,我在学习 Kafka 的时候,知道 Kafka 很多功能的实现依赖了 ZooKeeper。
前几天,总结项目经验的时候,我突然问自己 ZooKeeper 到底是个什么东西?想了半天,脑海中只是简单的能浮现出几句话:
@@ -20,58 +18,58 @@
_如果文章有任何需要改善和完善的地方,欢迎在评论区指出,共同进步!_
-## 2. ZooKeeper 介绍
+## ZooKeeper 介绍
-### 2.1. ZooKeeper 由来
+### ZooKeeper 由来
正式介绍 ZooKeeper 之前,我们先来看看 ZooKeeper 的由来,还挺有意思的。
-下面这段内容摘自《从 Paxos 到 ZooKeeper 》第四章第一节,推荐大家阅读一下:
+下面这段内容摘自《从 Paxos 到 ZooKeeper》第四章第一节,推荐大家阅读一下:
> ZooKeeper 最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题。所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。
>
> 关于“ZooKeeper”这个项目的名字,其实也有一段趣闻。在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如著名的 Pig 项目),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家 RaghuRamakrishnan 开玩笑地说:“在这样下去,我们这儿就变成动物园了!”此话一出,大家纷纷表示就叫动物园管理员吧一一一因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而 ZooKeeper 正好要用来进行分布式环境的协调一一于是,ZooKeeper 的名字也就由此诞生了。
-### 2.2. ZooKeeper 概览
+### ZooKeeper 概览
ZooKeeper 是一个开源的**分布式协调服务**,它的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。
> **原语:** 操作系统或计算机网络用语范畴。是由若干条指令组成的,用于完成一定功能的一个过程。具有不可分割性·即原语的执行必须是连续的,在执行过程中不允许被中断。
-**ZooKeeper 为我们提供了高可用、高性能、稳定的分布式数据一致性解决方案,通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。**
+ZooKeeper 为我们提供了高可用、高性能、稳定的分布式数据一致性解决方案,通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。这些功能的实现主要依赖于 ZooKeeper 提供的 **数据存储+事件监听** 功能(后文会详细介绍到) 。
-另外,**ZooKeeper 将数据保存在内存中,性能是非常棒的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景)。**
+ZooKeeper 将数据保存在内存中,性能是不错的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景)。
-### 2.3. ZooKeeper 特点
+另外,很多顶级的开源项目都用到了 ZooKeeper,比如:
+
+- **Kafka** : ZooKeeper 主要为 Kafka 提供 Broker 和 Topic 的注册以及多个 Partition 的负载均衡等功能。不过,在 Kafka 2.8 之后,引入了基于 Raft 协议的 KRaft 模式,不再依赖 Zookeeper,大大简化了 Kafka 的架构。
+- **Hbase** : ZooKeeper 为 Hbase 提供确保整个集群只有一个 Master 以及保存和提供 regionserver 状态信息(是否在线)等功能。
+- **Hadoop** : ZooKeeper 为 Namenode 提供高可用支持。
+
+### ZooKeeper 特点
- **顺序一致性:** 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
- **原子性:** 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
- **单一系统映像 :** 无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。
- **可靠性:** 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。
-### 2.4. ZooKeeper 典型应用场景
+### ZooKeeper 应用场景
ZooKeeper 概览中,我们介绍到使用其通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
下面选 3 个典型的应用场景来专门说说:
-1. **分布式锁** : 通过创建唯一节点获得分布式锁,当获得锁的一方执行完相关代码或者是挂掉之后就释放锁。
-2. **命名服务** :可以通过 ZooKeeper 的顺序节点生成全局唯一 ID
-3. **数据发布/订阅** :通过 **Watcher 机制** 可以很方便地实现数据发布/订阅。当你将数据发布到 ZooKeeper 被监听的节点上,其他机器可通过监听 ZooKeeper 上节点的变化来实现配置的动态更新。
+1. **命名服务** :可以通过 ZooKeeper 的顺序节点生成全局唯一 ID。
+2. **数据发布/订阅** :通过 **Watcher 机制** 可以很方便地实现数据发布/订阅。当你将数据发布到 ZooKeeper 被监听的节点上,其他机器可通过监听 ZooKeeper 上节点的变化来实现配置的动态更新。
+3. **分布式锁** : 通过创建唯一节点获得分布式锁,当获得锁的一方执行完相关代码或者是挂掉之后就释放锁。分布式锁的实现也需要用到 **Watcher 机制** ,我在 [分布式锁详解](https://javaguide.cn/distributed-system/distributed-lock.html) 这篇文章中有详细介绍到如何基于 ZooKeeper 实现分布式锁。
实际上,这些功能的实现基本都得益于 ZooKeeper 可以保存数据的功能,但是 ZooKeeper 不适合保存大量数据,这一点需要注意。
-### 2.5. 有哪些著名的开源项目用到了 ZooKeeper?
-
-1. **Kafka** : ZooKeeper 主要为 Kafka 提供 Broker 和 Topic 的注册以及多个 Partition 的负载均衡等功能。
-2. **Hbase** : ZooKeeper 为 Hbase 提供确保整个集群只有一个 Master 以及保存和提供 regionserver 状态信息(是否在线)等功能。
-3. **Hadoop** : ZooKeeper 为 Namenode 提供高可用支持。
-
-## 3. ZooKeeper 重要概念解读
+## ZooKeeper 重要概念
_破音:拿出小本本,下面的内容非常重要哦!_
-### 3.1. Data model(数据模型)
+### Data model(数据模型)
ZooKeeper 数据模型采用层次化的多叉树形结构,每个节点上都可以存储数据,这些数据可以是数字、字符串或者是二级制序列。并且。每个节点还可以拥有 N 个子节点,最上层是根节点以“/”来代表。每个数据节点在 ZooKeeper 中被称为 **znode**,它是 ZooKeeper 中数据的最小单元。并且,每个 znode 都一个唯一的路径标识。
@@ -79,22 +77,18 @@ ZooKeeper 数据模型采用层次化的多叉树形结构,每个节点上都
从下图可以更直观地看出:ZooKeeper 节点路径标识方式和 Unix 文件系统路径非常相似,都是由一系列使用斜杠"/"进行分割的路径表示,开发人员可以向这个节点中写入数据,也可以在节点下面创建子节点。这些操作我们后面都会介绍到。
-
+
-### 3.2. znode(数据节点)
+### znode(数据节点)
介绍了 ZooKeeper 树形数据模型之后,我们知道每个数据节点在 ZooKeeper 中被称为 **znode**,它是 ZooKeeper 中数据的最小单元。你要存放的数据就放在上面,是你使用 ZooKeeper 过程中经常需要接触到的一个概念。
-#### 3.2.1. znode 4 种类型
-
我们通常是将 znode 分为 4 大类:
- **持久(PERSISTENT)节点** :一旦创建就一直存在即使 ZooKeeper 集群宕机,直到将其删除。
- **临时(EPHEMERAL)节点** :临时节点的生命周期是与 **客户端会话(session)** 绑定的,**会话消失则节点消失** 。并且,**临时节点只能做叶子节点** ,不能创建子节点。
- **持久顺序(PERSISTENT_SEQUENTIAL)节点** :除了具有持久(PERSISTENT)节点的特性之外, 子节点的名称还具有顺序性。比如 `/node1/app0000000001` 、`/node1/app0000000002` 。
-- **临时顺序(EPHEMERAL_SEQUENTIAL)节点** :除了具备临时(EPHEMERAL)节点的特性之外,子节点的名称还具有顺序性。
-
-#### 3.2.2. znode 数据结构
+- **临时顺序(EPHEMERAL_SEQUENTIAL)节点** :除了具备临时(EPHEMERAL)节点的特性之外,子节点的名称还具有顺序性
每个 znode 由 2 部分组成:
@@ -121,7 +115,7 @@ dataLength = 0
numChildren = 1
```
-Stat 类中包含了一个数据节点的所有状态信息的字段,包括事务 ID-cZxid、节点创建时间-ctime 和子节点个数-numChildren 等等。
+Stat 类中包含了一个数据节点的所有状态信息的字段,包括事务 ID(cZxid)、节点创建时间(ctime) 和子节点个数(numChildren) 等等。
下面我们来看一下每个 znode 状态信息究竟代表的是什么吧!(下面的内容来源于《从 Paxos 到 ZooKeeper 分布式一致性原理与实践》,因为 Guide 确实也不是特别清楚,要学会参考资料的嘛! ) :
@@ -139,7 +133,7 @@ Stat 类中包含了一个数据节点的所有状态信息的字段,包括事
| dataLength | 数据节点内容长度 |
| numChildren | 当前节点的子节点个数 |
-### 3.3. 版本(version)
+### 版本(version)
在前面我们已经提到,对应于每个 znode,ZooKeeper 都会为其维护一个叫作 **Stat** 的数据结构,Stat 中记录了这个 znode 的三个相关的版本:
@@ -147,7 +141,7 @@ Stat 类中包含了一个数据节点的所有状态信息的字段,包括事
- **cversion** : 当前 znode 子节点的版本
- **aclVersion** : 当前 znode 的 ACL 的版本。
-### 3.4. ACL(权限控制)
+### ACL(权限控制)
ZooKeeper 采用 ACL(AccessControlLists)策略来进行权限控制,类似于 UNIX 文件系统的权限控制。
@@ -168,15 +162,15 @@ ZooKeeper 采用 ACL(AccessControlLists)策略来进行权限控制,类似
- **digest** :用户名:密码认证方式: _username:password_ 。
- **ip** : 对指定 ip 进行限制。
-### 3.5. Watcher(事件监听器)
+### Watcher(事件监听器)
Watcher(事件监听器),是 ZooKeeper 中的一个很重要的特性。ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。
-
+
_破音:非常有用的一个特性,都拿出小本本记好了,后面用到 ZooKeeper 基本离不开 Watcher(事件监听器)机制。_
-### 3.6. 会话(Session)
+### 会话(Session)
Session 可以看作是 ZooKeeper 服务器与客户端的之间的一个 TCP 长连接,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watcher 事件通知。
@@ -184,21 +178,21 @@ Session 有一个属性叫做:`sessionTimeout` ,`sessionTimeout` 代表会
另外,在为客户端创建会话之前,服务端首先会为每个客户端都分配一个 `sessionID`。由于 `sessionID`是 ZooKeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个 `sessionID` 的,因此,无论是哪台服务器为客户端分配的 `sessionID`,都务必保证全局唯一。
-## 4. ZooKeeper 集群
+## ZooKeeper 集群
为了保证高可用,最好是以集群形态来部署 ZooKeeper,这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么 ZooKeeper 本身仍然是可用的。通常 3 台服务器就可以构成一个 ZooKeeper 集群了。ZooKeeper 官方提供的架构图就是一个 ZooKeeper 集群整体对外提供服务。
-
+
上图中每一个 Server 代表一个安装 ZooKeeper 服务的服务器。组成 ZooKeeper 服务的服务器都会在内存中维护当前的服务器状态,并且每台服务器之间都互相保持着通信。集群间通过 ZAB 协议(ZooKeeper Atomic Broadcast)来保持数据的一致性。
**最典型集群模式: Master/Slave 模式(主备模式)**。在这种模式中,通常 Master 服务器作为主服务器提供写服务,其他的 Slave 服务器从服务器通过异步复制的方式获取 Master 服务器最新的数据提供读服务。
-### 4.1. ZooKeeper 集群角色
+### ZooKeeper 集群角色
但是,在 ZooKeeper 中没有选择传统的 Master/Slave 概念,而是引入了 Leader、Follower 和 Observer 三种角色。如下图所示
-
+
ZooKeeper 集群中的所有机器通过一个 **Leader 选举过程** 来选定一台称为 “**Leader**” 的机器,Leader 既可以为客户端提供写服务又能提供读服务。除了 Leader 外,**Follower** 和 **Observer** 都只能提供读服务。Follower 和 Observer 唯一的区别在于 Observer 机器不参与 Leader 的选举过程,也不参与写操作的“过半写成功”策略,因此 Observer 机器可以在不影响写性能的情况下提升集群的读性能。
@@ -218,14 +212,14 @@ ZooKeeper 集群中的所有机器通过一个 **Leader 选举过程** 来选定
准 leader 才会成为真正的 leader。
4. **Broadcast(广播阶段)** :到了这个阶段,ZooKeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步。
-### 4.2. ZooKeeper 集群中的服务器状态
+### ZooKeeper 集群中的服务器状态
- **LOOKING** :寻找 Leader。
- **LEADING** :Leader 状态,对应的节点为 Leader。
- **FOLLOWING** :Follower 状态,对应的节点为 Follower。
- **OBSERVING** :Observer 状态,对应节点为 Observer,该节点不参与 Leader 选举。
-### 4.3. ZooKeeper 集群为啥最好奇数台?
+### ZooKeeper 集群为啥最好奇数台?
ZooKeeper 集群在宕掉几个 ZooKeeper 服务器之后,如果剩下的 ZooKeeper 服务器个数大于宕掉的个数的话整个 ZooKeeper 才依然可用。假如我们的集群中有 n 台 ZooKeeper 服务器,那么也就是剩下的服务数必须大于 n/2。先说一下结论,2n 和 2n-1 的容忍度是一样的,都是 n-1,大家可以先自己仔细想一想,这应该是一个很简单的数学问题了。
@@ -234,7 +228,7 @@ ZooKeeper 集群在宕掉几个 ZooKeeper 服务器之后,如果剩下的 ZooK
综上,何必增加那一个不必要的 ZooKeeper 呢?
-### 4.4. ZooKeeper 选举的过半机制防止脑裂
+### ZooKeeper 选举的过半机制防止脑裂
**何为集群脑裂?**
@@ -246,27 +240,28 @@ ZooKeeper 集群在宕掉几个 ZooKeeper 服务器之后,如果剩下的 ZooK
ZooKeeper 的过半机制导致不可能产生 2 个 leader,因为少于等于一半是不可能产生 leader 的,这就使得不论机房的机器如何分配都不可能发生脑裂。
-## 5. ZAB 协议和 Paxos 算法
+## ZAB 协议和 Paxos 算法
Paxos 算法应该可以说是 ZooKeeper 的灵魂了。但是,ZooKeeper 并没有完全采用 Paxos 算法 ,而是使用 ZAB 协议作为其保证数据一致性的核心算法。另外,在 ZooKeeper 的官方文档中也指出,ZAB 协议并不像 Paxos 算法那样,是一种通用的分布式一致性算法,它是一种特别为 Zookeeper 设计的崩溃可恢复的原子消息广播算法。
-### 5.1. ZAB 协议介绍
+### ZAB 协议介绍
ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
-### 5.2. ZAB 协议两种基本的模式:崩溃恢复和消息广播
+### ZAB 协议两种基本的模式:崩溃恢复和消息广播
ZAB 协议包括两种基本的模式,分别是
- **崩溃恢复** :当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB 协议就会进入恢复模式并选举产生新的 Leader 服务器。当选举产生了新的 Leader 服务器,同时集群中已经有过半的机器与该 Leader 服务器完成了状态同步之后,ZAB 协议就会退出恢复模式。其中,**所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和 Leader 服务器的数据状态保持一致**。
- **消息广播** :**当集群中已经有过半的 Follower 服务器完成了和 Leader 服务器的状态同步,那么整个服务框架就可以进入消息广播模式了。** 当一台同样遵守 ZAB 协议的服务器启动后加入到集群中时,如果此时集群中已经存在一个 Leader 服务器在负责进行消息广播,那么新加入的服务器就会自觉地进入数据恢复模式:找到 Leader 所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。
-关于 **ZAB 协议&Paxos 算法** 需要讲和理解的东西太多了,具体可以看下面这两篇文章:
+关于 **ZAB 协议&Paxos 算法** 需要讲和理解的东西太多了,具体可以看下面这几篇文章:
-- [图解 Paxos 一致性协议](http://codemacro.com/2014/10/15/explain-poxos/)
+- [Paxos 算法详解](https://javaguide.cn/distributed-system/theorem&algorithm&protocol/paxos-algorithm.html)
- [Zookeeper ZAB 协议分析](https://dbaplus.cn/news-141-1875-1.html)
+- [Raft 算法详解](https://javaguide.cn/distributed-system/theorem&algorithm&protocol/raft-algorithm.html)
-## 6. 总结
+## 总结
1. ZooKeeper 本身就是一个分布式程序(只要半数以上节点存活,ZooKeeper 就能正常服务)。
2. 为了保证高可用,最好是以集群形态来部署 ZooKeeper,这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么 ZooKeeper 本身仍然是可用的。
@@ -275,6 +270,6 @@ ZAB 协议包括两种基本的模式,分别是
5. ZooKeeper 有临时节点的概念。 当创建临时节点的客户端会话一直保持活动,瞬时节点就一直存在。而当会话终结时,瞬时节点被删除。持久节点是指一旦这个 znode 被创建了,除非主动进行 znode 的移除操作,否则这个 znode 将一直保存在 ZooKeeper 上。
6. ZooKeeper 底层其实只提供了两个功能:① 管理(存储、读取)用户程序提交的数据;② 为用户程序提供数据节点监听服务。
-## 7. 参考
+## 参考
-1. 《从 Paxos 到 ZooKeeper 分布式一致性原理与实践》
+- 《从 Paxos 到 ZooKeeper 分布式一致性原理与实践》
diff --git a/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md b/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md
index b3885208..22a17f8f 100644
--- a/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md
+++ b/docs/distributed-system/distributed-process-coordination/zookeeper/zookeeper-plus.md
@@ -2,15 +2,7 @@
> [FrancisQ](https://juejin.im/user/5c33853851882525ea106810) 投稿。
-## 1. 好久不见
-
-离上一篇文章的发布也快一个月了,想想已经快一个月没写东西了,其中可能有期末考试、课程设计和驾照考试,但这都不是借口!
-
-一到冬天就懒的不行,望广大掘友督促我🙄🙄✍️✍️。
-
-> 文章很长,先赞后看,养成习惯。❤️ 🧡 💛 💚 💙 💜
-
-## 2. 什么是ZooKeeper
+## 什么是ZooKeeper
`ZooKeeper` 由 `Yahoo` 开发,后来捐赠给了 `Apache` ,现已成为 `Apache` 顶级项目。`ZooKeeper` 是一个开源的分布式应用程序协调服务器,其为分布式系统提供一致性服务。其一致性是通过基于 `Paxos` 算法的 `ZAB` 协议完成的。其主要功能包括:配置维护、分布式同步、集群管理、分布式事务等。
@@ -34,7 +26,7 @@
比如各个分布式组件如何协调起来,如何减少各个系统之间的耦合度,分布式事务的处理,如何去配置整个分布式系统等等。`ZooKeeper` 主要就是解决这些问题的。
-## 3. 一致性问题
+## 一致性问题
设计一个分布式系统必定会遇到一个问题—— **因为分区容忍性(partition tolerance)的存在,就必定要求我们需要在系统可用性(availability)和数据一致性(consistency)中做出权衡** 。这就是著名的 `CAP` 定理。
@@ -44,7 +36,7 @@
而上述前者就是 `Eureka` 的处理方式,它保证了AP(可用性),后者就是我们今天所要讲的 `ZooKeeper` 的处理方式,它保证了CP(数据一致性)。
-## 4. 一致性协议和算法
+## 一致性协议和算法
而为了解决数据一致性问题,在科学家和程序员的不断探索中,就出现了很多的一致性协议和算法。比如 2PC(两阶段提交),3PC(三阶段提交),Paxos算法等等。
@@ -56,7 +48,7 @@
而为什么要去解决数据一致性的问题?你想想,如果一个秒杀系统将服务拆分成了下订单和加积分服务,这两个服务部署在不同的机器上了,万一在消息的传播过程中积分系统宕机了,总不能你这边下了订单却没加积分吧?你总得保证两边的数据需要一致吧?
-### 4.1. 2PC(两阶段提交)
+### 2PC(两阶段提交)
两阶段提交是一种保证分布式系统数据一致性的协议,现在很多数据库都是采用的两阶段提交协议来完成 **分布式事务** 的处理。
@@ -86,7 +78,7 @@
* **阻塞问题**,即当协调者发送 `prepare` 请求,参与者收到之后如果能处理那么它将会进行事务的处理但并不提交,这个时候会一直占用着资源不释放,如果此时协调者挂了,那么这些资源都不会再释放了,这会极大影响性能。
* **数据不一致问题**,比如当第二阶段,协调者只发送了一部分的 `commit` 请求就挂了,那么也就意味着,收到消息的参与者会进行事务的提交,而后面没收到的则不会进行事务提交,那么这时候就会产生数据不一致性问题。
-### 4.2. 3PC(三阶段提交)
+### 3PC(三阶段提交)
因为2PC存在的一系列问题,比如单点,容错机制缺陷等等,从而产生了 **3PC(三阶段提交)** 。那么这三阶段又分别是什么呢?
@@ -104,13 +96,13 @@
所以,要解决一致性问题还需要靠 `Paxos` 算法⭐️ ⭐️ ⭐️ 。
-### 4.3. `Paxos` 算法
+### `Paxos` 算法
`Paxos` 算法是基于**消息传递且具有高度容错特性的一致性算法**,是目前公认的解决分布式一致性问题最有效的算法之一,**其解决的问题就是在分布式系统中如何就某个值(决议)达成一致** 。
在 `Paxos` 中主要有三个角色,分别为 `Proposer提案者`、`Acceptor表决者`、`Learner学习者`。`Paxos` 算法和 `2PC` 一样,也有两个阶段,分别为 `Prepare` 和 `accept` 阶段。
-#### 4.3.1. prepare 阶段
+#### prepare 阶段
* `Proposer提案者`:负责提出 `proposal`,每个提案者在提出提案时都会首先获取到一个 **具有全局唯一性的、递增的提案编号N**,即在整个集群中是唯一的编号 N,然后将该编号赋予其要提出的提案,在**第一阶段是只将提案编号发送给所有的表决者**。
* `Acceptor表决者`:每个表决者在 `accept` 某提案后,会将该提案编号N记录在本地,这样每个表决者中保存的已经被 accept 的提案中会存在一个**编号最大的提案**,其编号假设为 `maxN`。每个表决者仅会 `accept` 编号大于自己本地 `maxN` 的提案,在批准提案时表决者会将以前接受过的最大编号的提案作为响应反馈给 `Proposer` 。
@@ -119,7 +111,7 @@

-#### 4.3.2. accept 阶段
+#### accept 阶段
当一个提案被 `Proposer` 提出后,如果 `Proposer` 收到了超过半数的 `Acceptor` 的批准(`Proposer` 本身同意),那么此时 `Proposer` 会给所有的 `Acceptor` 发送真正的提案(你可以理解为第一阶段为试探),这个时候 `Proposer` 就会发送提案的内容和提案编号。
@@ -135,7 +127,7 @@
> 对于 `Learner` 来说如何去学习 `Acceptor` 批准的提案内容,这有很多方式,读者可以自己去了解一下,这里不做过多解释。
-#### 4.3.3. `paxos` 算法的死循环问题
+#### paxos 算法的死循环问题
其实就有点类似于两个人吵架,小明说我是对的,小红说我才是对的,两个人据理力争的谁也不让谁🤬🤬。
@@ -147,15 +139,15 @@
那么如何解决呢?很简单,人多了容易吵架,我现在 **就允许一个能提案** 就行了。
-## 5. 引出 `ZAB`
+## 引出 `ZAB`
-### 5.1. `Zookeeper` 架构
+### Zookeeper 架构
作为一个优秀高效且可靠的分布式协调框架,`ZooKeeper` 在解决分布式数据一致性问题时并没有直接使用 `Paxos` ,而是专门定制了一致性协议叫做 `ZAB(ZooKeeper Atomic Broadcast)` 原子广播协议,该协议能够很好地支持 **崩溃恢复** 。

-### 5.2. `ZAB` 中的三个角色
+### ZAB 中的三个角色
和介绍 `Paxos` 一样,在介绍 `ZAB` 协议之前,我们首先来了解一下在 `ZAB` 中三个主要的角色,`Leader 领导者`、`Follower跟随者`、`Observer观察者` 。
@@ -165,7 +157,7 @@
在 `ZAB` 协议中对 `zkServer`(即上面我们说的三个角色的总称) 还有两种模式的定义,分别是 **消息广播** 和 **崩溃恢复** 。
-### 5.3. 消息广播模式
+### 消息广播模式
说白了就是 `ZAB` 协议是如何处理写请求的,上面我们不是说只有 `Leader` 能处理写请求嘛?那么我们的 `Follower` 和 `Observer` 是不是也需要 **同步更新数据** 呢?总不能数据只在 `Leader` 中更新了,其他角色都没有得到更新吧?
@@ -185,7 +177,7 @@
定义这个的原因也是为了顺序性,每个 `proposal` 在 `Leader` 中生成后需要 **通过其 `ZXID` 来进行排序** ,才能得到处理。
-### 5.4. 崩溃恢复模式
+### 崩溃恢复模式
说到崩溃恢复我们首先要提到 `ZAB` 中的 `Leader` 选举算法,当系统出现崩溃影响最大应该是 `Leader` 的崩溃,因为我们只有一个 `Leader` ,所以当 `Leader` 出现问题的时候我们势必需要重新选举 `Leader` 。
@@ -229,13 +221,13 @@

-## 6. Zookeeper的几个理论知识
+## Zookeeper的几个理论知识
了解了 `ZAB` 协议还不够,它仅仅是 `Zookeeper` 内部实现的一种方式,而我们如何通过 `Zookeeper` 去做一些典型的应用场景呢?比如说集群管理,分布式锁,`Master` 选举等等。
这就涉及到如何使用 `Zookeeper` 了,但在使用之前我们还需要掌握几个概念。比如 `Zookeeper` 的 **数据模型** 、**会话机制**、**ACL**、**Watcher机制** 等等。
-### 6.1. 数据模型
+### 数据模型
`zookeeper` 数据存储结构与标准的 `Unix` 文件系统非常相似,都是在根节点下挂很多子节点(树型)。但是 `zookeeper` 中没有文件系统中目录与文件的概念,而是 **使用了 `znode` 作为数据节点** 。`znode` 是 `zookeeper` 中的最小数据单元,每个 `znode` 上都可以保存数据,同时还可以挂载子节点,形成一个树形化命名空间。
@@ -264,13 +256,13 @@
* `numChildre`:该节点的子节点个数,如果为临时节点为0。
* `pzxid`:该节点子节点列表最后一次被修改时的事务ID,注意是子节点的 **列表** ,不是内容。
-### 6.2. 会话
+### 会话
我想这个对于后端开发的朋友肯定不陌生,不就是 `session` 吗?只不过 `zk` 客户端和服务端是通过 **`TCP` 长连接** 维持的会话机制,其实对于会话来说你可以理解为 **保持连接状态** 。
在 `zookeeper` 中,会话还有对应的事件,比如 `CONNECTION_LOSS 连接丢失事件` 、`SESSION_MOVED 会话转移事件` 、`SESSION_EXPIRED 会话超时失效事件` 。
-### 6.3. ACL
+### ACL
`ACL` 为 `Access Control Lists` ,它是一种权限控制。在 `zookeeper` 中定义了5种权限,它们分别为:
@@ -280,19 +272,19 @@
* `DELETE`:删除子节点的权限。
* `ADMIN`:设置节点 ACL 的权限。
-### 6.4. Watcher机制
+### Watcher机制
`Watcher` 为事件监听器,是 `zk` 非常重要的一个特性,很多功能都依赖于它,它有点类似于订阅的方式,即客户端向服务端 **注册** 指定的 `watcher` ,当服务端符合了 `watcher` 的某些事件或要求则会 **向客户端发送事件通知** ,客户端收到通知后找到自己定义的 `Watcher` 然后 **执行相应的回调方法** 。

-## 7. Zookeeper的几个典型应用场景
+## Zookeeper的几个典型应用场景
前面说了这么多的理论知识,你可能听得一头雾水,这些玩意有啥用?能干啥事?别急,听我慢慢道来。

-### 7.1. 选主
+### 选主
还记得上面我们的所说的临时节点吗?因为 `Zookeeper` 的强一致性,能够很好地在保证 **在高并发的情况下保证节点创建的全局唯一性** (即无法重复创建同样的节点)。
@@ -306,7 +298,7 @@
总的来说,我们可以完全 **利用 临时节点、节点状态 和 `watcher` 来实现选主的功能**,临时节点主要用来选举,节点状态和`watcher` 可以用来判断 `master` 的活性和进行重新选举。
-### 7.2. 分布式锁
+### 分布式锁
分布式锁的实现方式有很多种,比如 `Redis` 、数据库 、`zookeeper` 等。个人认为 `zookeeper` 在实现分布式锁这方面是非常非常简单的。
@@ -330,13 +322,13 @@
具体怎么做呢?其实也很简单,你可以让 **读请求监听比自己小的最后一个写请求节点,写请求只监听比自己小的最后一个节点** ,感兴趣的小伙伴可以自己去研究一下。
-### 7.3. 命名服务
+### 命名服务
如何给一个对象设置ID,大家可能都会想到 `UUID`,但是 `UUID` 最大的问题就在于它太长了。。。(太长不一定是好事,嘿嘿嘿)。那么在条件允许的情况下,我们能不能使用 `zookeeper` 来实现呢?
我们之前提到过 `zookeeper` 是通过 **树形结构** 来存储数据节点的,那也就是说,对于每个节点的 **全路径**,它必定是唯一的,我们可以使用节点的全路径作为命名方式了。而且更重要的是,路径是我们可以自己定义的,这对于我们对有些有语意的对象的ID设置可以更加便于理解。
-### 7.4. 集群管理和注册中心
+### 集群管理和注册中心
看到这里是不是觉得 `zookeeper` 实在是太强大了,它怎么能这么能干!
@@ -352,11 +344,9 @@

-## 8. 总结
+## 总结
-看到这里的同学实在是太有耐心了👍👍👍,如果觉得我写得不错的话点个赞哈。
-
-不知道大家是否还记得我讲了什么😒。
+看到这里的同学实在是太有耐心了👍👍👍不知道大家是否还记得我讲了什么😒。

diff --git a/docs/distributed-system/images/zookeeper/znode-structure.drawio b/docs/distributed-system/images/zookeeper/znode-structure.drawio
new file mode 100644
index 00000000..7253bacb
--- /dev/null
+++ b/docs/distributed-system/images/zookeeper/znode-structure.drawio
@@ -0,0 +1 @@
+7Vrfc5s4EP5r9HgZQAiLR7DN3fSuc53Lw7VPHRVkzAUjV8iJ3b/+JBC/iYlTO3ZmmszE0mq1Et+utN8SAzjf7H/nZLv+yCKaAsuI9gAugGWZpuHIDyU5lJIZdktBzJNIKzWC++QH1UJDS3dJRPOOomAsFcm2KwxZltFQdGSEc/bUVVuxtLvqlsR0ILgPSTqU/ptEYl1KsTVr5H/QJF5XK5uOfr5vJHyIOdtlej1gwcAJggCXwxtS2dIPmq9JxJ5aIrgEcM4ZE2Vrs5/TVGFbwVbOC54ZrffNaSZeMmE/u//7wyHA8wP9fvhq/vmPTb7/pq3k4lDhQSMJj+4yLtYsZhlJl43UD3f8kSqjpuwUABQ9Q/aaCX8xttUq/1EhDtrxZCeYFK3FJtWjK5YJPWg6sp8Lzh5qV0iU/HKLal/PPnn1GGzHQ3rkcZEOMMJjKo7ozWr/yLinbEMFP8h5nKZEJI/dfRAdgHGt1zhBNrQfTvCJdXWfSFz54bOaf4eq7hdtrugs9p3eQfdu0pf4mr6Ev3x5Tl86P+nLYqrHOTm0FLYsyUTesvxJCaSCznEQ6htcZzi7f9H29E37qL5slDtooqp+lNcHmn31QLvJgHHfQ8Ag5L59wGgEH0m6oxWBCVIWPuSDSGpCQ/n5aZ0Ier8lhX+eJCk8HgarJE3nLGW8sAUjQvEqrMOjGslYRusIeaRc0P3xGBn6VE+wcBd8iPTReGrYnWlonXWL2dnOhXKAcwTp4tO4KOKGgSEOLoi424t2R2Wa60I+m4J8yHvPCfnctpGNLhnk/RRzA5jjKcyHvPZdYQ7x7WHuTmGevW/MkXV7mFcvLjqg97lXFnnq3UQDRkTydY16C2El/0SEoDwrJJYBR7lT2xP4BC41hLYFHBrBrZKdRpEGnMbuZwUMuyZKiqdnHSNH5oShkgMODJ2LJ5nm2BlLondOkxz71miSORseo8kS5mrl8fCEdqqplx7PF5Q6pr5eJmsdNO7wy9Y6yOjFETxe6/Rro57+ZWodE78itG7jNcxFq+gXh5b5zGXyxrE1UUc77lH9C8WWNZYfzpscRpNAL2OskPrVk1vy8uc8ScNGXYDrMuR6SQNeg4x1b4Nbp2IOdivSXHEoF1aSU+nYiLHZwNilKdnYG5VfDLznqVn/Nqzq11Ndjs0JQ5d291iV+7y7w5TkeRJ2ndw9sRPkje4T8bnV/tKkbdlrErXqVHm6E11nT9FXuzp69bflvDKGHNg39LZVnDVSxS0d4BnAd8ESA+wBLCUz9dd3B+ElU6boBtRkStYikiaxuldC6Xkq5b5KwElIUk8PbJIoKvjmGCfohm2fFpwho/fLQFleDzK6MxJf0Hg+lH7un98jdEo5KgA4AEsb+Bh43ojHli7AEPgLpexipV8qy7uqnmUZPzIWUWDNR0zWg3ICUiPahA88VBidA/XNFiMrNOqNIOAtgLxpR2LISVXMfOOyFavWxKLtByjWkrZdu/skGPizQoKAvwTYVhLPBB5Wy3pSzXvpsqxetzRePwouNmAr+9Km6xWrSIlc0VANvADespq1KDYghWaxN9lARUMuJ6t5w9zc8EkKyCZJVdh/oMLnJMlkJWJ8lLhUJ626mtdCbOUYghI4pKi9/KMU8ruYsTilZJvkdyHbFANhXqgGq9K6bLbtI8tvr3DesyzpeecsI2fIzuu3ae3DjNHJh1l2m28ulZd08/UwuPwf
\ No newline at end of file
diff --git a/docs/distributed-system/images/zookeeper/zookeeper-watcher.drawio b/docs/distributed-system/images/zookeeper/zookeeper-watcher.drawio
new file mode 100644
index 00000000..3da7244d
--- /dev/null
+++ b/docs/distributed-system/images/zookeeper/zookeeper-watcher.drawio
@@ -0,0 +1 @@
+7Vjbbts4EP0aPiawRF2oR8m1tgg2wALZxW6fFqzESGxp0aXo2O7XdyhR0S321kjjGou+2JwzQ4qcOTwaG+Hlev+bopvyXuZMIHeR7xF+h1zXiTCGL4McWiQkUQsUiuc2qAce+FdmwYVFtzxn9ShQSyk034zBTFYVy/QIo0rJ3TjsUYrxUze0YDPgIaNijv7Nc122KHHDHn/PeFF2T3YCe76PNPtcKLmt7POQi9MgTVPSute0W8setC5pLncDCK8QXiopdTta75dMmNx2aWvnpUe8z/tWrNLfM4F5H/786wvZ4vv9v3dc8I85ubuxxav1ocsHyyE91pRKl7KQFRWrHk2aMzOz6gKsPuZ3KTcAOgB+YlofbK3pVkuASr0W1gsbVod/zPxbvzM/2OUa491+ZB2s9SgrbRd1ImundM2FCbhjOlGUVzUc515WsouXW5WZGaXWwCjXxzF8QJLMhwmobwspC8Hohte3mVw3jqxuQtPHdnUYDtf33cQ+oc2eSdnRolio7vZxrBId96kqmD4R5z5TB64kk2sGGYJ5igmq+dN4H9TejeI5zk6NlaKHQcBGcsjEYOU/DAAB3TUnlsT2krtkwrVJvB/5p+Jh0O6gswZH6aGGv2dw2R76iYot665kILQlwojlwZet7Bw3dUMpoMUCKrdvqtr5YVSY70xwU1C7HGqZ0zlnV6i/IIbtu5Jr9rChTfV3IKLjyzAkdWBsLsRSCqmatXBOGXnMAK+1kp9Z56lkxa7oBjwxpdn+9B2Yc7absBiTC/vW3vV67HRYOdDicHGc5gOqnc+k8JpU0TlDFYMr4sQPUUX3O1XxCMPeVhWnKucvTquiE56MfxtVdF+tik50RBVrpuDi/wxVXHqe7/n/a1X03WtTRW/GJAetMIJXO4FBgBKMYoJWPiIBIkuzU6qz0hBkwgRIih6X++UyDmpuISp4UYGZQRJhYZyYFHNo5mPrWPM8b+T4JX6NJfpadfNVrHGjSaP2EmuCF1iD34o1/ow17oA1HkpiRJJmkKAkaOiToghcIYo8FKWNK2pifASnIyu0isz0KG5iUhT7xhWvUOwaGhKCktC44gTF6S/yXZB8wZh8vjMn3zPRLkI+8jMauWltB42de3Zndw2kuOjv2x/Syc1bL0xG1PSmlGv3ZWf1rDv7hzKevLXx6ZYwfFW45/1Hwzk9tXeBhjOaCT4etQkkQjHoM0GxY9oEI92pUXgYwLsANN+oOrwUvEbwExStTHAC07GZHgVNcNNudP33L3m/hLzfOBN9x+Hb6TuY/V+jLTX7/5/x6hs=
\ No newline at end of file
diff --git a/docs/distributed-system/theorem&algorithm&protocol/cap&base-theorem.md b/docs/distributed-system/theorem&algorithm&protocol/cap&base-theorem.md
index 3d679322..9d74ccc7 100644
--- a/docs/distributed-system/theorem&algorithm&protocol/cap&base-theorem.md
+++ b/docs/distributed-system/theorem&algorithm&protocol/cap&base-theorem.md
@@ -1,5 +1,5 @@
---
-title: CAP & BASE理论
+title: CAP & BASE理论详解
category: 分布式
tag:
- 分布式协议&算法
diff --git a/docs/distributed-system/theorem&algorithm&protocol/gossip.md b/docs/distributed-system/theorem&algorithm&protocol/gossip.md
index 9f710a14..fcf42383 100644
--- a/docs/distributed-system/theorem&algorithm&protocol/gossip.md
+++ b/docs/distributed-system/theorem&algorithm&protocol/gossip.md
@@ -1,3 +1,10 @@
+---
+title: CAP & BASE理论详解
+category: 分布式
+tag:
+ - 分布式协议&算法
+---
+
## 背景
在分布式系统中,不同的节点进行数据/信息共享是一个基本的需求。
@@ -12,7 +19,7 @@ Gossip 直译过来就是闲话、流言蜚语的意思。流言蜚语有什么

-Gossip 协议也叫 Epidemic 协议(流行病协议)或者 Epidemic propagation 算法(疫情传播算法),别名很多。不过,这些名字的特点都具有 **随机传播特性** (联想一下病毒传播、癌细胞扩散等生活中常见的情景),这也正是 Gossip 协议最主要的特点。
+**Gossip 协议** 也叫 Epidemic 协议(流行病协议)或者 Epidemic propagation 算法(疫情传播算法),别名很多。不过,这些名字的特点都具有 **随机传播特性** (联想一下病毒传播、癌细胞扩散等生活中常见的情景),这也正是 Gossip 协议最主要的特点。
Gossip 协议最早是在 ACM 上的一篇 1987 年发表的论文 [《Epidemic Algorithms for Replicated Database Maintenance》](https://dl.acm.org/doi/10.1145/41840.41841)中被提出的。根据论文标题,我们大概就能知道 Gossip 协议当时提出的主要应用是在分布式数据库系统中各个副本节点同步数据。
@@ -24,23 +31,34 @@ Gossip 协议最早是在 ACM 上的一篇 1987 年发表的论文 [《Epidemic
## Gossip 协议应用
-1、我们经常使用的分布式缓存 Redis 的官方集群解决方案(3.0 版本引入) Redis Cluster 就是基于 Gossip 协议来实现集群中各个节点数据的最终一致性。
+**1、Redis Cluster 基于 Gossip 协议通信共享信息**
+
+我们经常使用的分布式缓存 Redis 的官方集群解决方案(3.0 版本引入) Redis Cluster 就是基于 Gossip 协议来实现集群中各个节点数据的最终一致性。

-Redis Cluster 中的每个 Redis 节点都维护了一份集群的状态信息,各个节点利用 Gossip 协议传递的信息就是集群的状态信息。
+Redis Cluster 是一个典型的分布式系统,分布式系统中的各个节点需要互相通信。既然要相互通信就要遵循一致的通信协议,Redis Cluster 中的各个节点基于 **Gossip 协议** 来进行通信共享信息,每个 Redis 节点都维护了一份集群的状态信息。
+
+Redis Cluster 的节点之间会相互发送多种 Gossip 消息:
+
+- **MEET** :在 Redis Cluster 中的某个 Redis 节点上执行 `CLUSTER MEET ip port` 命令,可以向指定的 Redis 节点发送一条 MEET 信息,用于将其添加进 Redis Cluster 成为新的 Redis 节点。
+- **PING/PONG** :Redis Cluster 中的节点都会定时地向其他节点发送 PING 消息,来交换各个节点状态信息,检查各个节点状态,包括在线状态、疑似下线状态 PFAIL 和已下线状态 FAIL。
+- **FAIL** :Redis Cluster 中的节点 A 发现 B 节点 PFAIL ,并且在下线报告的有效期限内集群中半数以上的节点将 B 节点标记为 PFAIL,节点 A 就会向集群广播一条 FAIL 消息,通知其他节点将故障节点 B 标记为 FAIL 。
+- ......
下图就是主从架构的 Redis Cluster 的示意图,图中的虚线代表的就是各个节点之间使用 Gossip 进行通信 ,实线表示主从复制。

-2、NoSQL 数据库 Apache Cassandra 集群通过 Gossip 协议来进行动态管理集群节点状态(节点故障检测和恢复)。
+有了 Redis Cluster 之后,不需要专门部署 Sentinel 集群服务了。Redis Cluster 相当于是内置了 Sentinel 机制,Redis Cluster 内部的各个 Redis 节点通过 Gossip 协议互相探测健康状态,在故障时可以自动切换。
-3、服务网格解决方案 Consul 使用 Gossip 协议网络内可靠有效地传输新服务和事件的信息。
+关于 Redis Cluster 的详细介绍,可以查看这篇文章 [Redis 集群详解(付费)](https://javaguide.cn/database/redis/redis-cluster.html) 。
-4、Bitcoin 使用 Gossip 协议来传播交易和区块信息。不过,为了提供更好的隐私保护,CMU 的研究人员提出 **蒲公英协议**。
+**2、NoSQL 数据库 Apache Cassandra 集群通过 Gossip 协议来进行动态管理集群节点状态(节点故障检测和恢复)。**
-5、......
+**3、服务网格解决方案 Consul 使用 Gossip 协议网络内可靠有效地传输新服务和事件的信息。**
+
+**4、Bitcoin 使用 Gossip 协议来传播交易和区块信息。不过,为了提供更好的隐私保护,CMU 的研究人员提出 蒲公英协议。**
还有非常多使用 Gossip 协议的应用,学习 Gossip 协议有助于我们搞清很多技术的底层原理。
diff --git a/docs/distributed-system/theorem&algorithm&protocol/paxos-algorithm.md b/docs/distributed-system/theorem&algorithm&protocol/paxos-algorithm.md
index ff392ece..9c6a7acb 100644
--- a/docs/distributed-system/theorem&algorithm&protocol/paxos-algorithm.md
+++ b/docs/distributed-system/theorem&algorithm&protocol/paxos-algorithm.md
@@ -1,5 +1,5 @@
---
-title: Paxos 算法
+title: Paxos 算法详细
category: 分布式
tag:
- 分布式协议&算法
diff --git a/docs/distributed-system/theorem&algorithm&protocol/raft-algorithm.md b/docs/distributed-system/theorem&algorithm&protocol/raft-algorithm.md
index e580ed55..ec8c37e4 100644
--- a/docs/distributed-system/theorem&algorithm&protocol/raft-algorithm.md
+++ b/docs/distributed-system/theorem&algorithm&protocol/raft-algorithm.md
@@ -1,5 +1,5 @@
---
-title: Raft 算法
+title: Raft 算法详解
category: 分布式
tag:
- 分布式协议&算法
diff --git a/docs/java/basis/java-keyword-summary.md b/docs/java/basis/java-keyword-summary.md
index 09113434..78e0d4a6 100644
--- a/docs/java/basis/java-keyword-summary.md
+++ b/docs/java/basis/java-keyword-summary.md
@@ -10,7 +10,10 @@
3. final 修饰的变量是常量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能让其指向另一个对象。
-说明:使用 final 方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。
+说明:使用 final 方法的原因有两个:
+
+1. 把方法锁定,以防任何继承类修改它的含义;
+2. 效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。
## static 关键字