Kubernetes之(三)核心组件ETCD介绍
Kubernetes之(三)核心组件ETCD介绍
Etcd是CoreOS基于Raft开发的分布式key-value存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。
ETCD的主要功能
- 基本的key-value存储
- 监听机制
- key的过期及续约机制,用于监控和服务发现
- 原子CAS和CAD,用于分布式锁和leader选举
ETCD基于RAFT的一致性
选举方法
- 初始化系统时,阶段处于follower状态并设定一个election timeout,如果在这时间周期内没有收到来自leader的heartbeat,节点将发起选举:将自己切换为candidate之后,向集群中其他follower节点发送请求,询问其是否选举自己成为leader。
- 当收到来及集群中过半节点数的接受投票后,节点即成为leader,开始接受保存client的数据并向其他follower节点同步日志,如果没有达成一致,则candidate随机选择一个等待时间(150-300ms)再次发起投票,得到集群中半数以上follower接受的candidate将成为lwader。
- leader节点依靠定时向follower发送heartbeat来保持其地位。
- 任何时候如果其他follower在election timeout期间都没有收到来自leader的headerbeat,同样会将自己状态切换为candidate并发起选举。没成功选举一次,新lwader的任期(Term)都会比之前的leader任期大1。
日志复制
当接Leader收到客户端的日志(事务请求) 后先把该日志追加到本地的Log中,然后通过heartbeat把该Entry同步给其他Follower,Follower接收到日志后记录日志然后向Leader发送ACK,当Leader收到大多数(n/2+1) Follower的ACK信息后将该日志设置为已提交并追加到本地磁盘中,通知客户端并在下个heartbeat中Leader将通知所有的Follower将该日志存储在自己的本地磁盘中。
安全性
安全性是用于保证每个节点都执行相同序列的安全机制,如当某个Follower在当前Leader commit Log时变得不可用了,稍后可能该Follower又会倍选举为Leader,这时新Leader可能会用新的Log覆盖先前已committed的Log,这就是导致节点执行不同序列;Safety就是用于保证选举出来的Leader一定包含先前 commited Log的机制;
- 选举安全性(Election Safety) :每个任期(Term) 只能选举出一个Leader
- Leader完整性(Leader Completeness) :指Leader日志的完整性,当Log在任期Term1被Commit后,那么以后任期Term2、Term3…等的Leader必须包含该Log;Raft在选举阶段就使用Term的判断用于保证完整性:当请求投票的该Candidate的Term较大或Term相同Index更大则投票,否则拒绝该请求。
失效处理
-
- Leader失效:其他没有收到heartbeat的节点会发起新的选举,而当Leader恢复后由于步进数小会自动成为follower(日志也会被新leader的日志覆盖)
- 2) follower节点不可用:follower 节点不可用的情况相对容易解决。因为集群中的日志内容始终是从 leader 节点同步的,只要这一节点再次加入集群时重新从 leader节点处复制日志即可。
- 3) 多个candidate:冲突后candidate将随机选择一个等待间隔(150ms ~ 300ms)再次发起投票,得到集群中半数以上follower接受的candidate将成为leader
ETCD,Zoopkeeper,Consul比较
- Etcd 和 Zookeeper 提供的能力非常相似,都是通用的一致性元信息存储,都提供watch机制用于变更通知和分发,也都被分布式系统用来作为共享信息存储,在软件生态中所处的位置也几乎是一样的,可以互相替代的。二者除了实现细节,语言,一致性协议上的区别,最大的区别在周边生态圈。Zookeeper 是apache下的,用java写的,提供rpc接口,最早从hadoop项目中孵化出来,在分布式系统中得到广泛使用(hadoop, solr, kafka, mesos 等) 。Etcd 是coreos公司旗下的开源产品,比较新,以其简单好用的rest接口以及活跃的社区俘获了一批用户,在新的一些集群中得到使用(比如kubernetes) 。虽然v3为了性能也改成二进制rpc接口了,但其易用性上比 Zookeeper 还是好一些。
- 而Consul 的目标则更为具体一些,Etcd 和 Zookeeper 提供的是分布式一致性存储能力,具体的业务场景需要用户自己实现,比如服务发现,比如配置变更。而Consul 则以服务发现和配置变更为主要目标,同时附带了kv存储。
ETCD实用注意事项
1、ETCD cluster初始化的问题
如果集群第一次初始化启动的时候,有一台节点未启动,通过v3的接口访问的时候,会报告Error: Etcdserver: not capable 错误。这是为兼容性考虑,集群启动时默认的API版本是2.3,只有当集群中的所有节点都加入了,确认所有节点都支持v3接口时,才提升集群版本到v3。这个只有第一次初始化集群的时候会遇到,如果集群已经初始化完毕,再挂掉节点,或者集群关闭重启(关闭重启的时候会从持久化数据中加载集群API版本) ,都不会有影响。
2、ETCD读请求的机制
v2 quorum=true 的时候,读取是通过raft进行的,通过cli请求,该参数默认为true。
v3 –consistency=“l” 的时候(默认) 通过raft读取,否则读取本地数据。sdk 代码里则是通过是否打开:WithSerializable option 来控制。一致性读取的情况下,每次读取也需要走一次raft协议,能保证一致性,但性能有损失,如果出现网络分区,集群的少数节点是不能提供一致性读取的。但如果不设置该参数,则是直接从本地的store里读取,这样就损失了一致性。使用的时候需要注意根据应用场景设置这个参数,在一致性和可用性之间进行取舍。
3、ETCD的compact机制
Etcd 默认不会自动 compact,需要设置启动参数,或者通过命令进行compact,如果变更频繁建议设置,否则会导致空间和内存的浪费以及错误。Etcd v3 的默认的backend quota 2GB,如果不 compact,boltdb 文件大小超过这个限制后,就会报错:”Error: etcdserver: mvcc: database space exceeded”,导致数据无法写入。
ETCD的问题
当前 Etcd 的raft实现保证了多个节点数据之间的同步,但明显的一个问题就是扩充节点不能解决容量问题。要想解决容量问题,只能进行分片,但分片后如何使用raft同步数据?只能实现一个 multiple group raft,每个分片的多个副本组成一个虚拟的raft group,通过raft实现数据同步。当前实现了multiple group raft的有 TiKV 和 Cockroachdb,但尚未一个独立通用的。理论上来说,如果有了这套 multiple group raft,后面挂个持久化的kv就是一个分布式kv存储,挂个内存kv就是分布式缓存,挂个lucene就是分布式搜索引擎。当然这只是理论上,要真实现复杂度还是不小。
参考文档
Kubernetes指南-倪朋飞
Kubernetes-handbook-jimmysong-20181218