-
将数据存储在集群中的高可用 K-V 存储
-
允许应用实时监听存储中的 K-V 变化
-
能够容忍单点故障,能够应对网络分区
-
一个班级 60 人
-
有一个秘密,告知给班里的 31 个人
-
那么随便挑选 31 个人,一定有 1 个人知道秘密
-
Raft 是强一致的集群日志同步算法
-
etcd 是一个分布式 KV 存储
-
etcd 利用 raft算法 在集群中同步 key-value
Quorum模型
集群需要 2N+1 个节点
日志实时复制(Replication)
+---------------------------------------------+
| |
| |
| |
| |
| |
| v
+---+--------+ +-------------+ +--------+------+
| | | | | |
| leader +---->+ follower | | follower |
| | | | | |
+--+----+----+ +-------------+ +---------------+
^ |
| | 复制给 N+1 节点后,本地提交,返回客户端
| |
| v
+--+----+----+
| |
| 调用者 | 写入性能差:1000次/秒
| |
+------------+
Quorum模型
集群需要 2N+1 个节点
异步通知 followers 完成提交
+---------------------------------------------+
| |
| |
| |
| |
| |
| v
+---+--------+ +-------------+ +--------+------+
| | | | | |
| leader +---->+ follower | | follower |
| | | | | |
+--+----+----+ +-------------+ +---------------+
^ |
| | 复制给 N+1 节点后,本地提交,返回客户端
| |
| v
+--+----+----+
| |
| 调用者 | 写入性能差:1000次/秒
| |
+------------+
日志格式
1 2 3 4 5 6 7 8 log index
+------+------+------+------+------+------+------+------+
| 1 | 1 | 1 | 2 | 3 | 3 | 3 | 3 | leader
| | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | x<+5 | x<+4 |
+------+------+------+------+------+------+------+------+
+------+------+------+------+------+------+ +----+
| 1 | 1 | 1 | 2 | 3 | 3 | |
| | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | |
+------+------+------+------+------+------+ |
|
|
+------+------+------+------+------+------+------+------+ |
| 1 | 1 | 1 | 2 | 3 | 3 | 3 | 3 | |
| | | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | x<+5 | x<+4 | |
+------+------+------+------+------+------+------+------+ |
|
+---+ followers
|
+------+------+ |
| 1 | 1 | |
| | | |
| x<+3 | y<+1 | |
+------+------+ |
|
|
+------+------+------+------+------+------+------+ |
| 1 | 1 | 1 | 2 | 3 | 3 | 3 | |
| | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | x<+5 | |
+------+------+------+------+------+------+------+ +----+
+<---------------------------------------------->+
committed entries
1 2 3 4 5 6 7 8 log index
+ +
| |
+------+------+------+------+------+------+-------------+
| 1 | 1 | 1 | 2 | 3 | 3 | 3 | 3 | leader
| | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | x<+5 | x<+4 |
+------+------+------+------+------+------+-------------+
| |
+------+------+------+------+------+------+ | +----+
| 1 | 1 | 1 | 2 | 3 | 3 | | |
| | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | | |
+------+------+------+------+------+------+ | |
| | |
| | |
+------+------+------+------+------+------+-------------+ |
| 1 | 1 | 1 | 2 | 3 | 3 | 3 | 3 | |
| | | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | x<+5 | x<+4 | |
+------+------+------+------+------+------+-------------+ |
| | |
| | +---+ followers
| | |
+------+------+ | |
| 1 | 1 | | |
| | | | |
| x<+3 | y<+1 | | |
+------+------+ | |
| | |
| | |
+------+------+------+------+------+------+------+ |
| 1 | 1 | 1 | 2 | 3 | 3 | 3 | |
| | | | | | | | |
| x<+3 | y<+1 | y<+9 | x<+2 | x<+0 | x<+7 | x<+5 | |
+------+------+------+------+------+------+------+ +----+
| |
+<---------------------------------------------->+
| committed entries |
+ +
图中 log index 代表日志索引,简单展示了 leader 以及所有 followers 的 committed 日志情况,容易得出只有 日志索引(log index) 为 7 状态为 committed 的节点 超过 2N+1。
todo
-
选举 leader 需要半数以上节点参与
-
节点 commit 日志最多的允许选举为 leader
-
commit 日志同样多,则 term、index 越大的允许选举为 leader
todo
-
提交成功的请求,一定不会丢
-
各个节点的数据将最终一致
-
通用的 HTTP+JSON 协议,性能抵消
-
SDK 内置 GRPC 协议,性能高校
-
底层存储是按 key 有序排列的,可以顺序遍历
-
因为 key 有序,所有 etcd 天然支持按目录结构高效遍历
-
支持复杂事务,提供类似 if ... then ... else ... 的事务能力
-
基于租约机制实现 key 的 TTL 过期
存储引擎是按 Key 有序排列的:
/config/database
/feature-flags/verbost-logging
/feature-flags/redesign
获取子目录内容,只需要 seek 到不大于 /feature-flags/ 的第一个 key,开始向后 SCAN 即可
Put /key1 value1 -> revision=1
Put /key2 value2 -> revision=2
Put /key1 value3 -> revision=3
-
提交版本(revision) 在 etcd 中单调递增
-
同 key 维护多个历史版本,用于实现 watch 机制
-
历史版本过多,可以通过执行 compact 命令完成删减
-
通过 watch 机制,可以监听某个 key,或者某个目录(key前缀)的连续变化。
-
常用语分布式系统的配置分发、状态同步。
todo
-
搭建单机 etcd,熟悉命令行操作
-
golang 调用 put/get/delete/lease/watch 方法
-
使用 txn事务功能,实现分布式乐观锁