etcd核心概念

etcd 是强一致性、分布式的key-value存储,为分布式系统或集群提供一种可靠的数据存储方式。它在网络分区期间优雅地处理leader选举,并且可以容忍机器故障,甚至在leader节点中也是如此。etcd 是典型的读多写少存储,在我们实际业务场景中,读一般占据 2/3 以上的请求。

目前较常用的etcd 3.5的性能较v3.1约翻倍提升,如下表所示(官网数据Performance | etcd):

Number of keysKey size in bytesValue size in bytesNumber of connectionsNumber of clientsTarget etcd serverAverage write QPSAverage latency per requestAverage server RSS
10,000825611leader only5831.6ms48 MB
100,00082561001000leader only44,34122ms124MB
100,00082561001000all members50,10420ms126MB

表一 etcd3.5写性能测试数据

Number of requestsKey size in bytesValue size in bytesNumber of connectionsNumber of clientsConsistencyAverage read QPSAverage latency per request
10,000825611Linearizable1,3530.7ms
10,000825611Serializable2,9090.3ms
100,00082561001000Linearizable141,5785.5ms
100,00082561001000Serializable185,7582.2ms

表二 etcd3.5读性能测试数据

etcd 的基础架构:

  • Client 层:Client 层包括 client v2 和 v3 两个大版本 API 客户端库
  • API 网络层:API 网络层主要包括 client 访问 server 和 server 节点之间的通信协议。一方面,client 访问 etcd server 的 API 分为 v2 和 v3 两个大版本。v2 API 使用 HTTP/1.x 协议,v3 API 使用 gRPC 协议。同时 v3 通过 etcd grpc-gateway 组件也支持 HTTP/1.x 协议,便于各种语言的服务调用。另一方面,server 之间通信协议,是指节点间通过 Raft 算法实现数据复制和 Leader 选举等功能时使用的 HTTP 协议。
  • Raft 算法层:Raft 算法层实现了 Leader 选举、日志复制、ReadIndex 等核心算法特性,用于保障 etcd 多个节点间的数据一致性、提升服务可用性等,是 etcd 的基石和亮点。
  • 功能逻辑层:etcd 核心特性实现层,如典型的 KVServer 模块、MVCC 模块、Auth 鉴权模块、Lease 租约模块、Compactor 压缩模块等,其中 MVCC 模块主要由 treeIndex 模块和 boltdb 模块组成。
  • 存储层:存储层包含预写日志 (WAL) 模块、快照 (Snapshot) 模块、boltdb 模块。其中 WAL 可保障 etcd crash 后数据不丢失,boltdb 则保存了集群元数据和用户写入的数据。

要理解etcd 源码,首先要理解以下内容:

1. Raft协议

可通过动画该协议理解:Raft 分布式共识算法动画演示

(1)Leader 选举

(2)日志复制

(3)数据一致性保证

2. MVCC多版本控制

MVCC 机制正是基于多版本技术实现的一种乐观锁机制.有乐观锁就有悲观锁,两种锁都能保证数据的安全,不存在孰优孰劣,分适用场景。悲观锁比较好理解就是先加锁,加锁既可以是对代码块加锁(如Java的synchronized关键字),也可以是对数据加锁(如MySQL中的排它锁)。

乐观锁实现方式常见的实现方式有两种:CAS(Compare And Swap)机制和版本号机制。

etcd v3存储的逻辑视图是一个扁平的二进制键空间。etcd的键空间可维护多个revision.每个原子的修改操作都会在键空间创建一个新的version,之前version 的所有数据均保持不变。新建一个key,version为1;删除key,version重置为0来结束key的生命周期;对key的每一次修改都会增加其version,因此,key的version在key的一次生命周期中是单调递增的。

但是reversion是一直增加的。boltdb中存储的key是reversion,value是etcd自己的key-value组合,即上面说的。etcdv3会在boltdb中保存每个版本,从而实现多版本机制。新建、更新、删除都会记录一个新的revision.

3. boltdb存储

etcd 数据存储在基于 B+ treemmap 的数据库的 boltdb中,下图是db 文件磁盘布局图。从图中的左边部分你可以看到,文件的内容由若干个 page 组成,一般情况下 page size 为 4KB. 

