etcd 启动分析_etcd简单解析

ETCD

ETCD是一个分布式的,强一致性的k-v存储。主要用于服务的注册与发现,以及共享配置

为什么需要etcd

分布式系统面临的问题是多节点之间的数据共享,所以分布式系统要么自己实现一个可靠的共享存储来同步信息,要么依赖一个可靠的共享存储服务(etcd)

etcd 可以提供什么

提供存储以及获取数据的接口,它通过协议保证 Etcd 集群中的多个节点数据的强一致性。用于存储元信息以及共享配置。

提供监听机制,客户端可以监听某个key或者某些key的变更(v2和v3的机制不同,参看后面文章)。用于监听和推送变更。

提供key的过期以及续约机制,客户端通过定时刷新来实现续约(v2和v3的实现机制也不一样)。用于集群监控以及服务注册发现。

提供原子的CAS(Compare-and-Swap)和 CAD(Compare-and-Delete)支持(v2通过接口参数实现,v3通过批量事务实现)。用于分布式锁以及leader选举。

- 一致性

通过Raft协议提供一致性 (文末介绍)

- 数据存储

etcd的存储分为内存存储和持久化(硬盘)存储两部分

内存中的存储除了顺序化的记录下所有用户对节点数据变更的记录外,还会对用户数据进行索引、建堆等方便查询的操作。

持久化则使用预写式日志(WAL:Write Ahead Log)进行记录存储。\

在WAL的体系中,所有的数据在提交之前都会进行日志记录。

在etcd的持久化存储目录中,有两个子目录。

WAL,存储着所有事务的变化记录;

snapshot,用于存储某一个时刻etcd所有目录的数据。\

通过WAL和snapshot相结合的方式,etcd可以有效的进行数据存储和节点故障恢复等操作。

etcd默认每10000条记录做一次snapshot,经过snapshot以后的WAL文件就可以删除

首次启动时,etcd会把启动的配置信息存储到data-dir参数指定的数据目录中。

配置信息包括本地节点的ID、集群ID和初始时集群信息。

用户需要避免etcd从一个过期的数据目录中重新启动,因为使用过期的数据目录启动的节点会与集群中的其他节点产生不一致

WAL

WAL(Write Ahead Log)预写式日志, 最大的作用是记录了整个数据变化的全部历程

- 在etcd中,所有数据的修改在提交前,都要先写入到WAL中。

使用WAL进行数据的存储使得etcd拥有两个重要功能。

故障快速恢复: 当你的数据遭到破坏时,就可以通过执行所有WAL中记录的修改操作,快速从最原始的数据恢复到数据损坏前的状态。

数据回滚(undo)/重做(redo):因为所有的修改操作都被记录在WAL中,需要回滚或重做,只需要方向或正向执行日志中的操作即可。

WAL结构

- Etcd 解析

wal日志是二进制的,解析出来后是以上数据结构LogEntry。

第一个字段type,只有两种一种是0表示Normal,1表示ConfChange(ConfChange表示 Etcd 本身的配置变更同步,比如有新的节点加入等)。

第二个字段是term,每个term代表一个主节点的任期,每次主节点变更term就会变化。

第三个字段是index,这个序号是严格有序递增的,代表变更序号。

第四个字段是二进制的data,将raft request对象的pb结构整个保存下。

WAL有两种模式,读模式(read)和数据添加(append)模式,两种模式不能同时成立。

一个新创建的WAL文件处于append模式,并且不会进入到read模式。

一个本来存在的WAL文件被打开的时候必然是read模式,并且只有在所有记录都被读完的时候,才能进入append模式,进入append模式后也不会再进入read模式。这样做有助于保证数据的完整与准确。

集群在进入到etcdserver/server.go的NewServer函数准备启动一个etcd节点时,会检测是否存在以前的遗留WAL数据。

检测的第一步是查看snapshot文件夹下是否有符合规范的文件,若检测到snapshot格式是v0.4的,则调用函数升级到v0.5。

从snapshot中获得集群的配置信息,包括token、其他节点的信息等等

然后载入WAL目录的内容,从小到大进行排序。根据snapshot中得到的term和index,找到WAL紧接着snapshot下一条的记录,然后向后更新,直到所有WAL包的entry都已经遍历完毕,Entry记录到ents变量中存储在内存里。

此时WAL就进入append模式,为数据项添加进行准备。

当WAL文件中数据项内容过大达到设定值(默认为10000)时,会进行WAL的切分,同时进行snapshot操作。

这个过程可以在etcdserver/server.go的snapshot函数中看到。

所以,实际上数据目录中有用的snapshot和WAL文件各只有一个,默认情况下etcd会各保留5个历史文件。

Raft 一致性算法

共识算法Raft通过集群中唯一的领导者管理集群其他服务器上的日志复制来保证数据一致性。共识问题在Raft中被分解为leader选举、log复制两个相对独立的子问题。

一致性问题

在分布式系统中,一致性问题(consensus problem)是指对于一组服务器,给定一组操作,我们需要一个协议使得最后它们的结果达成一致。

leader选举机制

Raft集群中每个节点有三种状态:Follower,Candidate,Leader,状态之间是互相转换。节点启动的初始状态为follower,每个Follower节点上都有一个倒计时器 (随机在 150ms 到 300ms 之间设置Election Timeout时间),倒计时截止后状态转换为Candidate,并开始发起leader选举。Follower节点通过接受leader hearteat或者candidate RequestVote请求重设Election Timeout来维持Follower状态。

Follower节点定时器截止后增加当前的term(一段任意的时间序号,相当于一个国家的朝代,每个Term以选举开始,如果选举成功,则集群会在当前Term下由当前的leader管理),节点状态转换为Candidate。

Candidate节点首先增加投票计数器,投票给自己作为新的领导者,然后向集群中的其他服务器发送RequestVote RPC请求。

收到RequestVote的服务器,在同一term中只会按照先到先得投票给一个与自身log一样或者更(gèng)新的candidate节点。

Candidate 节点获得超过一半的节点投支持票,该节点状态将转换为leader。其它Candidate 节点收到term值等于或大于当前自身term值得leader hearteat后,该节点状态将转换为follower。如果Candidate 节点定时器截止,仍没有选出leader,将由最先截止的Candidate 节点发起下一轮投票(解决多个Candidate同时获取相同选票无法确定leader问题)。

随机设置Election Timeout时间,可避免多个follower同时变为Candidate状态,发起leader投票。

日志复制机制

Raft集群采用master/slave结构,leader为master,follower为slave,只有leader能够接收client请求。

leader节点接收客户端的请求命令转换为操作记录并写入日志。

leader节点向其他的服务器发送AppendEntries RPCs请求。

follower节点接收到leader的AppendEntries RPCs请求后,将操作日志写入日志并返回结果给leader节点。

leader节点收到半数以上的节点回应该条记录已写入日志,则可认为该记录是有效的,leader节点将该记录提交,并将执行结果返回给客户端。leader节点在下次心跳AppendEntries RPCs请求中,会记录可被提交的日志条目编号commitIndex。

follower节点在收到leader的AppendEntries RPCs请求后,会根据请求中的commitIndex,将本地日志中commitindex

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值