2020年8月27日
在研究DCache过程中,发现其计划使用ETCD作为RouterServer的分布式协调组件,所以顺便研究了一下,帮助大家了解ETCD的功能、用途以及重要原理。
1 简介
1.1 功能特性
ETCD是一种用于实现共享配置、服务发现的分布式一致性系统,具备如下功能特性:
- GO语言实现的,K/V分布式一致性存储系统
- 提供HTTP API, 支持POST/GET/DELETE操作
- 支持SSL客户端安全认证
- 支持KEY持有TTL属性
- 支持目录(树形)操作
- 支持多KEY的事务操作
1.2 架构说明
HTTP Server:用于处理客户端HTTP请求
Store:用于处理客户端大部分事务(读)
Raft:etcd的一致性协议,核心模块,数据新增或变更时调用Raft模块;
WAL:Write ahead Log,预写式日志,是etcd的持久化存储方式
Snapshot,是为了防止日志文件过多而进行的快照存储
Entry,是存储日志的具体内容。
1.3 用途
鉴于ETCD的上述特性,其可以应用于:配置中心、服务注册发现、选主、分布式锁、应用调度,分布式队列,等等场景中。
1.4 与zookeeper对比
与zookeeper对比,etcd在项目实现,一致性协议易理解性,运维,安全等多个维度上,都占据优势。
1、一致性协议
etcd使用raft协议,zk使用zab(类paxos协议),前者易于理解,方便工程实现。ZooKeeper的部署、维护、使用比较复杂,需要安装客户端。
2、多语言适配
etcd提供http+json,grpc接口,跨平台语言;zk则需要使用其专用客户端,且官方只提供了Java和C两种语言的接口。
3、访问安全方面
etcd支持https访问,zk在这方面缺失。
5、etcd读写性能
每个实例每秒支持一千次写操作。这个性能还是相当可观的。越多,由于数据同步涉及到网络延迟,会根据实际情况越来越慢,而读性能会随之变强,因为每个节点都能处理用户请求。
2 基本概念
2.1 超时时间
在Raft算法中有2种超时设置:
1、选举超时时间(electric timeout)
当follower超过此时间未收到leader的心跳消息,会先发起投票,选举Leader。
2、心跳超时时间(heartbeat timeout)
- Leader定时(heartbeat timeout)向follower发送心跳消息,日志复制是随着心跳消息发送的。
2.2 term
新的leader时代,每发生一次leader选举,都会刷新term值+1。
2.3 角色
ETCD中存在3种角色
- leader
- follower
- candidate
3 一致性算法 --Raft
分布式协调系统的一致性算法,主要体现在选举和日志复制的过程中。
3.1 选举过程
1、所有节点初始状态为 follower
2、当 follower 没有收到 Leader的心跳时,角色就转变为 candidate,更新term值;投票给自己,然后给其他 follower发vote请求;
- 如果此时集群里有其他 candidate,也发起了投票(vote)请求,则follwer的投票响应遵循“先到先得”原则,并且只能投票给一个candidate;也就是说谁的投票请求先到达 follower,谁就会获得该follower的投票;后到达的投票请求无法获得投票(即voteResponse中标识位为false) 。
- 收到投票请求的节点会重置自己的选举超时时间,避免发起重复选举;
3、当candidate获得集群中半数以上的投票时,升级为Leader,开始日志复制。
4、当多个candidate收集到的票数相同,且commitIndex一致的情况下,会等待一个选举周期,进行下一次选举;
3.2 日志复制(Log replication)
3.2.1 二阶段提交
- leader接到客户端请求,会先写log;
- 将请求log发送给所有follower;follower跟leader一样写log,成功后给予响应;
- Leader 统计响应,如有超过半数响应成功,leader本地提交,响应客户端,然后发送commit消息给follower;
- follower接收到commit消息后提交本地变更
- 最终达到数据一致性
3.2.2 异常情况
某个follower出现异常,恢复后的数据同步:
- 如果在同步过程中有1个follower掉线,这个节点收不到后续的数据内容
- 在Leader节点上会维护每个follower当前的 commitIndex,并一直尝试发送 commitIndex 的提交请求;
- 当这个节点恢复后,状态仍为follower,等待leader消息;
- leader消息到来,follower提交本地 commitIndex 这条数据;
- 循环这个过程,直到 follower数据与其他节点一致;
3.4 重新选举
- 当leader宕机或网络异常时,follower在超过选举超时时间(electic timeout)后,变成cadidate,进入投票选举过程
- cadidate发起投票,重复“选举过程”
3.5 其他情况
当各follower数据不一致时,选举流程如下:
1、cadidate给 follower发送 vote请求,并附带以下信息
- term,这个cadidate当前所处的选举周期
- lastLogIndex,log中最新Index的位置
- lastLogTerm,log中最新Index是在哪个选举周期产生的
2、follower在接收到vote请求时,会跟自身情况对比,每个follower保存的信息有:
- currentTerm,follower所处的选举周期;
- Log[],本节点上的数据;
- commitIndex, log中最后一个提交的index;
3、比较规则:
- 先看是否处于同一选举周期,若term < currentTerm,follower对此投票请求不予理睬(返回false);
- 如果follower已经购票给了别人,则返回false;
- 如果处于同一选举周期,再看数据的新旧程度;若 lastLogIndex<commitIndex,follower对此投票请求不予理睬(返回false);
- 以上都满足,则反馈投票,并等待选举结束;
3.6 参考资料
Raft动画演示:Raft
Raft一致性算法演示:Raft Consensus Algorithm
4 其他问题
4.1 日志压缩
- Log是以追加的方式写入的,会越来越大;
- 对log采用快照的方式进行备份;并清理log中已备份、提交的内容
- 快照的另一个作用是:当有新节点加入时,或者某一个follower落后较多时,可以通过快照加载数据
- Leader必须偶尔发送一次快照给follower
4.2 客户端访问流程
- 客户端随机挑选一台etcd通信
- 如果不是leader,请求会被拒绝;follower会在响应消息中携带接收到的 leader(地址)信息;
- 客户端再次发送请求到Leader,进行交互;
- 如果Leader这时候挂了,客户端访问会超时,等待一段时间重复这个过程。
5 总结
etcd工作流程总结:
- 所有节点在leader,cadidate,follower之间切换
- 在选举阶段,cadidate向其他节点发送vote请求;最终只有包含所有最新数据的节点才能升级为leader;
- 在数据同步阶段,采用二阶段提交:
- Leader在收到客户端变更请求后,先将数据写入本地log,然后发送给所有follower;
- follower接受数据后给予成功或失败响应;
- Leader在收到超过半数的成功响应后,提交本地log,并广播提交给follower;
- follower在收到提交确认后提交数据