etcdv2的每个key只保留一个value,所以数据库并不大,可以直接放在内存中。但是etcd v3实现了MVCC后,每个key的value都需要保存多个历史版本,内存中存不下,因此使用boltdb将数据存储中磁盘中。

boltdb只提供简单的key/value存储,官网上说是一种GO语言嵌入式键值v数据库。代码精简(小于3KB),非常适合在其上构建更加复杂的数据库功能。BoltDB基本原理是用mmap将磁盘的page映射到内存的page,而操作系统则是通过 COW ( copy - on - write )技术进行 page 管理,通过COW 技术,系统可实现无锁的读写并发,但是无法实现无锁的写写并发,这就注定了这类数据库读性能超高,但写性能一般,因此非常适合于"读多写少"的场景。同时 BoltDB 支持完全可序列化的 ACID 事务。因此最适合作为 etcd 的底层存储引擎。

B+树中键值对的key即revison,是一个2元组(main, sub),其中main是该revison的主版本号,sub是同一个revison的副版本号,用于区分同一个revision的不同key.例如通过etcdctl来写入两条数据put key1 'v1' key2 'v2';然后再更新一下put key1 'v12' key2 'v22';那么boltdb中包含4条数据:

rev={3,0}, key=key1, value='v1'

rev={3,1}, key=key2, value='v2'

rev={4,0}, key=key1, value='v12'

rev={4,1}, key=key2, value='v22'

4. 日志和快照管理

etcd 对数据的持久化,采用的是 binlog (日志,也称为WAL,即 Write - Ahead - Log )加 Snapshot (快照)的方式。
在计算机科学中,预写式日志( Write - Ahead - Log , WAL )是关系数据库系统中用于提供原子性和持久性( ACID 属性中的两个)的一系列技术。在使用 WAL 的系统中,所有的修改在提交之前都要先写入 log 文件中。

□ wal :用于存放预写式日志,其最大的作用是记录整个数据变化的全部历程。在 etcd 中,所有数据的修改在提交前,都要先写入 WAL 中。使用 WAL 进行数据的存储使得 etcd 拥有故障快速恢复和数据回滚这两个重要功能。WAL 文件存储在 etcd 数据目录的 member/wal 子目录中。

□ snap :用于存放快照数据。 etcd 为防止 WAL 文件过多会创建快照, snap 用于存储 etcd 的快照数据状态。生成快照后,etcd 可以删除包含在 Snapshot 中的旧 WAL 文件,从而减少磁盘使用量和加快恢复速度。Snapshot 文件存储在 etcd 数据目录的 member/snap 子目录中。

既然有了 WAL 实时存储所有的变更,那么为什么还需要做快照呢?因为随着使用量的增加, WAL 存储的数据会暴增,为了防止磁盘很快就爆满, etcd 默认每10000条记录做一次快照,做过快照之后的 WAL 文件就可以删除。而通过 API 可以查询的历史 etcd 操作默认为1000条。另外一个场景:如果某个节点故障下线后,又添加了一个小节点,那么向这个新节点拷贝数据时,可以只需要先复制整个快照,然后复制剩下的较少量的 binlog即可。

另外,BoltDB 是 etcd 的底层存储引擎,用于存储实际的数据。读写时都会通过boltdb,WAL和snapshot只是日志副本工具。etcd 启动的时候,会通过 mmap 机制将 db 文件映射到内存,后续可从内存中快速读取文件中的数据。写请求通过 fwrite 和 fdatasync 来写入、持久化数据到磁盘。WAL只在写数据时会用到,snapshot和读写都没关系,是一些场景触发的快照。boltdb通过高效的 B+ 树数据结构提供键值对存储和检索功能,并支持 ACID 特性的事务,保证数据的一致性和完整性。BoltDB 文件存储在 etcd 数据目录的 member 子目录中,通常是 member/snap/db.例如,/var/lib/etcd/member/snap/db.

最后放两张etcd读写流程图便于理解:

etcd读请求执行过程

etcd写请求执行过程

最后,留一个思考题,etcd既然是基于raft协议的,那么会不会出现数据不一致的情况呢?

参考:

1. 杜军 等,《云原生分布式存储基石——etcd深入解析》,机械工业出版社

2. 唐聪,《etcd实战课》,极客时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值