etcd数据存储及数据多版本控制实现逻辑

etcdV2数据存储机制

etcd v2 是一个纯内存数据库,整个数据库在内存中是一个简单的树结构.。写操作先通过 Raft 复制日志文件,复制成功后将数据写人内存。
etcd v2 并未实时地将数据写人磁盘, 持久化是靠快照来实现的,具体实现就是将整个内存中的数据复制一份出来, 然后序列化成 JSON ,写人磁盘中,成为一个快照 。
做快照的时候使用的是复 制出来的数据库,客户端的读写请求依旧落在原始的数据库上,这样的话,做 快照的操作才不会阻塞客户端的读写请求 。
因为操作系统对内存进行了分页,内存的复制操作实际上是 cow( Copy-On -Write )的,只有当某一个内存页发生更改时才会发生 实际的复制行为 ,即只有那些被 客户端读写到的数据页才会在内存中被复制, 因此此操作而花费很多时间,也不会造成内存使用量的显著增加 。

etcdV3数据模型

etcd v2 的每个 key 只保留 一个 value ,所以数据量不大 , 可以直接放在 内 存中 。 但 是 etcd d 实现了 MVCC 以后,每个 key 都会保存多个历史版本,数据量会很大,因此需要保存到硬盘。
etcd v3 将数据存储在一个多版本的持久化 key-value 存储里面,后台的键值存储实际上是不可变的,当持久键值存储的值发生变化时, etcd 操作不会就地修改原记录,而是生成一个更新之后的新条目进行保存 。 key 先前版本的所有值仍然可以访问和watch。由于保存了所有的历史版本数据,为了防止数据无限期增长,etcd 可能会压缩(删除) key 的旧版本数据。

数据结构

etcdV3 采用两个树来实现数据的存储和查找。
物理B+树存储版本-取值映射
etcd 将物理 数据存储在 B +树中 的键值对 。B +树中 以包含主版本号(main )和副版本号(sub)的revision 作为关键字,main 是该 etcd 数据的索引号(每次有数据更改索引号都会增加), sub 是副版本号,主要用于区分一次事务更改的多个键值。
大致结构如下。
在这里插入图片描述
etcd v3 当前使用 BoltDB引擎实现数据的物理存储。
BoltDB 是根据 HowardChu 的LMDB 项目开发的一个纯粹的 Go 语言版的key/value存储。它的目标是为项目提供一个简单、高效、可靠的嵌入式的、可 序列化的键/值数据库。它只提供简单的 key/value存储,BoltDB支持事务,没有其他的特性,代码精简(小于 3KB ),质量高, 非常适合“读多写少”的场景 ,因此其也非常适合于 etcd。
etcd 会在 BoltDB 中保存每个版本,从而实现多版本机制(结构见上节)
示例:
分别通过两个事务,写入 key1 和 key2 的值,则 boltDB中保存了四条记录如下
put keyl ”vl" put key2”v2”
put keyl ”vl1" put key2”v22”,

BoltDB树形结构中节点信息如下:
rev={3 0),key=keyl,value=” v l ”
rev={3 1) ,key=key2,value=”v2”
rev={4 0),key=keyl,value=” v l 2 "
rev={4 1),key=key2,value=”v22"

B+树中叶子节点的 value 包含了本次修改的某个键值的内容,包括:key、value、key创建的revision等。
B+树按 版本号字节序进行排序 。 etcd d 对 revision 增量的范围 查询会很快

内存B树存储key-版本映射
上述结构中是基于版本号进行存储的,但是一般etcd是根据key来进行数据查找和读写的,因此为了高效,etcd v3 还在内存中维护了一个基于 B 树的二级索引来加快对 key 的范围查 询 。
该 B 树 关键字(key) 是 etcd v3 存储的 数据的key,value是指向 B+树版本号指针 。如果一个数据key被多次操作(有多个版本操作记录),所有的key都会保存在这个B树节点取值中。大致结构如下:

在这里插入图片描述
etcd基于 Google 开源的GoJang 的 B 树实现该功能

etcdV3MVCC实现

BoltDB key 结构

