你想了解的k8s-etcd一致性分布式数据库精讲(2)- etcd节点竞选原理


title: k8s之etcd节点竞选
date: 2018-12-03 16:15:00
tags: [‘k8s’,‘etcd’]
category: etcd
article: k8s之etcd二

竞选流程

etcd内部采用raft协议来实现,所以在etcd里面,节点有3个状态,一开始都是follower节点,然后接收leader的心跳信息,如果接收不到,就进入candidate进入下一轮term发起竞选,等到收到集群多数节点的投票时,该节点就会转变成新的leader节点。leader节点有可能出现故障,导致follower接收不到心跳,这时候就会发生上面的竞选,新的leader产生以后,旧的leader就会变成follower。其实就是有新的leader之后,所有其他节点都会变成follower。

成为leader也是有条件的,比如你的数据完整性,在竞选投票的时候,如果其他节点发现你的数据不完整,是不会给你投票的。

节点损坏

节点可能会因为各种原因损坏,导致无法正常工作。如果是leader节点那么就会导致follower收不到心跳而触发竞选机制,如果是follower节点,那么我们可以将这个节点删除以后在创建新的节点。因为损坏的节点依然会被计算在etcd总节点之中。

etcd采用基于仲裁模型的分布式共识,即(n + 1) / 2成员(多数)必须就提案一致才能提交给集群。因此当有follower损坏的时候,我们需要先删除在创建,而不能先创建在删除。

比如:如果有一个3个成员的集群,有一个成员损坏,那么这个集群仍然可以正常工作,这个时候删除损坏成员,该集群依然可以正常工作,然后添加新节点,这个行为是存在风险的,因为他可能会导致配置错误或无法加入集群,这种情况下,集群依然可以正常工作。而如果正确加入,依然可以正常工作。那我们想一下先增加新成员,如果增加失败,那么该集群总成员数量变成4个,而其中有1个早已损坏,还有一个刚添加的同样算是损坏,这将会使仲裁失效,所以默认情况下,etcd会拒绝这种成员的添加。

读写流程

etcd采用强一致性,实时同步,所以读的话,你从哪个节点读取都一样。对于写入来说,写入请求总会被leader先获取,然后leader节点广播给其他节点,当多数节点通过以后,这次写入会被提交,然后同步follower节点。一个已提交的数据才是真正存储下来的数据。

数据模型

etcd旨在可靠地存储不经常更新的数据并提供可靠的监视查询。etcd公开了以前版本的键值对,以支持快照和观看历史事件(“时间旅行查询”)。持久的多版本并发控制数据模型非常适合这些用例。

etcd将数据存储在多版本持久键值存储中。持久键值存储在其值被新数据取代时,保留键值对的先前版本。键值存储实际上是不可变的; 它的操作不会直接更新结构,而是始终生成新的结构。所有以前版本的密钥仍然可以访问,并且在修改后可以观看。为了防止数据存储随着时间的推移无限增长以及维护旧版本,可以压缩存储以删除最旧版本的数据。

逻辑视图

对于数据的存储保留了多个版本,每个原子变异操作(例如,事务操作可以包含多个操作)在key space上创建新的版本。之前修订的所有数据保持不变。旧版本的key仍可通过以前的版本访问。同样,版本也被编入索引; 对观察者进行修订是有效的。如果压缩存储以节省空间,则将删除紧凑版本之前的版本。版本在群集的生命周期内单调递增。

一个key的生命周期,从创造到删除。每个key可以有一个或多个生命周期。创建key会增加该key的版本,如果当前版本中不存在key,则从1开始。删除key会生成key的逻辑删除,通过将key的版本重制为0来结束key的当前生命周期。key的每次修改都会增加其版本;因此,版本在key的一个生命周期中单调增加。一旦压缩发生,之前设置的值将被删除。

物理视图

etcd将物理数据存储为持久b+树中的键值对。存储状态的每个版本仅包含其先前版本的增量,以实现高效。单个版本可以对应于树中的多个键。

键值对的关键是3元组(major, sub, type)。Major是持有key的存储版本。Sub在同一版本中的键之间进行区分。Type是特殊值的可选后缀。键值对的值包含先前版本的修改,因此是先前版本的一个增量。b+树按词汇顺序,字节顺序排序。对版本增量的远程查找很快; 这样可以快速找到从一个特定版本到另一个版本,压缩删除过时的键值对。

etcd还保留了辅助内存中的btree索引,以加快对key的范围查询。btree索引中的键是向用户公开的存储的键。该值是指向持久性b+树的修改的指针。压缩删除死指针。

关于WAL

WAL(Write Ahead Log)预写式日志,是etcd的数据存储方式。除了在内存中存有所有数据的状态以及节点的索引外,etcd就通过WAL进行持久化存储。WAL 中,所有的数据提交前都会事先记录日志。Snapshot 是为了防止数据过多而进行的状态快照;Entry 表示存储的具体日志内容。

在 WAL 的体系中,所有的数据在提交之前都会进行日志记录。在 etcd 的持久化存储目录中,有两个子目录。一个是 WAL,存储着所有事务的变化记录;另一个则是 snapshot,用于存储某一个时刻 etcd 所有目录的数据。通过 WAL 和 snapshot 相结合的方式,etcd 可以有效的进行数据存储和节点故障恢复等操作。

既然有了 WAL 实时存储了所有的变更,为什么还需要 snapshot 呢?随着使用量的增加,WAL 存储的数据会暴增,为了防止磁盘很快就爆满,etcd 默认每 10000 条记录做一次 snapshot,经过 snapshot 以后的 WAL 文件就可以删除。

命名规则

在 etcd 的数据目录中,WAL 文件以 s e q seq- index.wal的格式存储。最初始的 WAL 文件是0000000000000000-0000000000000000.wal,表示是所有 WAL 文件中的第 0 个,初始的 Raft 状态编号为 0。运行一段时间后可能需要进行日志切分,把新的条目放到一个新的 WAL 文件中。

假设,当集群运行到 Raft 状态为 20 时,需要进行 WAL 文件的切分时,下一份 WAL 文件就会变为0000000000000001-0000000000000021.wal。如果在 10 次操作后又进行了一次日志切分,那么后一次的 WAL 文件名会变为0000000000000002-0000000000000031.wal。可以看到-符号前面的数字是每次切分后自增 1,而-符号后面的数字则是根据实际存储的 Raft 起始状态来定。

snapshot 的存储命名则比较容易理解,以 t e r m term- index.wal格式进行命名存储。term 和 index 就表示存储 snapshot 时数据所在的 raft 节点状态,当前的任期编号以及数据项位置信息。

参考文章

https://www.infoq.cn/article/etcd-interpretation-application-scenario-implement-principle

发布了30 篇原创文章 · 获赞 6 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/Thepatterraining/article/details/105215670