作者:Gyuho Lee(AWS,@gyuho),Jingyi Hu(谷歌,@jingyih)
etcd 3.4侧重于稳定性、性能和操作的便利性,具有预投票(pre-vote)和非投票(non-voting)成员等特性,并改进了存储后端和客户端平衡器。
有关更改的完整列表,请参阅更改日志。
https://github.com/etcd-io/etcd/blob/master/CHANGELOG-3.4.md
更好的存储后端
etcd v3.4包含了大量针对大规模Kubernetes工作负载的性能改进。
特别是,etcd遇到了大量并发读事务的性能问题,即使没有写(例如,“只读范围请求……花了太长时间来执行”)。以前,即使没有挂起写入,挂起写入的存储后端提交操作也会阻止传入的读取事务。现在,提交不会阻止读取,这会改善长时间运行的读取事务性能。
我们进一步使后端读取事务完全并发。以前,正在进行的长时间运行的读事务阻塞写和即将到来的读。通过此更改,在长时间运行的读取情况下,写吞吐量增加了70%,P99写延迟减少了90%。我们还在GCE上运行Kubernetes 5000节点可伸缩性测试,并观察到类似的改进。例如,在测试的最开始,有很多长时间运行的“LIST pods”,“POST clusterrolebindings”的P99延迟降低了97.4%。这个非阻塞读取事务现在用于压缩(compaction),结合压缩批大小的减少,可以减少压缩过程中的P99服务器请求延迟。
在租赁存储方面,已经做了更多的改进。通过更有效地存储租赁对象,提高了租赁过期/撤销性能,并通过当前的租赁授予/撤销操作使租赁查找操作不阻塞。etcd v3.4引入了租借检查点作为实验特性,通过协商一致的方式来持久化剩余的生存时间值。这确保了短期租约对象不会在领导者选举后自动更新。当生存时间值相对较大时(例如,在Kubernetes用例中,1小时TTL从未过期),这也可以防止租约对象堆积。
改进的Raft投票过程
etcd服务器实现了用于数据复制的Raft一致性算法。Raft是基于领导的协议。数据从领导者复制到追随者;跟随者将建议转发给领导者,领导者决定要做什么或不做什么。一旦某个条目被集群的法定人数数量所同意,领导者将保存并复制该条目。集群成员选举领导者,所有其他成员成为追随者。当选的领导者定期向追随者发送心跳,以保持其领导地位,并期待每个追随者的反应,以跟踪其进展。
最简单的形式是,当Raft领导者接收到具有更高任期(term)的消息而没有任何进一步的集群范围的健康检查时,它会成为跟随者。此行为可能会影响整个群集的可用性。
例如,一个脆弱(或重新加入)的成员突然加入或退出,并开始活动。该成员使用较高的任期,忽略所有具有较低任期的传入消息,并发送具有较高任期的消息。当领导者收到这个更高任期的消息时,它会成为追随者。
当存在网络分区时,这将变得更具破坏性。无论分区节点何时恢复连接,都可能触发领导者重选。为了解决这个问题,etcd Raft引入了新的节点状态预选者,具有预投票特性。预选者首先询问其他服务器它是否足够新以获得选票。只有当它能获得多数选票时,它才会提高任期并开始选举。这一额外阶段总体上提高了领导者选举的稳健性。并帮助领导者保持稳定,只要它保持与同级的法定人数的连接。
同样,当重新启动的节点没有及时接收到领导者心跳时(例如,由于网络速度较慢),etcd的可用性也会受到影响,从而触发领导者选举。以前,etcd快进选举滴答服务器启动,只有一个滴答留给领导人选举。例如,当选举超时为1秒时,追随者在开始选举前只等待领导者100毫秒。这加快了服务器的初始启动速度,因为不需要等待选举超时(例如,选举在100ms而不是1秒内触发)。对于具有较大选举超时的跨数据中心部署,提前选择滴答也很有用。然而,在许多情况下,可用性比最初选举领导者的速度更为关键。为了确保重新连接节点的可用性更好,etcd现在在剩余一个以上滴答的情况下调整选举滴答,这样领导者就有更多的时间来防止破坏性的重启。
Raft无投票权成员,学习者
成员关系重新配置的挑战在于,它常常导致法定人数大小的更改,这很容易导致集群不可用。即使它不更改法定人数,具有成员更改的集群也更有可能遇到其他潜在问题。为了提高重构的可靠性和置信度,etcd 3.4版本引入了一个新的角色,学习者(Learner)。
一个新的etcd成员在没有初始数据的情况下加入集群,请求领导者提供所有的历史更新,直到它赶上领导者的日志为止。这意味着领导者的网络更有可能超载,阻塞或降低领导者对追随者的心跳。在这种情况下,追随者可能会经历选举超时,并开始新的领导者选举。也就是说,一个有新成员的群体更容易受到领导者选举的影响。领导者的选择和随后对新成员的更新传播都容易导致集群不可用(参见Figure 1)。
最坏的情况是成员添加配置错误。etcd中的成员重新配置是一个两步的过程:etcdctl member add添加peer URL,并启动一个新的etcd来加入集群。也就是说,无论peer URL值是否无效,都会应用member add命令。如果第一步是应用无效URL并更改法定人数大小,则集群可能已经丢失法定人数,直到新节点连接为止。由于URL无效的节点永远不会联机,并且没有领导者,所以不可能还原成员更改(请参见Figure 2)。
当存在分区节点时,这将变得更加复杂(有关更多信息,请参阅设计文档)。
为了解决这种故障模式,etcd引入了一个新的节点状态“学习者”,它以无投票权成员的身份加入集群,直到赶上领导者的日志。这意味着学习者仍然接收来自领导者的所有更新,而它不计入法定人数,法定人数被领导者用来评估同伴的活跃度。学习者只作为备用节点,直到被提升。这种对法定人数的放松要求,在成员重新配置和操作安全期间提供了更好的可用性(参见Figure 3)。
我们将进一步提高学习者的稳健性,探索自动提升机制,使操作更简单、更可靠。请阅读我们用户指南的学习者设计文档和运行时配置文档。
https://github.com/etcd-io/etcd/blob/master/Documentation/learning/design-learner.md
https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/runtime-configuration.md#add-a-new-member-as-learner
新客户均衡器
etcd被设计用来容忍各种系统和网络故障。按照设计,即使一个节点宕机,通过提供多个服务器的一个逻辑集群视图,集群“看起来”仍能正常工作。但是,这并不能保证客户的活性。因此,etcd客户端实现了一套不同的复杂协议,以确保其正确性和在错误条件下的高可用性。
从历史上看,etcd客户端平衡器严重依赖于旧的gRPC接口:每次gRPC依赖项升级都会破坏客户端行为。大多数开发和调试工作都致力于修复这些客户机行为更改。因此,由于对服务器连接的错误假设,它的实现变得过于复杂。etcd v3.4的主要目标是简化客户机中的平衡器故障转移逻辑;当客户机断开与当前端点的连接时,只需使用一个端点,而不是维护不健康的端点列表(这些端点可能已经过时)。它不假定端点状态。因此,不需要更复杂的状态跟踪。
此外,新客户机现在创建自己的凭据包,以针对安全端点修复平衡器故障转移。这就解决了长达一年的bug,当第一个etcd服务器不可用时,kube-apiserver将失去与etcd集群的连接。
有关更多信息,请参阅客户端平衡器设计文档。
https://github.com/etcd-io/etcd/blob/master/Documentation/learning/design-client.md