etcd V3 实 现了 MVCC ,对 每 个 key 的 value 值都保存了历 史 版 本 ,每 个 value 都对应了一 个版本 号 ,这个版 本 号在 etcd v3 中就是 revision ,其数据结构定义如下所示:
在这里插入图片描述
1 ) 每个事务都有唯一事务 ID ,全局递增不重复 即 revision 的 mainID 。
2 )一个事务可以包含多个修改操作( PUT 和 DELETE ),每个修改操作均对 应于一个 revision , 但共享同一个 main。 因此 , 我们有时候也称 revision 为修订。
3 )一个事务内连续的多个修改操作都会从 0 开始递增编号作为sub

内存索引取值结构

在内存的索引中 ,每个 key 都会关联一个 key_index 结构,里 面维护了多版本信息, 示例代码具体如下:
在这里插入图片描述
1) key 字段就是用户的原始 key,
2)modified 字段记录 了这个 key 的最后一次修 改对应的 revision 信息 。
3)generations 保存key的多版本信息(历史修改记录)

generation结构定义如下:
在这里插入图片描述
当一 个 key 从 无 到 有 的时 候 ,就 会 创 建 一个generation, 其 created 字 段记录了引起 本 次 key 创建的 revision 信息 。 当 用户继续更新这个 key 的时候, generation .revs 数组会不 断追加记录本次 的revision 信息( main , sub ) 。
如果一个key被删除后,又被再次创建,则新建一个generation。所以generations 是一个数组。

BoltDB取值结构

在 BoltDB 中 存储的 key 是 revision, value 是一个 ISON 序列化后的 结构: key、 value 、版 本号, 创 建该 key 时 etcd 的 revision 、本次更新时 etcd 的 revision 、租约 ID 等,具体代码如 下所示:
在这里插入图片描述

如此:对 key 进行指定版本号 查询时,etcd 从内存的索引中查询到该 key 大于 curRev 的版本号,再去 BoltDB 中读取数据 ,返回 给客户端即可 。

历史版本压缩

持续更新 同 一个 key ,那么 generation.revs 就会一直变大,etcd采用 compact 来压缩历史版本,即 当历史版本达到一定的数量时 ,会删除一些历史版本 ,只保存最近的一些版本 ,下面的示例展示压缩一个 keyIndex 时, generations 数组的 变化
在这里插入图片描述
在这里插入图片描述

key一旦删除就会结束当前的 generation ,生成新的 generation 。 在上面的 代码块中,小括号里的 t 即 tombstone ,表示该 key 被删除了 。 compact(n) 表示压缩掉“ revision.main <= n ” 的所有历史版本。

除了内存索引的版本信息被压缩,boltdb中的历史数据也会被删除

etcd为什么选择boltdb

底层的存储引擎一般包含如下三大类的选择 :
SQL Lite 等 SQL 数据库 。
LevelDB 和 RocksDB 。
LMDB 和 BoltDB 。

SQL Lite 支持 ACID 事务。但是作为一个关系型数据库,SQL Lite主 要定位于提供高效灵活的 SQL 查询语句支持,可以支持复杂的联表查询等。而 etcd 只是一个简单的KV 数据库,并不需要复杂的SQL 支持。

Leve IDB 和 RocksDB 分别是 Google 和 Facebook 开发的存储引 擎, RocksDB 是在 LeveIDB 的 基础上针对 Flash 设 备做了优 化。基本原理是将有序的 key/value 存 储在不同的文件中,并通过“层级”将它们分开,并且周期性地将小的文件合 并为大的文件,这样做就能把随机写转化为顺序写,从而提高随机写的性能,因此特别适合“写多读少”和“随机写多”的场景。Leve IDB 和 RocksDB 都不支持完整的ACID 事务。

LMDB 和 BoltDB 则是基于 B 树和 mmap的数据库,基本原理是用 mmap 将磁盘的 page 映射到内存的 page ,而操作系统是通过 COW (copy-on-write) 技术进行 page管理,通过 cow 技术,系统可实现无锁的读写并发,但是无法 实现无锁的写写并发,这类数据库读性能超高,但写性能一般,因 此非常适合于 “读多写少”的场景。同时BoltDB 支持完全可序列化的ACID 事务。因此最适合作为etcd 的底层存储引擎。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catch that elf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值