etcd的MVCC和租约和Watch原理分析
1 MVCC流程
mvcc(多版本并发控制,mysql中也使用到了)解决的就是读写时的线程安全问题,线程不用去争抢读写锁。

查询

更新

2 Lease(租约)流程
一个key一个TTL太占内存,同时性能不高。说白了就相当于租房的一个合同而已,这个合同可以管理很多key,在合同的时间围之内,我的key存在你那里是有效的,你不能删除我关联到此Lease上的key-value。
2.1 架构
- 创建Lease流程(跟put流程差不多)最 终会保存LeaseId到ItemMap和boltdb中
- Lease关联key流程:在put的时候会 根据参数去掉Attach方法,将Key关 联到Lease的key内存集合ItemSet中
- 过期自动淘汰流程

2.2 源码

2.3 优化
➢ 续期的优化
⚫ 从网络通信上优化,http转成了gRPC
⚫ 从TTL上优化,以前一个key要创建一个TTL,现在多个key绑定同一个Lease
➢ 淘汰优化
⚫ 以前是遍历所有的TTL,看到没到期
⚫ 现在所有的Lease存一个对象到最小堆里,按到期时间升序排,只要找堆顶的少数数据就可以停止循环找了
3 Watch流程
3.1 推拉模式
➢ 拉模式
⚫ Etcdv2的实现方式
⚫ 一般通过定时任务定时拉取,时效性不高,一般不会发生消息堆积
⚫ 当watch过多的时候,QPS过高会导致接口崩溃,同时销毁大量的socket资源
➢ 推模式
⚫ Etcdv3的实现方式
⚫ 一般基于发布订阅的方式去实现,时效性高,可能造成消息堆积
⚫ 当client因网络等异常出现连接闪断后,通过版本号,它就可从server端的boltdb中获取错过的 历史事件,而无需全量同步,它是etcd Watch机制数据增量同步的核心
3.2 事件存储
➢ 滑动窗口
⚫ Etcdv2的实现方式
⚫ 仅保存有限的最近历史版本到内存中(EventHistory中的eventQueue)
⚫ 优点就是eventQueue固定容量是1000,最多保存1000条事件,超过了就删除最早的事件,这不会 造成OOM,缺点就是不可靠啊
➢ MVCC
⚫ Etcdv3的实现方式
⚫ MVCC机制则将历史版本保存在磁盘中,避免了历史版本的丢失,极大的提升了Watch机制的可靠性
3.3 可靠的事件推送机制
➢ 整体架构 ➢ 最新的事件推送 ➢ 发生异常了重试机制 ➢ 历史事件推送
3.4 架构

3.5 源码

3.6 异常场景重试流程
➢ 发生异常比如网络波动,或者channel满了,事件没有被执行怎么办?
Etcd的watch并不会丢弃,这个时候会将watch从synced watcherGroup删除,并放到victim watchBatch中
然后上面说的那个sync VictimLoop协程开始干活,就是不断去看victim watchBatch里面有没有watch,有就重试事件的执行
➢ syncVictimsLoop工作流程
- 遍历victim watcherBatch数据结构,尝试将堆积的事件再次推送到watcher的接收channel中。若推送失败,则再次加入到victim watcherBatch数据结构中等待下次重试。
- 若推送成功,watcher监听的最小版本号(minRev)小于等于server当前版本号(currentRev),说明可能还有历史事件未推送,需加入到unsynced watcherGroup中,由下面介绍的历史事件推送机制, 推送minRev到currentRev之间的事件。
- 若watcher的最小版本号大于server当前版本号,则加入到synced watcher集合中,进入上面介绍的最新事件通知机制。
3.7 高效匹配watch
➢ 监听单个key的watch ⚫ 使用map进行存储匹配
➢ 监听key范围或者前缀的watch ⚫ 使用区间树进行匹配
