Etcd 按照官方介绍
java
Etcd is a distributed, consistent key-value store for shared configuration and service discovery算法
etcd 是一个分布式一致性键值存储,用于共享配置和服务发现,专一于:apache
简单: 良好定义的,面向用户的API (gRPC)
安全: 带有可选客户端证书认证的自动 TLS
快速: 测试验证,每秒 10000 写入
可靠: 使用Raft适当分布安全
etcd是Go编写,并使用 Raft 一致性算法来管理高可用复制日志。网络
为何须要 Etcd 并发
全部的分布式系统,都面临的一个问题是多个节点之间的数据共享问题,这个和团队协做的道理是同样的,成员能够分头干活,但老是须要共享一些必须的信息,好比谁是 leader, 都有哪些成员,依赖任务之间的顺序协调等。因此分布式系统要么本身实现一个可靠的共享存储来同步信息(好比 Elasticsearch ),要么依赖一个可靠的共享存储服务,而 Etcd 就是这样一个服务。分布式
Etcd 提供什么能力ide
Etcd 主要提供如下能力,已经熟悉 Etcd 的读者能够略过本段。oop
提供存储以及获取数据的接口,它经过协议保证 Etcd 集群中的多个节点数据的强一致性。用于存储元信息以及共享配置。性能
提供监听机制,客户端能够监听某个key或者某些key的变动。用于监听和推送变动。
提供key的过时以及续约机制,客户端经过定时刷新来实现续约。用于集群监控以及服务注册发现。
提供原子的CAS(Compare-and-Swap)和 CAD(Compare-and-Delete)支持(v2经过接口参数实现,v3经过批量事务实现)。用于分布式锁以及leader选举。
Etcd 如何实现一致性的
Etcd使用Raft协议来维护集群内各个节点状态的一致性。简单说,Etcd集群是一个分布式系统,由多个节点相互通讯构成总体对外服务,每一个节点都存储了完整的数据,而且经过Raft协议保证每一个节点维护的数据是一致的。
如图所示,每一个Etcd节点都维护了一个状态机,而且,任意时刻至多存在一个有效的主节点。主节点处理全部来自客户端写操做,经过Raft协议保证写操做对状态机的改动会可靠的同步到其余节点。
Etcd工做原理核心部分在于Raft协议。本节接下来将简要介绍Raft协议,具体细节请参考其[论文]。
Raft协议正如论文所述,确实方便理解。主要分为三个部分:选主,日志复制,安全性。
1) 选主
Raft协议是用于维护一组服务节点数据一致性的协议。这一组服务节点构成一个集群,而且有一个主节点来对外提供服务。当集群初始化,或者主节点挂掉后,面临一个选主问题。集群中每一个节点,任意时刻处于Leader, Follower, Candidate这三个角色之一。选举特色以下:
当集群初始化时候,每一个节点都是Follower角色;
集群中存在至多1个有效的主节点,经过心跳与其余节点同步数据;
当Follower在必定时间内没有收到来自主节点的心跳,会将本身角色改变为Candidate,并发起一次选主投票;当收到包括本身在内超过半数节点同意后,选举成功;当收到票数不足半数选举失败,或者选举超时。若本轮未选出主节点,将进行下一轮选举(出现这种状况,是因为多个节点同时选举,全部节点均为得到过半选票)。
Candidate节点收到来自主节点的信息后,会当即终止选举过程,进入Follower角色。
为了不陷入选主失败循环,每一个节点未收到心跳发起选举的时间是必定范围内的随机值,这样可以避免2个节点同时发起选主。
2) 日志复制
所谓日志复制,是指主节点将每次操做造成日志条目,并持久化到本地磁盘,而后经过网络IO发送给其余节点。其余节点根据日志的逻辑时钟(TERM)和日志编号(INDEX)来判断是否将该日志记录持久化到本地。当主节点收到包括本身在内超过半数节点成功返回,那么认为该日志是可提交的(committed),并将日志输入到状态机,将结果返回给客户端。
这里须要注意的是,每次选主都会造成一个惟一的TERM编号,至关于逻辑时钟。每一条日志都有全局惟一的编号。
主节点经过网络IO向其余节点追加日志。若某节点收到日志追加的消息,首先判断该日志的TERM是否过时,以及该日志条目的INDEX是否比当前以及提交的日志的INDEX跟早。若已过时,或者比提交的日志更早,那么就拒绝追加,并返回该节点当前的已提交的日志的编号。不然,将日志追加,并返回成功。
当主节点收到其余节点关于日志追加的回复后,若发现有拒绝,则根据该节点返回的已提交日志编号,发生其编号下一条日志。
主节点像其余节点同步日志,还做了拥塞控制。具体地说,主节点发现日志复制的目标节点拒绝了某第二天志追加消息,将进入日志探测阶段,一条一条发送日志,直到目标节点接受日志,而后进入快速复制阶段,可进行批量日志追加。
按照日志复制的逻辑,咱们能够看到,集群中慢节点不影响整个集群的性能。另一个特色是,数据只从主节点复制到Follower节点,这样大大简化了逻辑流程。
3) 安全性
截止此刻,选主以及日志复制并不能保证节点间数据一致。试想,当一个某个节点挂掉了,一段时间后再次重启,并当选为主节点。而在其挂掉这段时间内,集群如有超过半数节点存活,集群会正常工做,那么会有日志提交。这些提交的日志没法传递给挂掉的节点。当挂掉的节点再次当选主节点,它将缺失部分已提交的日志。在这样场景下,按Raft协议,它将本身日志复制给其余节点,会将集群已经提交的日志给覆盖掉。
这显然是不可接受的。
其余协议解决这个问题的办法是,新当选的主节点会询问其余节点,和本身数据对比,肯定出集群已提交数据,而后将缺失的数据同步过来。这个方案有明显缺陷,增长了集群恢复服务的时间(集群在选举阶段不可服务),而且增长了协议的复杂度。
Raft解决的办法是,在选主逻辑中,对可以成为主的节点加以限制,确保选出的节点已定包含了集群已经提交的全部日志。若是新选出的主节点已经包含了集群全部提交的日志,那就不须要从和其余节点比对数据了。简化了流程,缩短了集群恢复服务的时间。
这里存在一个问题,加以这样限制以后,还可否选出主呢?答案是:只要仍然有超过半数节点存活,这样的主必定可以选出。由于已经提交的日志必然被集群中超过半数节点持久化,显然前一个主节点提交的最后一条日志也被集群中大部分节点持久化。当主节点挂掉后,集群中仍有大部分节点存活,那这存活的节点中必定存在一个节点包含了已经提交的日志了。
至此,关于Raft协议的简介就所有结束了。
Etcd的使用场景
和ZK相似,Etcd有不少使用场景,包括:
配置管理
服务注册于发现
选主
应用调度
分布式队列
分布式锁
这三个产品是常常被人拿来作选型比较的。 Etcd 和 Zookeeper 提供的能力很是类似,都是通用的一致性元信息存储,都提供watch机制用于变动通知和分发,也都被分布式系统用来做为共享信息存储,在软件生态中所处的位置也几乎是同样的,能够互相替代的。两者除了实现细节,语言,一致性协议上的区别,最大的区别在周边生态圈。Zookeeper 是apache下的,用java写的,提供rpc接口,最先从hadoop项目中孵化出来,在分布式系统中获得普遍使用(hadoop, solr, kafka, mesos 等)。Etcd 是coreos公司旗下的开源产品,比较新,以其简单好用的rest接口以及活跃的社区俘获了一批用户,在新的一些集群中获得使用(好比kubernetes)。虽然v3为了性能也改为二进制rpc接口了,但其易用性上比 Zookeeper 仍是好一些。 而 Consul 的目标则更为具体一些,Etcd 和 Zookeeper 提供的是分布式一致性存储能力,具体的业务场景须要用户本身实现,好比服务发现,好比配置变动。而Consul 则以服务发现和配置变动为主要目标,同时附带了kv存储。