一、简介
ETCD 是CoreOS基于Raft协议开发的分布式键值存储系统,通过分布式锁、选主、写屏障实现可靠的分布式协作,并提供配置共享和服务发现等功能。类型提供同样功
能的系统还有Zookeeper等,ETCD相对于Zookeeper 有以下优点:
1. 使用简单、容易部署:提供基于HTTP+JSON的API 接口,etcd本身由GO语言编写可跨平台部署;
2. 支持HTTPS相对更安全;
3. 采用Raft协议保证一致性,相对于PAXOS更容易理解。
二、原理介绍
ETCD整体架构如下:
HTTP SERVER接收请求后检查配额、限速、鉴权等,然后转发到RAFT模块进行一致性处理, 处理完成后数据变更为unstable 状态,然后leader会通知其他follower节点
来同步数据,并发送给WAL模块写日志,当超过半数的follower同步完成后,leader将数据变更为commited状态并通过MVCC 模块写入数据并最终落盘。其中RAFT模块实现
Raft 共识算法来保证一致性,该算法主要包括3部分:Leader选举、日志同步、安全性。
1. Leader选举
ETCD 通过 Raft 协议来保证集群内节点数据的一致性。Raft 协议在集群初始化时、已有主节点挂掉时发起选举。选举中一共存在三种角色:Follower/Leader/Candidate
选举开始时,每个节点都是Follower,同时规定集群中最多只能由一个Leader,当Follower 没有收到Leader的心跳就会自动转换成Candidate,并发起投票。如果该节点收到
超过集群节点总数一半以上的投票后,就转为Leader,此时其他Candidate 收到新Leader的心跳后终止投票并转换为Follower。为了防止2个节点同时发起投票,每个节点发
起投票的时间为随机值,以此避免循环选举失败。
2. 日志同步
ETCD通过日志同步在集群内同步数据,Leader节点上的每一次操作都会记录日志,并持久化落盘到本地,最后同步给Follower,当超过半数的Follower 都同步成功后,
Leader节点将日志状态修改为commited,并返回给客户端写成功。为了保证日志顺序一致,每一条日志都拥有term + index 2个字段,term代表Leader 在线时间,index为递
增序列号,Follower 收到同步日志消息后,会比较日志中的term 和节点term,以及日志中的index和节点上一次的committed index, 只有当日志中的term 没有过期并且
index 比当前commited index大的情况下才追加日志,并返回同步成功。
3. 安全性
如果主节点挂掉后引发集群重新选主,并且在集群正常工作期间,原来的主节点一直处于down 的状态没有加入集群,那么这一段时间集群产生的日志无法同步给down
掉的节点。如果这个down 的节点重新上线后,再次因为某些原因触发选主操作,并且重新当选为主节点,那么它将缺失一部分数据;假如此时的主节点直接按Raft协议发起
日志同步,将导致其他节点上较新的数据被覆盖。为了解决这种场景的问题,一般可以让新选的主节点与其他节点进行数据对比,并同步缺失的数据,但是这会增加集群恢
复时间(集群没有选出leader前不可用)。Raft协议 通过term + index来限制选主的条件,其他节点发现down 的节点的index 更小,则判断数据不完整,拒绝投票选择该节
点成为主节点。
三、常见应用场景
1. 服务发现
服务提供商以服务名为key,node_ip + port 为value,将自己注册到ETCD中,并设置TTL定时保持服务心跳刷新key,让ETCD可以检测服务的健康状态。然后服务消费者
向ETCD查特定的服务名key,从而找到对应的服务地址。
2. 消息订阅/发布
分布式系统中的各种组件都是通过消息来通信。为了保证消息传输,减少进程的等待,可以采用订阅/发布机制。ETCD作为消息订阅发布中心,生产者进程以topic为key
注册到etcd,消费者通过ETCD的watch机制检测感兴趣的topic是否有更新,一旦生产者将消息更新到topic的value,ETCD就会通知对应的消费者对应topic的value变化,从而
让消费者接收到消息。
3. 负载均衡
分布式系统中,为了保证服务的高可用以及数据的一致性,通常都会把数据和服务部署多份,以此达到对等服务,即使其中的某一个服务失效了,也不影响使用。由此
带来的坏处是数据写入性能下降,而好处则是数据访问时可以通过负载均衡保证服务的高可用,并减缓单个节点的压力。一种实现方式是通过提供同样服务的多个节点以服
务名+节点UUID作为key 注册到ETCD中,并通过心跳更新自身的负载到value。服务消费者通过带prefix的查询可以获得所有节点注册的key,以及节点负载情况,从而选择
负载较小的节点发起请求。
4. 分布式锁
分布式系统中,为了保证多节点访问的数据一致性,需要用到分布式锁。由于ETCD本身基于raft协议可以保证数据的强一致性,并且还提供了一套分布式锁的原子操作
CAS(CompareAndSwap)的API,通过设置prevExist值,可以保证在多个节点同时PUT时只有一个返回成功,从而认为获得锁。
5. 集群健康检查
集群各个节点将节点UUID注册到ETCD,并创建lease租约,将key与对应的lease绑定。节点定时刷新租约lease,如果节点down掉则租约过期,ETCD将自动租约绑定的
key删除,观察者通过watch机制可以获取到所有key的变化情况,从而获取集群健康状态。