1. Etcd V2与V3存储差异
在 Etcd v2 与 v3 两个版本中,使用的存储方式完全不同,所以两个版本的数据并不兼容,对外提供的接口也是不一样的,不同版本的数据是相互隔离的,只能使用对应的版本去存储与获取。
1.1. V2——基于内存的存储
在 v2 版本中,数据是以树形结构完全存储在内存中的,只有进行持久化的时候才会将数据以 JSON 格式存储进磁盘。
1.1.1. v2的 watch 机制
- 在 v2 版本中,存在着一个 EventHistory 表,EventHistory 表是有长度限制的,默认是1000.
- v2 中存在一个全局的版本 currentIndex,有数据更新时 currentIndex++
- 在客户端 watch 的时候,如携带 waitIndex(小于 currentindex),那么会从 EventHistory 表中查询出从 waitIndex 开始并且与watch key 匹配的 event 返回。
- v2版本的 watch 机制并不可靠,当客户端断连,如果此时 event 的条数超过 eventHistory 表的最大长度时候,当客户端重连的时候可能会出现 event 的丢失(v3版本解决了这个问题,但是如果进行了压缩也是会清理掉之前的版本)
eventQueue 是一个先进先出的环形队列,当 eventQueue 填满后继续添加会导致最先添加的 Event 示例被覆盖
watcher 只能监听某一个key及其子节点
1.1.2. v2 的 node
- CreatedIndex:记录了当前节点创建的 currentIndex 值
- ModifiedIndex:记录了当前节点最后一次更新的 currentIndex 值
- store:指向当前节点关联的v2版本实例
v2版本中,节点的过期时间是存储在 node 的 ExpireTime,v3 的过期是通过租约 lease 来实现的
1.2. V3 store
在v3中,store的实现分为两部分
- backend store:可以使用不同的存储,默认使用BoltDB(单机的支持事务的键值对存储)
- 内存索引,基于 http://github.com/google/btree 的b树索引实现
etcd 在 BoltDB 中存储的 ke y是 revision,value 是 etcd 自定义的键值对组合,etcd 会将键值对的每个版本都保存到 BoltDB 中,所以 etcd 能实现多版本的机制
每次查询键值对需要通过 revision 来查找,所以会在内存中维护一份 B树索引,关联了一个 keyIndex 实例用来映射 key 与 revision,并维护了多个版本的 revision,客户端只会根据 key 去获取数据而不是 revision
由 revision 的结构可以看出 reversion 有 main reversion 和 sub reversion 组成,每次事务的话 main reversion 递增,同个事务中每次操作(put等)则是 sub reversion 递增
主要流程:先扫描存储B树索引得到对应的revision,然后查询BoltDB得到真正的键值对数据,反序列化为KeyValue并封装成RangeResult返回
v3版本的存储废弃了树形的存储结构但是可以通过前缀的方式来模拟
1.2.1. 多个version的区别
- revision 由 main revision 和 sub revision 组成,每次事务的话 main revision 递增,同个事务中每次操作(put等)则是 sub revision 递增
- Kv中的:
- CreateRevision:最近一次创建当前键值对的revision
- ModRevision:最近一次修改当前键值对的revision
- Version:当前键值对的版本,每次修改递增,删除则置为0
1.3. v2/v3 版本的 etcdctl 操作
由于 v2 和 v3 版本的 API 不兼容,在使用 etcdctl 操作时访问不同的 API 版本需要声明版本的变量
例如是 V3 版本
$ export ETCDCTL_API=3
$ etcdctl member list
或者
$ ETCDCTL_API=3 etcdctl member list