etcd 凭借自身高效的一致性共识协议 (Raft) 和对存储数据高效的组织结构 (B-Tree 和 B+Tree), 已事实上成为云原生社区 “水和电” 一般的基础设施, 其重要性不言而喻;
因此有必要了解一下 etcd 的相关原理知识;
etcd 的逻辑时钟
Revision 是 etcd 中用于标识数据变更顺序的全局逻辑时钟: 每次对 etcd 的写操作(如 Put、Delete)都会生成一个新的 Revision,且 Revision 是单调递增的;
Revision 是一个 64 位整数,由两部分组成:
- 主版本号(Main Revision):高 56 位,表示全局的变更次数;
- 子版本号(Sub Revision):低 8 位,表示同一主版本下的多次变更(例如,在一次事务中可能包含多个操作);
etcd 的索引
key 索引
etcd 使用了一个内存数据结构 kvindex 实现了对 key 的索引, kvindex 使用了 google 开源的 btree 库提供的一个高效的 B-Tree 实现, 支持并发操作和自定义的键值比较逻辑; 其中每个 B-Tree 节点存储了以下内容:
- key: key 的名称, 用于索引;
- 版本信息(Revision):键的版本号,用于记录键的修改历史;
- 生成索引(Generation Index):用于跟踪键的生命周期(创建、更新、删除);
- 其他元数据:如键的创建时间、修改时间等;
revision 索引
用于追踪 Key 的历史版本和变更事件, etcd 使用了 google 开源的 BoltDB 实现, 该单机数据库使用了 B+Tree 来维护 Revision 索引, 每个 Revision 都关联一个事件 (对应到一个或多个 Key-Value 的变化):
- 每次对 etcd 的写事件 (如 Put、Delete) 都会生成一个新的全局单调递增的 Revision;
- 通过 Revision 索引, 可以查询 Key 的历史版本或特定时间点的数据;
lease 索引
用于管理 Key 的租约(Lease)和生存时间(TTL):
- 租约是一个时间期限,可以为 Key 设置租约,当租约到期时,Key 会自动删除;
- etcd 维护一个 Lease 索引,记录每个租约及其关联的 Key;
- 通过 Lease 索引,可以快速查找某个租约关联的所有 Key;
watch 索引
用于支持 Watch 机制,实时监听 Key 的变更事件:
- etcd 维护一个 Watch 索引,记录每个客户端注册的 Watch;
- 当 Key 发生变更时,etcd 会查找 Watch 索引,找到所有监听该 Key 的客户端,并发送事件通知;
Watch 索引的数据结构: watcherGroup, 它使用一个 Map 来存储每个 Key 对应的 watchers 列表:
- keyWatchers:
- key: 被监听的精确 key;
- value: watchers 列表,包含所有监听该 Key 的客户端 Watch;
- rangeWatchers:
- key: 被监听的 key 的前缀 (使用 B-Tree 作为索引);
- value: watchers 列表,包含所有监听该 Key 前缀的客户端 Watch;
1 | type watcherGroup struct { |
具体举例:
用户发起 etcd watch 请求:
1
2
3
4
5
6
7# client1 发起
etcdctl watch /zookeeper
etcdctl watch /zoo/ --prefix
# client2 发起
etcdctl watch /zoo/ --prefix
etcdctl watch /zoo/tiger --prefix
etcdctl watch /zoo/tiger-bigetcd 注册 watch 对象:
1
2
3
4
5
6
7
8
9
10
11watcherGroup:
- keyWatchers:
+------------------------------+
| /zookeeper -> [watcher1] |
| /zoo/tiger-big -> [watcher2] |
+------------------------------+
- rangeWatchers:
+------------------------------+
| /zoo -> [watcher1, wathcer2] |
| /zoo/tiger -> [watcher2] |
+------------------------------+key /zoo/tiger-big 发生了变更, etcd 生成对应的事件;
- etcd 去 watcherGroup keyWatchers 查找有无 key 精确匹配, 如有则将事件下发到对应的 watchers;
- etcd 去 watcherGroup rangeWatchers 根据 B-Tree 索引查找有无匹配的 key 前缀, 如有则将事件下发到对应的 watchers;
compact 索引
用于管理数据压缩和历史数据的清理:
- etcd 支持基于 Revision 的数据压缩,可以删除指定 Revision 之前的所有历史数据;
- Compact 索引记录每次压缩操作的 Revision,确保不会误删未压缩的数据;