06-etcd多版本并发控制
本文主要分析了 etcd v3 为什么选择了 MVCC,以及 etcd v3 中的 MVCC 大致实现原理。
原文作者: 意琦行
1. 为什么选择MVCC
etcd v2 是一个内存数据库,整个数据库拥有一个Stop-the-World
的大锁,通过锁机制来解决并发带来的数据竞争。
但是存在并发性能问题:
锁的粒度不好控制,每次都会锁整个数据库
写锁和读锁相互阻塞。
前面的事务会阻塞后面的事务,对并发性能影响很大。
同时在高并发环境下还存在另一个严重的问题:
- watch 机制可靠性问题:etcd 中的 watch 机制会依赖旧数据,v2 版本基于滑动窗口实现的 watch 机制,只能保留最近的 1000 条历史事件版本,当 etcd server 写请求较多、网络波动时等场景,很容易出现事件丢失问题,进而又触发 client 数据全量拉取,产生大量 expensive request,甚至导致 etcd 雪崩。
熟悉 Kubernetes 的朋友肯定知道,Kubernetes 使用 etcd 做存储,因此 etcd 的问题对 Kubernetes 有很直观的影响,具体如下:
- etcd 并发性能问题导致 Kubernetes 集群规模受限。
- watch 机制可靠性问题直接影响到 Kubernetes controller 的正常运行。
在 Kubernetes 中,各种各样的控制器实现了 Deployment、StatefulSet、Job 等功能强大的 Workload。控制器的核心思想是监听、比较资源实际状态与期望状态是否一致,若不一致则进行协调工作,使其最终一致。而这些特性的实现都严重依赖 etcd 的 watch 机制。
而 etcd 背后的公司 CoreOS 也是 Kubernetes 容器生态圈的核心成员之一,此时的 Kubernetes 和 Docker 公司还处于一个激烈的对抗之中,因此,此时的 etcd 迫切的需要解决以上的两个问题。
那么 etcd v3 为什么要选择 MVCC 呢?
解决并发问题的方法有很多,而MVCC 在解决并发问题的同时,还能通多存储多版本数据来解决watch 机制可靠性问题。
因此 etcd v3 版本果断选择了基于 MVCC 来实现多版本并发控制。
于是v3则采用了MVCC
,以一种优雅的方式解决了锁带来的问题。
执行写操作或删除操作时不会再原数据上修改而是创建一个新版本。
这样并发的读取操作仍然可以读取老版本的数据,写操作也可以同时进行。
这个模式的好处在于读操作不再阻塞,事实上根本就不需要锁。
客户端读key的时候指定一个版本号,服务端保证返回比这个版本号更新的数据,但不保证返回最新的数据。
MVCC能最大化地实现高效地读写并发,尤其是高效地读,非常适合读多写少
的场景。
2. MVCC 初体验
如下面的命令所示,第一次 key hello 更新完后,我们通过 get 命令获取下它的 key-value 详细信息。正如你所看到的,除了 key、value 信息,还有各类版本号。
这里我们重点关注 mod_revision,它表示 key 最后一次修改时的 etcd 版本号。
当我们再次更新 key hello 为 world2 后,然后通过查询时指定 key 第一次更新后的版本号,你会发现我们查询到了第一次更新的值,甚至我们执行删除 key hello 后,依然可以获得到这个值。那么 etcd 是如何实现的呢?
|
|
- 原文作者:长亭远望
- 原文链接:https://www.lvmo.work/2022/04/11/mvcc-analyze.html
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。