ETCD——基础原理

2020-11-07  本文已影响0人  DevilRoshan

"A distributed, reliable key-value store for the most critical data of a distributed system."

一个分布式、可靠 key-value 存储分布式系统。

应用场景

架构

ETCD.png

一个ETCD集群一般由3个或者5个节点组成,两个quorum一定存在交集,则
quorum=(n+1)/2
即:3个节点容忍1个节点故障,5个节点容忍2个节点故障,以此类推。

etcd功能.png

主要APIs

etcd数据版本号机制

etcd MVCC和stream watch

Put(key, value1) rev = 5
Put(key, value2) rev = 6
Get(key) --> value2
Get(key, rev=5) --> value1
...

默认为最新版本,可以指定版本号

watcher := Watch(key, rev)
for {
    event := watcher.Recv()
    handle(event)
    ...
}

指定旧版本,可以拿到从旧版本到当前的所有的数据版本更新

mvcc.png

首先,所有的数据都保存在B+树(灰色),当我们指定了版本信息之后,会直接到灰色B+树中去获取相关的数据;同时,还有另外一个B+树,它维护了key和revions的映射关系,查询key的数据时候,会根据key查询到revision,再通过revision查询到相应的key。

etcd mini-transactions

Txn.If(
    Compare(Value(key1),">", "bar"),
    Compare(Version(key1),"=", 2),
    ...
).Then(
    Put(key2, valueX)
    Delete(key3)
    ...
).Else(
    Put(key2, valueY)
    ...
).Commit()
  • 当key1的值大于“bar”,且key1的版本等于2的时候,将key2的值设为valueX,并删除key3;
  • 否则,将key2的值设为valueY;
  • 提交。

etcd Lease 的概念和用法

租约,检测一个节点是否存活。key1和key2绑定到lease租约上。

将多个key绑定到同一个lease对象之上,大幅提高etcd性能。

如何保证一致性?

etcd 使用 raft 协议来维护集群内各个节点状态的一致性。简单说,etcd 集群是一个分布式系统,由多个节点相互通信构成整体对外服务,每个节点都存储了完整的数据,并且通过 Raft 协议保证每个节点维护的数据是一致的。

每个 etcd 节点都维护了一个状态机,并且,任意时刻至多存在一个有效的主节点。主节点处理所有来自客户端写操作,通过 Raft 协议保证写操作对状态机的改动会可靠的同步到其他节点。

数据模型

etcd 的设计目标是用来存放非频繁更新的数据,提供可靠的 Watch插件,它暴露了键值对的历史版本,以支持低成本的快照、监控历史事件。这些设计目标要求它使用一个持久化的、多版本的、支持并发的数据数据模型。

当 etcd 键值对的新版本保存后,先前的版本依然存在。从效果上来说,键值对是不可变的,etcd 不会对其进行 in-place 的更新操作,而总是生成一个新的数据结构。为了防止历史版本无限增加,etcd 的存储支持压缩(Compact)以及删除老旧版本。

逻辑视图

从逻辑角度看,etcd 的存储是一个扁平的二进制键空间,键空间有一个针对键(字节字符串)的词典序索引,因此范围查询的成本较低。

键空间维护了多个修订版本(Revisions),每一个原子变动操作(一个事务可由多个子操作组成)都会产生一个新的修订版本。在集群的整个生命周期中,修订版都是单调递增的。修订版同样支持索引,因此基于修订版的范围扫描也是高效的。压缩操作需要指定一个修订版本号,小于它的修订版会被移除。

一个键的一次生命周期(从创建到删除)叫做 “代 (Generation)”,每个键可以有多个代。创建一个键时会增加键的版本(version),如果在当前修订版中键不存在则版本设置为1。删除一个键会创建一个墓碑(Tombstone),将版本设置为0,结束当前代。每次对键的值进行修改都会增加其版本号 — 在同一代中版本号是单调递增的。

当压缩时,任何在压缩修订版之前结束的代,都会被移除。值在修订版之前的修改记录(仅仅保留最后一个)都会被移除。

物理视图

etcd 将数据存放在一个持久化的 B+ 树中,处于效率的考虑,每个修订版仅仅存储相对前一个修订版的数据状态变化(Delta)。单个修订版中可能包含了 B+ 树中的多个键。

键值对的键,是三元组(major,sub,type)

键值对的值,包含从上一个修订版的 Delta。B+ 树 —— 键的词法字节序排列,基于修订版的范围扫描速度快,可以方便的从一个修改版到另外一个的值变更情况查找。

etcd 同时在内存中维护了一个 B 树索引,用于加速针对键的范围扫描。索引的键是物理存储的键面向用户的映射,索引的值则是指向 B+ 树修该点的指针。

典型使用场景

元数据存储——Kubernetes

Service Discovery(Name Service)

Distributed Coordination: Leader Election

1.--auto-compaction-retention

由于ETCD数据存储多版本数据,随着写入的主键增加历史版本需要定时清理,默认的历史数据是不会清理的,数据达到2G就不能写入,必须要清理压缩历史数据才能继续写入;

所以根据业务需求,在上生产环境之前就提前确定,历史数据多长时间压缩一次;例如生产环境现在升级后是默认一小时压缩一次数据。这样可以极大的保证集群稳定,减少内存和磁盘占用。

2.--max-request-bytes

etcd Raft消息最大字节数,ETCD默认该值为1.5M; 但是很多业务场景发现同步数据的时候1.5M完全没法满足要求,所以提前确定初始值很重要; 由于1.5M导致我们线上的业务无法写入元数据的问题,

例如升级之后把该值修改为默认32M,但是官方推荐的是10M,可以根据业务情况自己调整。

3.--quota-backend-bytes

ETCDdb数据大小,默认是2G,当数据达到2G的时候就不允许写入,必须对历史数据进行压缩才能继续写入;参加1里面说的,启动的时候就应该提前确定大小,官方推荐是8G。

/usr/bin/etcd --auto-compaction-retention '1' --max-request-bytes '33554432' --quota-backend-bytes '8589934592'
上一篇下一篇

猜你喜欢

热点阅读