etcd的MVCC和租约和Watch原理分析

1 MVCC流程

mvcc(多版本并发控制,mysql中也使用到了)解决的就是读写时的线程安全问题,线程不用去争抢读写锁。

查询

更新

2 Lease(租约)流程

一个key一个TTL太占内存,同时性能不高。说白了就相当于租房的一个合同而已,这个合同可以管理很多key,在合同的时间围之内,我的key存在你那里是有效的,你不能删除我关联到此Lease上的key-value。

2.1 架构

  1. 创建Lease流程(跟put流程差不多)最 终会保存LeaseId到ItemMap和boltdb中
  2. Lease关联key流程:在put的时候会 根据参数去掉Attach方法,将Key关 联到Lease的key内存集合ItemSet中
  3. 过期自动淘汰流程

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满了,事件没有被执行怎么办?

  1. Etcd的watch并不会丢弃,这个时候会将watch从synced watcherGroup删除,并放到victim watchBatch中

  2. 然后上面说的那个sync VictimLoop协程开始干活,就是不断去看victim watchBatch里面有没有watch,有就重试事件的执行

➢ syncVictimsLoop工作流程

  1. 遍历victim watcherBatch数据结构,尝试将堆积的事件再次推送到watcher的接收channel中。若推送失败,则再次加入到victim watcherBatch数据结构中等待下次重试。
  2. 若推送成功,watcher监听的最小版本号(minRev)小于等于server当前版本号(currentRev),说明可能还有历史事件未推送,需加入到unsynced watcherGroup中,由下面介绍的历史事件推送机制, 推送minRev到currentRev之间的事件。
  3. 若watcher的最小版本号大于server当前版本号,则加入到synced watcher集合中,进入上面介绍的最新事件通知机制。

3.7 高效匹配watch

➢ 监听单个key的watch ⚫ 使用map进行存储匹配

➢ 监听key范围或者前缀的watch ⚫ 使用区间树进行匹配


etcd的MVCC和租约和Watch原理分析
http://www.zivjie.cn/2023/04/15/云原生(容器化)/etcd/etcdMVCC和租约和Watch原理分析/
作者
Francis
发布于
2023年4月15日
许可协议